/** A minimalist's AJAX library
 * 
 * @author Erick S <esatire@gmail.com>
 * @version 1.0.3 20/08/2007
*/

/** empty function to simulate onreadystatechange = null */
function NullVoid(){}

/* static constants */
XHR.DEFAULT_TIMEOUT = 8000;

/** XmlHttpRequest object. Keeps everything encapsulated. Reusable request object */
function XHR(requestTimeout)
{
	// private properties
	var request = CreateXmlHttpRequest();
	var myself = this;
	var isInProgress = false;
	var resultFunc = null;
	var data = null; // if you'd like to pass an object to the result function

	// public properties
	this.timer = null; // points to an onTimeout timer so we can clear it
	// how many miliseconds before we abort request
	this.requestTimeout = (typeof requestTimeout == 'undefined') ? XHR.DEFAULT_TIMEOUT : requestTimeout;
	
	// private methods - need to be private so can be called from async result funcs
	var ErrorFunc = defaultErrorFunc; // good for reporting errors in different ways
	var TimeoutFunc = xmlHttpTimeout; // this one shouldn't be changed because it uses private vars
	
	// ### public methods ###

	/** checks wether request is in progress */
	this.InProgress = function() {return isInProgress;}
	// setters for private methods and vars
	this.SetErrorFunc = function(func){	ErrorFunc = func; }
	this.SetData = function(someData){ data = someData; }

/** For sending XHR before leaving a page (onunload) - synchronous and ignores results */
	this.PostAndForget = function(strURL,strSubmit)
	{
		request.open('POST', strURL, false);
		request.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
		request.send(strSubmit);
	}
	/**
	 * Sends a POST request to server
	 * 
	 * in order not to create 2 seperate functions,
	 * if a timeout func is excluded then we use anonymous functions
	 * 
	 * @param {string} strUrl The server side script URL
	 * @param {string} strSubmit The POST data
	 * @param {string} newResultFunc Which function will be executed on result
	 * @param {mixed}  someData any piece of data to be passed to the result func
	 */
	this.Post = function(strURL,strSubmit,newResultFunc,someData)
	{
		if (isInProgress)
		{
			ErrorFunc("Request is already in progress. Please wait.");
			return;
		}
		isInProgress = true;
		if (typeof (someData) != 'undefined') data = someData;
		else data = null; // so previous data won't be used
		
		request.open('POST', strURL, true);
		request.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
		resultFunc = newResultFunc;
		this.timer = window.setTimeout(TimeoutFunc,this.requestTimeout);
		request.onreadystatechange = xmlHttpResult;
		request.send(strSubmit);
	}
	/**
	 * Same as post, but without any post string
	 */
	this.Get = function(strURL, newResultFunc,someData)
	{
		if (isInProgress)
		{
			ErrorFunc("Request is already in progress. Please wait.");
			return;
		}
		isInProgress = true;
		if (typeof (someData) != 'undefined') data = someData;
		else data = null; // so previous data won't be used
		
		request.open('GET', strURL, true);
		resultFunc = newResultFunc;
		this.timer = window.setTimeout(TimeoutFunc,this.requestTimeout);
		request.onreadystatechange = xmlHttpResult;
		request.send(null);
	}
	/** The Asynchronous result function */
	function xmlHttpResult()
	{
	// DONT try a finally clause here because it will run before the request is ready
		try
		{
			if (request.readyState != 4) return;
			if (request.status == 200)
			{
				window.clearTimeout(myself.timer);
				request.onreadystatechange = NullVoid; // to prevent memleaks
				resultFunc(request.responseText,data);
				data = null; // to prevent a DOM object from sticking around
				isInProgress = false;
			}
			else
			{
				ErrorFunc("Error contacting server:\n" + request.statusText);
			}
			isInProgress = false;		
		}
		catch (e)
		{
			// Deal with server not available error:
			if (e.message.indexOf("0x80040111") != -1)
				ErrorFunc('Server not available');
			else
				ErrorFunc('Exception in result:' + e.message);

			isInProgress = false;
		}
	}
	/** The default timeout function. Will be called if request takes too long */
	function xmlHttpTimeout()
	{
		try
		{
			if (request.readyState != 4 && request.readyState != 0)
			{
			// we have to null the function before aborting, so we won't receive error message
				request.onreadystatechange = NullVoid;
				request.abort();
				ErrorFunc("Request took too long. Aborted");
			}
		}
		catch (e)
		{
			ErrorFunc("Timeout Error " + e.message);
		}
		finally 
		{
			isInProgress = false;
		}
	}
	/** default error function */
	function defaultErrorFunc(errorText)
	{
		if (typeof(MessageBox) != 'undefined') MessageBox.Alert(errorText);
		else alert(errorText);
	}
	/** As its name implies - Creates an XHR object */
	function CreateXmlHttpRequest()
	{
		// Everything except IE6
		if (window.XMLHttpRequest) return new XMLHttpRequest();
		if (window.ActiveXObject)
		{
			var xmlHttpReq;	
			try
			{
  				xmlHttpReq = new ActiveXObject("Msxml2.XMLHTTP");
  				return xmlHttpReq;
			}
			catch (e)
			{
  				try
				{
					xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
					return xmlHttpReq;
  				}
				catch (e2){}
  			}
 		}
	 	// no support for httprequest - old browser or js turned off (or ?)
 		alert("Either your javascript is turned off\nOr your browser doesn't support this site's functionality");
		return null;
	}
}
/** static function for encoding things like & (ampersands) */
XHR.Encode = function(text)
{
	return text.replace(/&/,'%26');
}