/* -------------------------------------------------------------------------- */
/* ---- AJAX REQUEST QUEUE HANDLER ------------------------------------------ */
/* -------------------------------------------------------------------------- */

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



/* ----------------------------------------------- */
/* ---- XMLRPCJob ---------- Class Definition ---- */
/* ----------------------------------------------- */
function XMLRPCJob( url, data, post, callbackObject ) {
	// Properties
	this.xmlHttp = GetHttpRequestObject();
	this.url = url;
	this.method = post;
	this.callbackObject = callbackObject;
	this.manager = null;
	this.validateXML = true;
	this.index = 0;
	
	this.data = data;
	
	// Methods
	this.Execute = function() {
		xmlRPCJobPool.Add( this );
	}
	
	this.Send = function() {
		this.xmlHttp.onreadystatechange = new Function( this.GetEventHandlerText() );
		
		if( this.method ) {
			this.xmlHttp.open( "POST", this.url, true );
			this.xmlHttp.setRequestHeader( "Content-type", "application/x-www-form-urlencoded" );
			this.xmlHttp.setRequestHeader( "Content-length", this.data.length );
			this.xmlHttp.setRequestHeader( "Connection", "close" );
			this.xmlHttp.send( this.data );
		} else {
			this.xmlHttp.open( "GET", this.url + ( this.data.length > 0 ? "?" + this.data : "" ), true );
			this.xmlHttp.send( null );
		}
	}
	this.Dispose = function() { this.manager.JobDisposed( this.index ); }
	
	this.ValidateResponse = function() {
		if( this.xmlHttp.responseXML === null )
			this.error = this.xmlHttp.responseText;
	}
	this.TransportError = function() { alert( "AJAX HTTP Error: " + this.xmlHttp.status + ": " + this.xmlHttp.statusText ); }
	this.ExecutionError = function() { alert( "AJAX Operation Error:\n" + this.error ); }
	
	this.GetEventHandlerText = function() {
		return "\
		var jobObject = xmlRPCJobPool.list[" + this.index + "];\
		if( jobObject.xmlHttp.readyState != 4 ) return;\
		if( jobObject.xmlHttp.status != 200 ) {\
			jobObject.TransportError();\
		} else {\
			if( jobObject.validateXML ) jobObject.ValidateResponse();\
			if( jobObject.error != null ) {\
				jobObject.ExecutionError();\
			} else {\
				if( jobObject.oncomplete ) jobObject.oncomplete();\
			}\
		}\
		jobObject.Dispose();";
	}
	
	this.oncomplete = null;
}




/* ----------------------------------------------- */
/* ---- XMLRPCJobPool ------ Class Definition ---- */
/* ----------------------------------------------- */
function XMLRPCJobPool() {
	// Properties
	this.list = new Array();
	
	// Methods
	this.Add = function( job ) {
		job.manager = this;
		job.index = ( this.list.push( job ) - 1 );
		job.Send();
	}
	
	this.JobDisposed = function( index ) {
		this.list[ index ] = null;
		
		for( var i in this.list )
			if( this.list[ i ] !== null ) return;
		
		this.list.splice( 0, this.list.length );
	}
}

// A global object for pooling RPC requests.
var xmlRPCJobPool = new XMLRPCJobPool();



/* ----------------------------------------------- */
/* ---- XML Data Unpacking ----------------------- */
/* ----------------------------------------------- */
function UnpackXMLIdList( xmlDocument ) {
	var ids = xmlDocument.documentElement.getElementsByTagName( "id" );
	var returnArray = new Array();
	
	for( var index = 0; index < ids.length; index++ ) {
		var currentNode = ids.item( index );
		if( currentNode.nodeType != 1 ) continue;
		returnArray.push( currentNode.textContent == undefined ? currentNode.text : currentNode.textContent );
	}
	
	return returnArray;
}
