function GetAjaxHandler()
{ 
	//Use default (XMLHttpRequest) handler if exists
	if (typeof XMLHttpRequest != "undefined") 
	{ 
		return new XMLHttpRequest();
	}
	
	//Else use ActiveX object - Listed from newest to oldest
	var ActiveX_Handlers = [
			"Msxml2.XMLHTTP.7.0", 
			"Msxml2.XMLHTTP.6.0", 
			"Msxml2.XMLHTTP.5.0", 
			"Msxml2.XMLHTTP.4.0", 
			"MSXML2.XMLHTTP.3.0", 
			"MSXML2.XMLHTTP", 
			"Microsoft.XMLHTTP"
		];
	
	for(var i=0; i<=ActiveX_Handlers.length; i++)
	{
		try 
		{
			ActiveX = new ActiveXObject(ActiveX_Handlers[i]);
			if(ActiveX)
			{
				return (ActiveX);
			}
		} 
		catch(e) { }; 
	} 
	
	//Could not find proper Ajax (XML/HTTP) handler
	return false;
}



function SetTimer(Handler) 
{
	var LocalHandler = Handler;
	function timerSet() {
		if (LocalHandler.Abort) {LocalHandler.abortRequest(LocalHandler);}
	};
	
	LocalHandler.timeoutID = window.setTimeout(timerSet, LocalHandler.Timeout);
}










function XMLHTTPEngine(Name, URL, Method, Data)
{
	this.Initialize (Name, URL, Method, Data)
};




XMLHTTPEngine.prototype = {
	Name: null,
	URL: null,
	Data: null,
	Method: null,
	
	Busy: false,
	Cancelled: false,
	
	Timeout: -1,
	TimeoutID: null,
	
	XMLHTTPHandler: null,
	
	ReturnHandler: null,


//Functions

	Initialize: function(Name, URL, Method, Data) 
	{
		this.Name = Name;
		this.URL = URL;
		this.Method="GET"; if (Method=="POST") {this.Method="POST"};
		this.Data = Data;

		this.XMLHTTPHandler = GetAjaxHandler();
	},


	setTimeout: function(time) {
		this.Timeout = time;
	},



	Execute: function (Handler) 
	{
		if (this.Busy) {throw "Already contacting server";};
		
		var LocalCopy = this;

		if (Handler==null) {Handler=this;}
		this.ReturnHandler = Handler;
		
		this.Busy = true;
		this.Cancelled = false;

		if (this.Method == "GET") 
		{
			this.XMLHTTPHandler.open('GET',this.URL,true);
		} 
		else
		{
			this.XMLHTTPHandler.open("POST", this.URL, true);
			this.XMLHTTPHandler.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
		}

		this.XMLHTTPHandler.onreadystatechange = function() 
		{
			LocalCopy.stateChange_Handler(LocalCopy);
		}

		this.XMLHTTPHandler.send(this.Data);
		
		if (this.Timeout > 0) 
		{
			SetTimer(this);
		}
	},



	stateChange_Handler: function(Handler) {
		switch (Handler.XMLHTTPHandler.readyState) 
		{

			case 1:
				try {
					if (!Handler.Cancelled) {
						Handler.ReturnHandler.onInit();
					}
				}
				catch (e)
				{}
			break;


			case 2:
				try {
					if (Handler.XMLHTTPHandler.status != 200)
					{
						if (!Handler.Cancelled) 
						{
							window.status="Error - Call failed";
							Handler.ReturnHandler.onError(
								Handler.XMLHTTPHandler.status,
								Handler.XMLHTTPHandler.statusText,
								Handler
							);
						}

						Handler.XMLHTTPHandler.abort();
						Handler.Busy = false;
					}
				}
				catch (e) {}
			break;


			case 3:
				var contentLength;
				try {
					try {
						contentLength = Handler.XMLHTTPHandler.getResponseHeader("Content-Length");
					} 
					catch (e) 
					{
						contentLength = NaN;
					}

					if (!Handler.Cancelled) {
						window.status="Checking...";
						Handler.ReturnHandler.onProgress(
							Handler.XMLHTTPHandler.responseText,
							contentLength
					);
					}
				}
				catch (e) {}
			break;


			case 4:
				try {
					if (Handler.timeoutID) {
						window.clearTimeout(Handler.timeoutID);
						Handler.timeoutID = null;
					}

					if (Handler.Busy) {
						Handler.Busy = false;
						if (!Handler.Cancelled) {
							window.status="Done";
							Handler.ReturnHandler.onLoad(Handler);
						}
					}
				} 
				catch (e) 
				{
				}
				finally 
				{
					Handler.Busy = false;
				}
			break;
			}
		},


	cancelRequest: function() {
		this.cancelled = true;

		if (this.timeoutID) 
		{
			window.clearTimeout(this.timeoutID);
			this.timeoutID = null;
		}
		this.abortRequest(this);
	},


	abortRequest: function(Handler) 
	{
		if (Handler.XMLHTTPHandler!=null)
		{
			try {
				Handler.XMLHTTPHandler.abort();
				if (Handler.Busy){
					window.status="Aborted";
					Handler.ReturnHandler.onError(
						'timeout',
						'Request timed out',
						Handler);
				}
			}
			catch (e)
			{}

			Handler.Cancelled = true;
			Handler.Busy = false;
		}
	},


	getText: function () 
	{
		return this.XMLHTTPHandler.responseText;
	},


	getXML: function () 
	{
		return this.XMLHTTPHandler.responseXML;
	},


	getTags: function (tagName) 
	{
		try {
			return this.XMLHTTPHandler.responseXML.getElementsByTagName(tagName);
		} 
		catch (e)
		{
			return null;
		}
	},


	getTagText: function (parent,item,index)
	{
		var result = parent.getElementsByTagName(item)[index];
		if (result)
		{
			if (result.childNodes.length > 1) 
			{
				return result.childNodes[1].nodeValue;
			}
			else if (result.childNodes.length==1) 
			{
				return result.firstChild.nodeValue;
			}
		}
		else 
		{ 
			return ""; 
		}
	},
	
	resetData: function ()
	{
	
		this.Data = "";
	},

	addData: function (paramName,paramValue)
	{
		this.Data += (this.Data!="")?"&":"";
		this.Data += paramName + "=" + encodeURIComponent(paramValue);
	},

	
	createData: function (form)
	{
		var elements = form.elements;
		var pairs = new Array();
		
		var index;
		var name;
		var value;
		
		for (var index = 0; i < elements.length; i++)
		{
			if ((name = elements[i].name) && (value = elements[i].value)) //Checks that the Element has a name and value (and stores in in parameters)
			pairs.push(name + "=" + encodeURIComponent(value));
		}
		
		this.Data += pairs.join("&");
	},

	//Handlers
	onProgress:function(Text,ContentLength) {},
	onError:function(Status,StatusText,Handler) {window.alert("Error: ["+Status+"]"+StatusText)},
	onLoad:function(Handler) {},
	onInit:function(Handler) {}

}




function MergeChildrenItems(ChildNodes)
{
	if (!ChildNodes) {return}; //Return immediately on empty data
	
	var Data = "";
	var RunIndex;
	for (RunIndex=0; RunIndex<ChildNodes.length; RunIndex++)
	{
		Data += ChildNodes.item(RunIndex).data;
	}
	
	RunIndex = null; //Free up memory
	
	return (Data);
}

