/* ==========================================================
     Design for Mambo javascript common ajax engine v1.0

     Author  : Nguyen Manh Cuong
     Email   : cuongnm@designformambo.com
     Homepage: http://designformambo.com
========================================================== */

if (typeof d4m_ajax_engine_included == 'undefined') {
	function d4m_ajax_engine() { // Define d4m_ajax_engine class
		// Define Settings
		var settings = new Array();
		settings['menthod'] = 'GET';
		settings['response_type'] = 'XML';
		settings['response_node'] = 'ajaxResponse';
		settings['response_update'] = 'innerHTML';
		settings['loading_status'] = false;
		settings['loading_text'] = 'Loading...';
		settings['persistent'] = false;
		settings['async'] = true;
		settings['call_outside'] = false;
		settings['debug'] = false;
		
		this.setMenthod = function(menthod) { // Set menthod to send variables to server-side script
			if (menthod.toUpperCase() == 'GET' || menthod.toUpperCase() == 'POST')
				settings['menthod'] = menthod.toUpperCase();
		}

		this.setResponseType = function(responseType) { // Set response type for server-side script to return data
			if (responseType.toUpperCase() == 'XML' || responseType.toUpperCase() == 'TEXT')
				settings['response_type'] = responseType.toUpperCase();
		}

		this.setResponseNode = function(responseNode) { // Set the response root node for XML data
			settings['response_node'] = responseNode;
		}

		this.setResponseUpdate = function(responseUpdate) { // Update using innerHTML or by calling a function
			if (responseUpdate == 'innerHTML' || responseUpdate == 'function')
				settings['response_update'] = responseUpdate;
		}

		this.setLoadingStatus = function(show) { // Show or hide the loading text
			if (typeof show == 'boolean')
				settings['loading_status'] = show;
		}

		this.setLoadingText = function(txt) { // Set the loading text
			settings['loading_text'] = txt;
		}

		this.setPersistent = function(persistent) { // Use persistent connection or not?
			if (typeof persistent == 'boolean')
				settings['persistent'] = persistent;
		}

		this.setAsync = function(async) { // Set acsynchronous or synchronous request
			if (typeof async == 'boolean')
				settings['async'] = async;
		}

		this.setCallOutside = function(set) { // Set whether the backend script is handled by "d4m_ajax_engine" or not
			if (typeof set == 'boolean')
				settings['call_outside'] = set;
		}

		this.setDebug = function(set) { // Enable debug or not?
			if (typeof set == 'boolean')
				settings['debug'] = set;
		}

		// Function to send request
		this.sendRequest = function() {
			if (settings['loading_status'] && typeof swapLoading == 'function') swapLoading(settings['loading_text'], true);
			if (settings['debug']) alert('d4m_ajax_engine.sendRequest: Preparing to send request...');

			var this_stack_index = -1;
			if (settings['persistent'] == true && typeof __ajax_engine_stack[0] == 'object') {
				switch (__ajax_engine_stack[0].getState()) {
					case -1: // no XMLHttpObject object has already been created
						this_stack_index = 0;
						if (settings['debug']) alert('d4m_ajax_engine.sendRequest: No any persistent connection created');
						break;

					case 4: // XMLHttpObject object is ready for a new request
						this_stack_index = 0;
						if (settings['debug']) alert('d4m_ajax_engine.sendRequest: Persistent connection created and ready to use');
						break;

					default: // connection is currently in use, don't do anything
						if (settings['debug']) alert('d4m_ajax_engine.sendRequest: Persistent connection currently in use, skip this request');
				}
			} else if (settings['persistent'] == true) { // persistent connection is active, but no object has been created
				this_stack_index = 0;
				__ajax_engine_stack[this_stack_index] = new d4m_ajax_call(this_stack_index);
				if (settings['debug']) alert('d4m_ajax_engine.sendRequest: No "d4m_ajax_call" object available for re-use, created new one');
			} else { // persistent connection is not active
				this_stack_index = __stack_index;
				__ajax_engine_stack[this_stack_index] = new d4m_ajax_call(this_stack_index);
				if (settings['debug']) alert('d4m_ajax_engine.sendRequest: Created new "d4m_ajax_call" object');
			}

			if (this_stack_index > -1) {
				__ajax_engine_stack[this_stack_index].setMenthod(settings['menthod']);
				__ajax_engine_stack[this_stack_index].setResponseType(settings['response_type']);
				__ajax_engine_stack[this_stack_index].setResponseNode(settings['response_node']);
				__ajax_engine_stack[this_stack_index].setResponseUpdate(settings['response_update']);
				__ajax_engine_stack[this_stack_index].setLoadingStatus(settings['loading_status']);
				__ajax_engine_stack[this_stack_index].setLoadingText(settings['loading_text']);
				__ajax_engine_stack[this_stack_index].setPersistent(settings['persistent']);
				__ajax_engine_stack[this_stack_index].setAsync(settings['async']);
				__ajax_engine_stack[this_stack_index].setCallOutside(settings['call_outside']);
				__ajax_engine_stack[this_stack_index].setDebug(settings['debug']);
				__ajax_engine_stack[this_stack_index].sendRequest(arguments);

				__stack_index++;
				if (settings['debug']) alert('d4m_ajax_engine.sendRequest: Current stack index = '+__stack_index);
			}
		}
	}

	var __stack_index = 0; // Current __ajax_engine_stack index in use
	var __ajax_engine_stack = new Array(); // first-in-first-out stack of "d4m_ajax_call" objects

	function d4m_ajax_call() { // Define d4m_ajax_call class
		// Define Settings
		var settings = new Array();
		settings['menthod'] = 'GET';
		settings['response_type'] = 'XML';
		settings['response_node'] = 'ajaxResponse';
		settings['response_update'] = 'innerHTML';
		settings['loading_status'] = false;
		settings['loading_text'] = 'Loading...';
		settings['persistent'] = false;
		settings['async'] = true;
		settings['call_outside'] = false;
		settings['debug'] = false;
		
		var __stack_index = arguments[0]; // Current stack index in use

		// Define a common request object
		var http = false;

		// Define a variable to store the response handler
		var responseHandler = '';

		this.setMenthod = function(menthod) { // Set menthod to send variables to server-side script
			if (menthod.toUpperCase() == 'GET' || menthod.toUpperCase() == 'POST')
				settings['menthod'] = menthod.toUpperCase();
		}

		this.setResponseType = function(responseType) { // Set response type for server-side script to return data
			if (responseType.toUpperCase() == 'XML' || responseType.toUpperCase() == 'TEXT')
				settings['response_type'] = responseType.toUpperCase();
		}

		this.setResponseNode = function(responseNode) { // Set the response root node for XML data
			settings['response_node'] = responseNode;
		}

		this.setResponseUpdate = function(responseUpdate) { // Update using innerHTML or by calling a function
			if (responseUpdate == 'innerHTML' || responseUpdate == 'function')
				settings['response_update'] = responseUpdate;
		}

		this.setLoadingStatus = function(show) { // Show or hide the loading text
			if (typeof show == 'boolean')
				settings['loading_status'] = show;
		}

		this.setLoadingText = function(txt) { // Set the loading text
			settings['loading_text'] = txt;
		}

		this.setPersistent = function(persistent) { // Use persistent connection or not?
			if (typeof persistent == 'boolean')
				settings['persistent'] = persistent;
		}

		this.setAsync = function(async) { // Set acsynchronous or synchronous request
			if (typeof async == 'boolean')
				settings['async'] = async;
		}

		this.setCallOutside = function(set) { // Set whether the backend script is handled by "d4m_ajax_engine" or not
			if (typeof set == 'boolean')
				settings['call_outside'] = set;
		}

		this.setDebug = function(set) { // Enable debug or not?
			if (typeof set == 'boolean')
				settings['debug'] = set;
		}

		this.getState = function() { // get the ready state of the internal XMLHttpObject "http" object
			var return_value = -1;
			if (typeof http == 'object') {
				return_value = http.readyState;
			}
			return return_value;
		}

		// Function to create request object
		function createRequestObject() {
			var new_connection  = false;

			// open new connection only if necessary
			if (settings['persistent'] == false) {
				// no persistent connection, create a new object every time
				if (settings['debug']) alert('d4m_ajax_call.createRequestObject: Using new connection object...');
				new_connection = true;
			} else {
				// persistent connection object, only open one if no object exists
				if (settings['debug']) alert('Using shared connection object.', 1);
				if (typeof http != 'object') {
					if (settings['debug']) alert('d4m_ajax_call.createRequestObject: Getting new persistent connection object...');
					new_connection = true;
				}
			}

			if (new_connection == true) {
				try {
					http = new ActiveXObject('Msxml2.XMLHTTP');
				} catch (e) {
					try {  
						http = new ActiveXObject('Microsoft.XMLHTTP');
					} catch (oc) {
						http = null;
					}
				}
				if (!http && typeof XMLHttpRequest != 'undefined') {
					http = new XMLHttpRequest();
				}
				if (!http) {
					if (settings['debug']) alert('d4m_ajax_call.createRequestObject: Could not create XML HTTP request object.');
					http = false;
				}
			}

			if (http.readyState != 4) { // problem with asynchronous calls?
				http.abort();
			}
		}

		// Function to send request
		this.sendRequest = function(passed_arguments) {
			backendURL = passed_arguments[0];
			responseHandle = passed_arguments[1];
			// Build query string
			var query_string = '';
			if (passed_arguments.length > 2) {
				for (var i = 2; i < passed_arguments.length; i++) {
					if (settings['call_outside']) { // leave query string as is
						query_string += passed_arguments[i]+'&';
					} else { // encode query string before send
						var pair = passed_arguments[i].split('=');
						if (pair.length > 2) {
							for (var k = 2; k < pair.length; k++) {
								pair[1] += '='+pair[k];
							}
						}
						query_string += pair[0]+'='+encodeURIComponent(pair[1])+'&';
					}
				}
			}
			if (settings['call_outside']) { // leave query string as is
				query_string = query_string.substring(0, query_string.length - 1);
			} else { // add detailed options
				query_string += 'response_type='+settings['response_type'];
				query_string += settings['response_type'] == 'XML' ? '&response_node='+settings['response_node'] : '';
			}
			if (settings['debug']) alert('d4m_ajax_call.sendRequest: Query string created: '+query_string);
			if (settings['menthod'] == 'GET') { // Send query string using GET menthod
				if (backendURL.indexOf('?') > -1)
					backendURL += '&' + query_string;
				else
					backendURL += '?' + query_string;
				if (settings['debug']) alert('d4m_ajax_call.sendRequest: Updated URL: '+backendURL);
			}

			// Open connection
			createRequestObject();
			http.open(settings['menthod'], backendURL, settings['async']);

			if (settings['menthod'] == 'POST') { // Send query string using POST menthod
				try {
					http.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
				} catch (error) {
					if (settings['debug']) alert('d4m_ajax_call.sendRequest: POST cannot be completed due to incompatible browser. Use GET as your request method.');
				}
			}

			if (settings['debug']) alert('d4m_ajax_call.sendRequest: Update response handler to: '+responseHandle);
			responseHandler = responseHandle; // Store the response handler
		    http.onreadystatechange = handleResponse;
		    
			if (settings['menthod'] == 'GET') { // GET menthod in use: send nothing
			    http.send(null);
			} else { // POST menthod in use: send query string to server
				http.send(query_string);
			}

			if (settings['async'] == false)
				handleResponse(); // Synchronized connectivity in use, call the response handle function manually

			if (settings['debug']) alert('d4m_ajax_call.sendRequest: Request sending completed.');
		}

		// Function to handle response
		function handleResponse() {
			if (http.readyState == 4) { // if response available, continue
				if (settings['debug']) alert('d4m_ajax_call.handleResponse: Processing response...');

				// response as XML or TEXT?
				var response = (settings['response_type'] == 'XML') ? http.responseXML : http.responseText;
				if (settings['debug']) alert('d4m_ajax_call.handleResponse: Response data: '+http.responseText);

				if (settings['response_update'] == 'innerHTML') { // Update directly using innerHTML
					if (settings['debug']) alert('d4m_ajax_call.handleResponse: Update type is: innerHTML.');
					if (typeof responseHandler != 'object' && !document.getElementById(responseHandler)) {
						// Passed element not defined
						if (settings['debug']) alert('d4m_ajax_call.handleResponse: Cannot update innerHTML for "'+responseHandler+'".');
					} else { // it`s time to update now
						responseHandler = typeof responseHandler == 'object' ? responseHandler : document.getElementById(responseHandler);
						if (settings['response_type'] == 'XML')
							responseHandler.innerHTML = response.getElementsByTagName(settings['response_node']).item(0).firstChild.data;
						else
							responseHandler.innerHTML = response;
						if (settings['debug']) alert('d4m_ajax_call.handleResponse: Updated innerHTML of destination element to: '+responseHandler.innerHTML);
					}
				} else { // call the passed function to handle response
					if (settings['debug']) alert('d4m_ajax_call.handleResponse: Update type is: function.');
					if (typeof responseHandler != 'function') {
						// Passed function not defined
						if (settings['debug']) alert('d4m_ajax_call.handleResponse: Cannot call "'+responseHandler+'" to update HTML document cause it is not a function.');
					} else { // call the passed function to update
						responseHandler(response);
						if (settings['debug']) alert('d4m_ajax_call.handleResponse: Called registered function to handle response.');
					}
				}

				destroyStackEntry();
				if (settings['loading_status'] && typeof swapLoading == 'function') swapLoading(settings['loading_text'], false);
			}
		}

		var destroyStackEntry = function() {
			// only if everything is okay and persistent connection is not active
			if (typeof __stack_index == 'number' && __ajax_engine_stack[__stack_index] && settings['persistent'] == false) {
				__ajax_engine_stack[__stack_index] = null;
			}
		}
	}

	var d4m_ajax_engine_included = 1; // Has been loaded
}