
/*
 *	@author			Martijn Polak <martijn.polak@amgate.com>
 *	@name			xmlhttp request object
 *	@since			18-06-2005
 *	@description	Provides a single object to make http requests using javascript. This works asynchronously;
 *					when the request is completed it calls the xmlHttp_onReadyStateCompleted(text, id) function (if it
 *					exists) with the return data, or the location-specific callback function if one has been supplied and exists.
 *					Features a request queue so you can fire multiple requests,	each one will be processed when the previous one completes.
 *					Usage:
 *					xmlHttp.get(url, [id], [callback]);		to make an http GET request
 *					xmlHttp.post(url, [id], [callback]);	to make an http POST request
 *					xmlHttp.head(url, [id], [callback]);	if you just want the http headers
 *					You may add an additional (unique) id value to a request. This value will be returned in the
 *					callback function so you can identify the request.
 */

// Possible XMLHttpRequest.readyState values
var XMLHTTP_READYSTATE_UNINITIALIZED = 0;		// open() has not been called yet.
var XMLHTTP_READYSTATE_LOADING = 1;				// send() has not been called yet.
var XMLHTTP_READYSTATE_LOADED = 2; 				// send() has been called, headers and status are available.
var XMLHTTP_READYSTATE_INTERACTIVE = 3;			// Downloading, responseText holds the partial data.
var XMLHTTP_READYSTATE_COMPLETED = 4;			// Finished with all operations.

// Request types
var XMLHTTP_REQUESTTYPE_GET = 'GET';
var XMLHTTP_REQUESTTYPE_POST = 'POST';
var XMLHTTP_REQUESTTYPE_HEAD = 'HEAD';

// MS xmlHTTP object types
var XMLHTTP_MSOBJECTS = Array("MSXML3", "MSXML2", "MSXML", "Microsoft");
var XMLHTTP_MSOBJECT = '';

// Main object
var xmlHttp = {

	requestObject : null,
	requestQueue : Array(),

	// Initialize
	_init : function() {

		if (!xmlHttp.requestObject) {

			try {

				// Mozilla
				if (window.XMLHttpRequest) {

					xmlHttp.requestObject = new XMLHttpRequest();

					// Some versions of Moz do not support the readyState property
					// and the onreadystate event so we patch it!
					if (xmlHttp.requestObject.readyState == null) {

						xmlHttp.requestObject.readyState = 1;
						xmlHttp.requestObject.addEventListener("load", function () {

							xmlHttp.requestObject.readyState = 4;
							if (typeof xmlHttp.requestObject.onreadystatechange == "function") xmlHttp.requestObject.onreadystatechange();

						}, false);

					}

				}

				// IE
				if (window.ActiveXObject) {

					if (!XMLHTTP_MSOBJECT) {

						for (var i = 0; i < XMLHTTP_MSOBJECTS.length; i++) {

							try {

								xmlHttp.requestObject = new ActiveXObject(XMLHTTP_MSOBJECTS[i] + ".XmlHttp");
								if (xmlHttp.requestObject) {
									XMLHTTP_MSOBJECT = XMLHTTP_MSOBJECTS[i];
									break;
								}

							}
							catch (ex) {}

						}

					} else {

						xmlHttp.requestObject = new ActiveXObject(XMLHTTP_MSOBJECT + ".XmlHttp");

					}

				}

			} catch (ex) {}

			// Callback function
			if (xmlHttp.requestObject) {

				xmlHttp.requestObject.onreadystatechange = function() {

					// Got all responseText
					if (xmlHttp.requestObject.readyState == XMLHTTP_READYSTATE_COMPLETED) {

						//xmlHttp.ready = true;
						var location = xmlHttp.requestQueue[0];
						var callback = eval(location.callback ? location.callback : 'xmlHttp_onReadyStateCompleted');

						// Callback function is defined
						if (typeof(callback) != 'undefined') {

							// Return only headers on HEAD request type
							if (location.requestType == XMLHTTP_REQUESTTYPE_HEAD)
								callback(xmlHttp.requestObject.getAllResponseHeaders(), location.id);
							else
								callback(xmlHttp.requestObject.responseText, location.id);

						}

						location.ready = true;
						xmlHttp._processQueue();

					}

				}

			}

		}

	},

	// Reinitialize requestObject
	_reset : function() {

		xmlHttp.requestObject = null;
		xmlHttp._init();

	},

	_processQueue : function() {

		// Queue isn't empty
		if (xmlHttp.requestQueue.length > 0) {

			var location = xmlHttp.requestQueue[0];

			if (location.ready) {

				// Call has completed; remove from queue
				xmlHttp.requestQueue.shift();
				xmlHttp._processQueue();

			} else {

				// No call in progress; execute new call
				if (!xmlHttp.requestObject || xmlHttp.requestObject.readyState == XMLHTTP_READYSTATE_UNINITIALIZED || xmlHttp.requestObject.readyState == XMLHTTP_READYSTATE_COMPLETED) {

					// Initialize when needed
					// For some reason successive calls using the same xmlhttprequest object yield unexpected results
					// so we'll just have to reinitialize for every call
					xmlHttp._reset();

					xmlHttp.requestObject.open(location.requestType, location.url + (location.url.indexOf('?') < 0 ? '?' : '&') + 'nocache=' + new Date().getTime(), true);

					if (location.requestType == XMLHTTP_REQUESTTYPE_POST) {
						xmlHttp.requestObject.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
					}

					xmlHttp.requestObject.send(location.postvars);

				}

			}

		}

	},

	_send : function(url, id, callback, type) {

		// Create location object for this request and push it onto the queue
		var location = new Object();

		if (type == XMLHTTP_REQUESTTYPE_POST && url.indexOf('?') > 0) {

			// split URL & postvars
			location.url = url.substr(0, url.indexOf('?'));
			location.postvars = url.substr(url.indexOf('?')+1);

		} else {

			location.url = url;
			location.postvars = null;

		}

		location.requestType = type;
		location.id = id;
		location.callback = callback;
		location.ready = false;

		xmlHttp.requestQueue.push(location);
		xmlHttp._processQueue();

	},

	get : function(url, id, callback) {

		xmlHttp._send(url, id, callback, XMLHTTP_REQUESTTYPE_GET);

	},

	post : function(url, id, callback) {

		xmlHttp._send(url, id, callback, XMLHTTP_REQUESTTYPE_POST);

	},

	head : function(url, id, callback) {

		xmlHttp._send(url, id, callback, XMLHTTP_REQUESTTYPE_HEAD);

	}

}

