

Ajax.xmlHttp = null;
Ajax.queue = new Array();
Ajax.prototype.xmlHttp = null;
Ajax.prototype.onqueueempty = function() {}
Ajax.prototype.charset = 'UTF-8';

Ajax.RESULT_OBJECT = 1;
Ajax.RESULT_XML = 2;
Ajax.RESULT_TEXT = 3;
Ajax.RESULT_HTML = 4;

function cloneObject(obj) { return obj; }

function Ajax(args) {
	if (!Ajax.xmlHttp) Ajax.xmlHttp = this.getXmlHttp();
	if (!args.queue) args.queue == true;
	if (!args.requesttype) args.requesttype = 'application/x-www-form-urlencoded';
	if (!args.method) args.method = 'POST';
	if (!args.resultMode) args.resultMode = Ajax.RESULT_OBJECT;
	if (args.params.getAttribute && args.params.getAttribute('method') != undefined) args.params = this.getForm(args.params);

	//this.xmlHttp = (args.queue == false ? this.getXmlHttp() : Ajax.xmlHttp);
	this.xmlHttp = Ajax.xmlHttp;
	
	 this.xmlHttp = this.getXmlHttp();

	//alert(this.xmlHttp.readyState);
	var self = this;
	
	//Check there's not a request in progress
	if (this.xmlHttp.readyState == 4 || this.xmlHttp.readyState == 0) {

		
		if (args.requesttype == 'application/x-www-form-urlencoded') var paramstr = this.objectToPostArray(args.params);
		else paramstr = params;
		
		this.callback = args.callback ? args.callback : function() {};
		
		this.xmlHttp.open(args.method, args.url + ((args.method == 'GET') ? paramstr : ''), true);
		
		this.xmlHttp.onreadystatechange = function() {
			self.readyState = self.xmlHttp.readyState;
			
			if (self.xmlHttp.readyState == 4) {
				if (args.resultMode == Ajax.RESULT_TEXT) self.callback(self.xmlHttp.responseText);
				else if (args.resultMode == Ajax.RESULT_XML) self.callback((self.xmlHttp.responseXML) ? self.xmlHttp.responseXML.documentElement : null);
				else if (args.resultMode == Ajax.RESULT_OBJECT) self.callback(self.xmlHttp.responseXML == null ? null : self.responseObject(self.xmlHttp.responseXML.documentElement));
				else if (args.resultMode == Ajax.REQUEST_HTML) slef.callback(self.xmlToHtmlElement(self.xmlHttp.responseXML.documentElement));
				
				if (Ajax.queue.length > 0) {
					var req = Ajax.queue.shift();
					new Ajax(req);				
				}
				else {
					try {
					self.oncomplete();
					self.onqueueempty();
					} catch (e) { }
				}
				
				
			}
		}
		
		if (args.method == 'POST') {
			this.xmlHttp.setRequestHeader('Content-type', args.requesttype + '; charset=' + this.charset);
			this.xmlHttp.setRequestHeader('Content-length', paramstr.length);
			this.xmlHttp.setRequestHeader('Connection', 'close');
		}
		this.xmlHttp.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
		this.xmlHttp.send((args.method == 'POST') ? paramstr : null);
	}
	else { //there is already a request in progress, add the request to the queue
		Ajax.queue[Ajax.queue.length] = args;
	}
}

Ajax.prototype.abort = function() {
	this.xmlhttp.abort();
}

Ajax.prototype.objectToPostArray = function(object, prefix, postfix) {
	if (!prefix) prefix = '';
	if (!postfix) postfix = '';
	
	var flat = '';
	for (var i in object) {
		if (typeof(object[i]) == 'object' || typeof(object[i]) == 'array') {
			flat += '&' + this.objectToPostArray(object[i], prefix + i+'[',']');
		}
		else flat += '&' + prefix + i + postfix + '=' + object[i];
	}
	
	return flat;
}


Ajax.prototype.getXmlHttp = function() {
	try {    // Firefox, Opera 8.0+, Safari
		var xmlhttp = new XMLHttpRequest();
	}
	catch (e) {    // Internet Explorer
		try {
			var xmlhttp = new ActiveXObject('Msxml2.XMLHTTP');
		}
		catch (e) {
			try {
				var xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');
			}
			catch (e) {
				return false;
			}
		}
	}
	Ajax.xmlHttp = xmlhttp;
	return xmlhttp;
}



Ajax.prototype.getForm = function(form) {
	var params = {};
	
	for (var i = 0; i < form.elements.length; i++) {
		if (!form.elements[i].name) continue;
		if (form.elements[i].type && (form.elements[i].type == 'radio')) {
			if (form.elements[i].checked) {
				params[form.elements[i].name] = form.elements[i].value;
			}
		}
		else if (form.elements[i].type == 'checkbox') {
			var name = form.elements[i].name.split('[]')[0];
			if (form[form.elements[i].name].length) {				
				if (!params[name]) params[name] = new Array();
				if (form.elements[i].checked) params[name].push(form.elements[i].value);							
			}
			else {
				if (form.elements[i].checked) params[form.elements[i].name] = form.elements[i].value;
			}			
		}
		else if (form.elements[i].tagName.toLowerCase() == 'select' && form.elements[i].multiple == true) {
			var options = form.elements[i].getElementsByTagName('option');
			
			params[form.elements[i].name] = new Array();
			for (var j = 0; j < options.length; j++) {
				if (options[j].selected) params[form.elements[i].name].push(options[j].value);
			}

		}		
		
		else params[form.elements[i].name] = form.elements[i].value;
	}
	
	return params;
}

Ajax.prototype.responseObject = function(xmlnode) {
	var newObj = new Object();

	if (xmlnode) {

		//loop through all the child nodes for the current node
		for (var node=0; node <= xmlnode.childNodes.length-1; node++) {
			if (xmlnode.childNodes[node].nodeType != 3) {
				//ignore (remove) whitespace at the start of lines.
				if (xmlnode.childNodes[node].hasChildNodes()) {
					if (xmlnode.childNodes[node].firstChild.nodeType == 3) {
						if (xmlnode.childNodes[node].firstChild.nodeValue.indexOf("\n") == 0 || xmlnode.childNodes[node].firstChild.nodeValue.indexOf("\t") == 0) {
							xmlnode.childNodes[node].removeChild(xmlnode.childNodes[node].firstChild);
						}
					}
				}
				//find out how many sibling nodes there are with the same name as the current one
				var ncount = 0;
				for (var i=0; i < xmlnode.childNodes.length; i++) {
					if (xmlnode.childNodes[node].nodeName == xmlnode.childNodes[i].nodeName) {
						ncount++;
					}
				}
				//ncount should be > 0. It should at least find itself.
				//get the value for the current node
				var nodeVal = (xmlnode.childNodes[node].hasChildNodes()) ? ((xmlnode.childNodes[node].firstChild.nodeType == 3) ? xmlnode.childNodes[node].firstChild.nodeValue : this.responseObject(xmlnode.childNodes[node])) : '';


				//if there is  more than one tag with this name, create an array
				if (ncount > 1) {
					if (!newObj[xmlnode.childNodes[node].nodeName])	{
						newObj[xmlnode.childNodes[node].nodeName] = new Array();
						newObj[xmlnode.childNodes[node].nodeName].isArray = true;
					}
					newObj[xmlnode.childNodes[node].nodeName].type = 'array';
					newObj[xmlnode.childNodes[node].nodeName][newObj[xmlnode.childNodes[node].nodeName].length] = nodeVal;
				}
				//if there is only one tag of the kind, dont use an array.
				else {
					newObj[xmlnode.childNodes[node].nodeName] =  (typeof(nodeVal) == 'object') ? cloneObject(nodeVal) : nodeVal;
					//Even though there is no array, make this accessible as node[0] in case the script is expecting 1 or more items.
					newObj[xmlnode.childNodes[node].nodeName][0] = nodeVal;
					//Give the user a way of checking whether an array has been returned.
					newObj[xmlnode.childNodes[node].nodeName].isArray = false;
					//report length so it is still loopable
					newObj[xmlnode.childNodes[node].nodeName].length = 1;
					//This will cause problems if push()/splice()/etc/other array methods are used on the result though.
				}
			}
		}
		return newObj;
	}
	else return null;
}


