/* ========================================================================= */
/* AjaxRequest object - r006 (13.05.2008)
/* Tested on Firefox 1.5 - 2, Explorer 6 - 7, Opera 8
/* ========================================================================= */

// Constants
var AJAX_ARR = 1;
var AJAX_XML = 2;
var AJAX_HTML = 3;
var AJAX_JSCRIPT = 4;
var AJAX_TEXT = 5;

function AjaxRequest(url, func, retType, mthod)
{
	// Properties
	this.httpRequest = null;
	this.httpMethod = (mthod ? mthod : 'GET'); // 'GET', 'POST'
	this.url = (url ? url : '');
	this.callbackFunc = (func ? func : null);
	this.returnType = (retType ? retType : AJAX_ARR);
	this.calls = 0;
	this.received = false;

	// Reference to this
	thisObj = this;

	// Methods
	this.requestSync = function (url, retType, mthod)
	{
		try {
			if (window.XMLHttpRequest)
				var xmlDoc = new XMLHttpRequest();
			else if (window.ActiveXObject)
				var xmlDoc = new ActiveXObject("Microsoft.XMLHTTP");
		}
		catch (e) {
			alert(e.message);
			return false;
		}

		try {
			if (!mthod)
				var mthod = 'GET';
			if (!retType)
				var retType = AJAX_ARR;

			xmlDoc.open(mthod, url, false);
			xmlDoc.send(null);

			// The result
			switch (retType)
			{
				case AJAX_ARR:
					return passXMLDom(xmlDoc.responseXML);
				case AJAX_XML:
					return xmlDoc.responseXML;
				case AJAX_HTML:
				case AJAX_JSCRIPT:
				case AJAX_TEXT:
					return xmlDoc.responseText;
			}
			return xmlDoc;
		}
		catch (e) {
			alert(e.message);
			return false;
		}
		return null;
	}

	this.request = function (url, func, retType, mthod)
	{
		try {
			if (window.XMLHttpRequest)
				this.httpRequest = new XMLHttpRequest();
			else if (window.ActiveXObject)
				this.httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
		}
		catch (e) {
			alert(e.message);
			return false;
		}

		if (url)
			this.url = url;
		if (func)
			this.callbackFunc = func;
		if (retType)
			this.returnType = retType;
		if (mthod)
			this.httpMethod = mthod;

		this.calls = 0;
		this.received = false;
		this.httpRequest.onreadystatechange = this.receive;
		this.httpRequest.open(this.httpMethod, this.url);
		this.httpRequest.send(null);
	}

	this.receive = function ()
	{
		this.calls ++;
		try {
			if (this.httpRequest.readyState != 4 || this.httpRequest.status != 200)
				return;
		}
		catch(e) {
			this.received = false;
			setTimeout('thisObj.receive()', 250);
			return;
		}

		if (this.received)
			return;

		this.received = true;

		// Call the callback function
		switch (this.returnType)
		{
			case AJAX_ARR:
				this.xmlArray = passXMLDom(this.httpRequest.responseXML);
				eval(this.callbackFunc+'(thisObj.xmlArray)');
				break;
			case AJAX_XML:
				eval(this.callbackFunc+'(thisObj.httpRequest.responseXML)');
				break;
			case AJAX_HTML:
			case AJAX_JSCRIPT:
			case AJAX_TEXT:
				eval(this.callbackFunc+'(thisObj.httpRequest.responseText)');
		}
	}

	// Auto request
	if (this.url && this.callbackFunc && this.returnType && this.httpMethod)
		this.request();
}


// --------------------------------
// XML DOM -> Associative array
// modeAttr = true -> the value will be 'nodename' = ('value' = ... , 'attrs' = ...)
//           false -> 'nodename' = 'value'
//
function passXMLDom(theNode, modeAttr)
{
	var xbuf = new Object();
	var multi = -1;

	for (var i=0; theNode && theNode.childNodes && i<theNode.childNodes.length; i++)
	{
		var multi = -1;
		var chnode = theNode.childNodes[i];
		if (chnode.nodeType == 1 && chnode.childNodes.length>0)    // html element
		{
			// Find element with same key
			if (xbuf[chnode.tagName])
			{
				multi = 0;
				if (typeof(xbuf[chnode.tagName]) == 'object')
					for (key in xbuf[chnode.tagName])
						if (!isNaN(key))
							multi ++;
			}

			var tmpxbuf = new Object();
			var key = chnode.tagName;

			// Get the value
			if (chnode.childNodes.length == 1 && chnode.childNodes[0].nodeType == 3)   // Text element
				tmpxbuf = chnode.childNodes[0].nodeValue;
			else
				tmpxbuf = passXMLDom(chnode, modeAttr);

			// Form attributes
			if (modeAttr)
			{
				var tmp = tmpxbuf;
				tmpxbuf = new Object();
				tmpxbuf['value'] = tmp;
				tmpxbuf['attrs'] = new Object();

				for (var j=0; j<chnode.attributes.length; j++)
					if (chnode.attributes[j].nodeName && chnode.attributes[j].value)
						tmpxbuf['attrs'][chnode.attributes[j].nodeName] = chnode.attributes[j].value;
			}

			// Add to the big array
			if (multi > -1)
			{
				if (multi == 0) // First dublicate
				{
					var tmp = xbuf[key];
					xbuf[key] = new Object();
					xbuf[key][0] = tmp;
					multi = 1;
				}
				if (!xbuf[key])
					xbuf[key] = new Object();
				xbuf[key][multi] = tmpxbuf;
			}
			else
				xbuf[key] = tmpxbuf;
		}
	}

	return xbuf;
}


// --------------------------------
// Returns the textual representation of the array.
// This function was inspired by the print_r function of PHP.
function dump(arr, level)
{
	var dumped_text = "";
	if (!level)
		level = 0;

	//The padding given at the beginning of the line.
	var level_padding = "";
	for (var j=0; j<level+1; j++)
		level_padding += "    ";

	if (typeof(arr) == 'object')
	{	//Array/Hashes/Objects
		for (var item in arr)
		{
			var value = arr[item];
			if (typeof(value) == 'object')
			{	//If it is an array,
				dumped_text += level_padding + "'" + item + "' ...\n";
				dumped_text += dump(value,level+1);
			}
			else
				dumped_text += level_padding + "'" + item + "' => \"" + value + "\"\n";
		}
	}
	else //Stings/Chars/Numbers etc.
		dumped_text = "===>"+arr+"<===("+typeof(arr)+")";
	return dumped_text;
}
