var globalajaxobject;

/**
 AjaxObject
 
 This object provides an easy to use wrapper for the XMLHttpRequest object
 in whatever form it exists (ActiveXObject or part of Javascript). The
 functions which are called do not have to be accessible in the global scope
 and can be passed any object reference which helps free Ajax requests from
 old procedural programming styles.

 @author Robert Flack
 @version 1.0

 */

function AjaxObject()
{

	/**
	* This is the type for a request object, which exists on the queue
	* of awaiting requests. All new requests exist as this before being
	* made.
	*
	* All request objects also have a function cancel() which will
	* remove them from the request queue, effectively cancelling the
	* request.
	*/
	function reqType()
	{
		this.next=null;
		this.prev=null;
		this.data='';
		this.postmethod='POST';
		this.statusreports=0;
		this.hndparam=null;
	};
	
	/* No requests exist at runtime */
	this.requestqueue=null;
	
	this.requestTimeout=0;
	this.timeoutTimer=null;
	
	/* Determine which method this browser supports for Ajax requests */
	if (window.XMLHttpRequest) {
		this.method="xmlhttprequest";
	}else if (window.ActiveXObject && (this.ajaxobj=new ActiveXObject("Microsoft.XMLHTTP"))){
		this.method="activexobject";
	}
	
	/** 
	 * Clears the active request as it has not succeeded within the
	 * set timeout value
	 */
	this.clearRequest=function()
	{
		if (this.requestqueue!=null)
		{
			this.requestqueue.cancel();
		}
		clearTimeout(this.timeoutTimer);
	}
	
	/** 
	 * The generic response handler for all ajax requests, this object
	 * accepts state changes and then delegates functionality to the user
	 * provided function to handle the response only for states which
	 * the user wishes to handle. If the request has completed it will
	 * also fire off the next request in the queue.
	 */
	this.handleResponse=function()
	{
	    if (this.ajaxobj.readyState == 4) {
	    	/* Fire off the user handler if successful */
	        if (this.ajaxobj.status == 200)
	        {
	        	if (this.requestqueue.hnd!=null)
					this.requestqueue.hnd(this.ajaxobj,this.requestqueue.hndparam);
	        }else if (this.requestqueue.statusreports>0){
			/* If the user wishes to handle Ajax errors, fire off their handler here */
	        	if (this.requestqueue.hnd!=null)
					this.requestqueue.hnd(this.ajaxobj,this.requestqueue.hndparam);
	        }else{
	        	alert(this.ajaxobj.statusText);
	        }
			
        	/* The request completed, so remove it from the queue and
		 * fire off another request
		 */
        	 if (this.requestqueue.next==this.requestqueue)
			{
				this.requestqueue=null;
			}else{
				this.requestqueue.prev.next=this.requestqueue.next;
				this.requestqueue.next.prev=this.requestqueue.prev;
				this.requestqueue=this.requestqueue.next;
				this.processRequest();
			}
	    } else if (this.requestqueue.statusreports>1)
	    {
	    	/* If the user wishes to handle state changes, then fire off
		 * their event handler here as well
		 */
        	if (this.requestqueue.hnd!=null)
		    	this.requestqueue.hnd(this.ajaxobj,this.requestqueue.hndparam);
	    }
	};
	
	/**
	 * This functions handles firing off the next request on the queue
	 * if an event exists.
	 */
	this.processRequest=function()
	{
		clearTimeout(this.timeoutTimer);
		if (this.requestqueue!=null)
		{
			if (this.method=="xmlhttprequest")
			{
				this.ajaxobj=new XMLHttpRequest();
			}else if (this.method=="activexobject"){
				this.ajaxobj = new ActiveXObject("Microsoft.XMLHTTP");
			}
		        if (this.ajaxobj) {
				if (this.requestTimeout>0)
				{
					setTimeout('ajax.clearRequest()',this.requestTimeout);
				}
				globalajaxobject=this;
				this.ajaxobj.onreadystatechange=function(){globalajaxobject.handleResponse();};
				this.ajaxobj.open(this.requestqueue.postmethod, this.requestqueue.url, true);
				this.ajaxobj.setRequestHeader("Content-Type", "text/xml");
				this.ajaxobj.send(this.requestqueue.data);
		        }
		}
	};
	
	/**
	 * Set the time an Ajax request is allowed to take before being
	 * terminated so that other requests can occur
	 *
	 * @param timedelay - 	The amount of time that can pass before any
	 *			requests will be cancelled in milliseconds.
	 */
	this.setRequestTimeout=function(timedelay)
	{
		this.requestTimeout=timedelay;
	}
	
	/**
	 * Make an Ajax request calling the handler function on success. Read
	 * parameter descriptions for more information.
	 *
	 * @param requesturl	The url to call with this request
	 * @param handler	The function to call with the response. This
	 *			will be called with the parameters ajaxobj and
	 *			handlerparam in this order. ajaxobj is the
	 *			ajax object and the response can be retreived
	 *			from ajaxobj.responseText.
	 * @param rawdata	The URL can only handle so much information, so
	 *			if you want to send more, put it in this value.
	 *			This is sent after the request header and can
	 *			be retrieved in PHP with $HTTP_RAW_POST_DATA
	 %			Default: ''
	 * @param statuslevel	This determines how much you want your handler
	 *			function to take care of, possible values are:
	 *			\li 0	Only call handler on success
	 *			\li 1	Call handler on completion with any
	 *				errors that may have occurred.
	 *			\li 2	Call handler on all state changes
	 *				(useful for progress updates)
	 %			Default: 0
	 * @param handlerparam	Since handler is called in the global scope,
	 *			you can pass any variables that do not exist
	 *			globally here. They will be the second
	 *			parameter your handler function is called with.
	 *			Default: null
	 * @return		Returns a request object corresponding to this
	 *			request. This object has a cancel() method which
	 *			allows you to cancel the request at any point
	 *			before it has began processing.
	 */
	this.requestPage=function(requesturl,handler,rawdata,statuslevel,handlerparam)
	{
		/* Construct a request object matching your request */
		var req;
		req = new reqType();
		req.url=requesturl;
		if (rawdata!=null)
			req.data=rawdata;
		req.hnd=handler;
		if (handlerparam!=null)
			req.hndparam=handlerparam;
		if (statuslevel!=null)
			req.statusreports=statuslevel;
		req.ajax=this;
		req.cancel=function()
		{
			/* If the request is currently being processed then
			 * do not allow it to be cancelled. */
			if (this==this.ajax.requestqueue)
				return false;

			/* Otherwise, remove the request from the queue */
			this.prev.next = this.next;
			this.next.prev = this.prev;
			return true;
		};

		/* Place the request object on the request queue. If the queue
		 * was empty then immediately handle this request, otherwise
		 * it will wait for whatever existing requests are running to
		 * complete. */
		if (this.requestqueue==null)
		{
			req.next=req;
			req.prev=req;
			this.requestqueue=req;
			this.processRequest();
		}else{
			this.requestqueue.prev.next=req;
			req.prev=this.requestqueue.prev;
			this.requestqueue.prev=req;
			req.next=this.requestqueue.next;
		}
		return req;
	};
	
}
/* Remove this line if you want to create the ajax object somewhere within
 * your code rather than having it exist in the global scope. */
var ajax = new AjaxObject();

