/*
================================================================================
                                 /\          /\                                 
                                /  \        /  \                                
                               /    \      /    \                               
                              /      \    /      \                              
                             /        \  /        \                             
                            /         / /          \                            
                           /         / /            \                           
                          /         / /              \                          
                         /       /\/ /       /\       \                         
                        /       /   /       /  \       \                        
                       /       /   /       /    \       \                       
                      /       /   /       / /\   \       \                      
                     /       /   /       / /  \   \       \                     
                    /       /   /       / /    \   \       \                    
                   /       /   /       / /      \   \       \                   
                  /       /   /       /  \       \   \       \                  
                  \       \   \       \  /       /   /       /                  
                   \       \   \       \/       /   /       /                   
                    \       \   \              /   /       /                    
                     \       \   \            /   /       /                     
                      \       \   \          /   /       /                      
                       \       \   \        /   /       /                       
                        \       \   \      /   /       /                        
                         \       \   \    /   /       /                         
                          \       \   \  /   /       /                          
                           \       \   \/   /       /                           
                            \       \      /       /                            
                             \       \    /       /                             
                              \       \  /       /                              
                               \       \/       /                               
                                \              /                                
                                 \            /                                 
                                  \          /                                  
                                   \        /                                   
                                    \      /                                    
                                     \    /                                     
                                      \  /                                      
                                       \/                                       
================================================================================
H T T P       R e q u e s t       f o r        A J A X       o p e r a t i o n s
================================================================================
Usage: To begin the sequence, call requestDocument with your XML/text generating 
application. executeOnReady is the handling function for the response.  
executeOnReady should make a call to getDocument to get the response document.

<!> executeOnReady must be declared without quotes (e.g. myFunction) if no 
    parameter is declared. If a parameter must be declared, or if you want use 
    your function with parentesis (e.g. "myFunction();" or 
                                       "myFunction('my parameters goes here');")

This section of code must be thought of as a concurrent environment.  We only 
want one XMLHttpRequest running at a time, otherwise requests can get mixed up.
A binary semaphore is used to attempt to ensure this.  
                                        
Sample 1 (great for deal with XML objects):
ŻŻŻŻŻŻŻŻ
function requestData(){
	requestDocument("myXML.xml",executeWhenDone);
}
function executeWhenDone() {
	var requestedXML = getDocument(); 
	if ( requestedXML != null ) {
		alert(requestedXML.getElementsByTagName("result").length); // your code...
	}
}
                                        
Sample 2 (great to dinamically insert contents in a rendered page):
ŻŻŻŻŻŻŻŻ
function requestData(){
	requestDocument("myHTML.html",executeWhenDone);
}
function executeWhenDone() {
	var requestedText = getDocument("text"); // "text" is used to parse the
	                                         // incoming stream into a plan one 
	                                         // (not a XML-tree)
	if ( requestedText != null ) {
		myDiv.innerHTML = requestedText; // your code...
	}
}
                                        
Sample 3 (performing a function with parameters):
ŻŻŻŻŻŻŻŻ
function requestData(){
	requestDocument("myXML.xml","executeWhenDone('my parameter')");
}
function executeWhenDone(incomingParameter) {
	var requestedXML = getDocument(); 
	if ( requestedXML != null ) {
		alert(requestedXML.getElementsByTagName("result").length); // your code...
		alert(incomingParameter); // will show a alert box with "my parameter"
	}
}
________________________________________________________________________________
ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
*/
// Library settings
// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
var httpRequestDebugMode =           0; // debug mode for this lib (only 0 or 1)
var httprequestHighlightColor = "#69f"; // hrTrace highlight color

// Global variables
// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
var requestQueue   =       new Array(); // queue of requests
var noRequests     =              true; // binary semaphore
var hrTraceMessage =             false; // display enableHRmessage

// Enable/disable this lib tracing
if (httpRequestDebugMode) { 
	hrTrace = trace; 
} else { 
	hrTrace = function(){
		if (!hrTraceMessage) {
			var enableHRmessage = "";
			enableHRmessage += "HTTP Request debug messages are disabled. ";
			enableHRmessage += "Click ";
			enableHRmessage += "<a href=\"javascript:void(hrTrace=trace);void(httpRequestDebugMode=1);\">";
			enableHRmessage += "here";
			enableHRmessage += "</a>";
			enableHRmessage += " to enable then.";
			trace(enableHRmessage);
			hrTraceMessage = true;
		}
	}; 
}

/*
________________________________________________________________________________
ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
Purpose: Add an XMLHttpRequest to the queue.  Please use this rather than 
         loadDocument directly (Unless you want weird behaviour where your 
         requests get mixed up.)
Inputs:  requestedURL:   A valid URL to call, e.g.: http://domain/myfile.xml
         executeOnReady: A function to be called when the requested URL is ready.
                         Read more about it above.
Return:  none
*/
function requestDocument(requestedURL, executeOnReady) {
	hrTrace("[F] function requestDocument(\"</b>" + requestedURL + "<b>\", </b>executeOnReady<b>)", httprequestHighlightColor);
	requestQueue.push({requestedURL: requestedURL, executeOnReady: executeOnReady});
	hrTrace("requestQueue.length: <b>" + requestQueue.length + "</b>");
	// Check to see if you're the first to arrive, and the waiting room is empty.
	if (noRequests) {
		var thisRequest = requestQueue.pop();
		loadDocument(thisRequest.requestedURL, thisRequest.executeOnReady);
	}
} // requestDocument
/*
________________________________________________________________________________
ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
Purpose: Make an XMLHttpRequest call if possible (depends on the browser).
Inputs:  requestedURL:   URL of the xml file. Can be relative. 
                         e.g.: requestxml_full.xml
         executeOnReady: A function to be called when the requested URL is ready.
                         Read more about it above.
Return:  none
*/
function loadDocument(requestedURL, executeOnReady) {
	hrTrace("[F] function loadDocument(\"</b>" + requestedURL + "<b>\", </b>executeOnReady<b>)", httprequestHighlightColor);
	noRequests = false;
	
	// To prevent IE from cacheing the XML document returned from this, append
	// a timestamp to the URL to ensure that it is unique.  The page itself 
	// doesn't actually use the time for anything.
	var failsafeRandom = "rnd=" + Math.floor(Math.random() * 0xFFFFFF).toString(16);
	if ( requestedURL.indexOf("?") < 0 ) { 
		hrTrace("Add \"<b>?</b>\" to the URL");
		var finalURL = requestedURL + "?" + failsafeRandom; 
	} else { 
		hrTrace("Add \"<b>&</b>\" to the URL");
		var finalURL = requestedURL + "&" + failsafeRandom; 
	}
	
	hrTrace("File requested: <b><a href=\"" + finalURL + "\" target=\"_blank\">" + finalURL + "</a></b>" ); 
 
	if (window.XMLHttpRequest) {
		// branch for native XMLHttpRequest object
		hrTrace("branch for <b>native XMLHttpRequest object</b>");
		httpRequest = new XMLHttpRequest();
		
		// execute the onready function
		hrTrace("typeof(executeOnReady): <b>" + typeof(executeOnReady) + "</b>");
		if ( typeof(executeOnReady) == "function" ) {
			httpRequest.onreadystatechange = executeOnReady;
		} else if ( typeof(executeOnReady) == "string" ) {
			httpRequest.onreadystatechange = function () { eval(executeOnReady); };
		}
		
		httpRequest.open("GET", finalURL, true);
		httpRequest.send(null);
	} else if (window.ActiveXObject) {
		// branch for IE/Windows ActiveX version
		hrTrace("branch for <b>IE/Windows ActiveX version</b>");
		httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
		if (httpRequest) {
			
			// execute the onready function
			hrTrace("typeof(executeOnReady): <b>" + typeof(executeOnReady) + "</b>");
			if ( typeof(executeOnReady) == "function" ) {
				httpRequest.onreadystatechange = executeOnReady;
			} else if ( typeof(executeOnReady) == "string" ) {
				httpRequest.onreadystatechange = function () { eval(executeOnReady); };
			}
			
			httpRequest.open("GET", finalURL, true);
			httpRequest.send();
		}
	} else {
		window.alert("This browser does not support HTTP requests" + "\n" + "Please contact technical support");
	}
} // loadDocument
/*
________________________________________________________________________________
ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
Purpose: Return the HTTP response.
Inputs:  forceMIMEto: if ommited, will retun a XML object.
                      if "text", will return a text string containing the 
                      requested file contents
Return:  - null if it is not yet ready or if there is 
                an error in the request/response or;
         - an XML object or a text string containing the requested file contents
*/
function getDocument(forceMIMEto) {
	hrTrace("[F] function getDocument(\"</b>" + forceMIMEto + "<b>\")", httprequestHighlightColor);
	if (httpRequest.readyState == 0) { hrTrace("Request state: <b>0: uninitialized...</b>"); }
	if (httpRequest.readyState == 1) { hrTrace("Request state: <b>1: loading...</b>");       }
	if (httpRequest.readyState == 2) { hrTrace("Request state: <b>2: loaded...</b>");        }
	if (httpRequest.readyState == 3) { hrTrace("Request state: <b>3: interactive...</b>");   }
	if (httpRequest.readyState == 4) { hrTrace("Request state: <b>4: complete...</b>");      }
	if (httpRequest.readyState == 4) { 
		// Ensures that we return this request rather than some other one
		// that slips through the semaphore between the semaphore release
		// and the return (basically returning the same request twice and
		// skipping this one).
		var tempHttpRequest = httpRequest;
		if (requestQueue.length > 0) {
			var thisRequest = requestQueue.pop();
			loadDocument(thisRequest.requestedURL, thisRequest.executeOnReady);
		} else {
			noRequests = true;
		}
		
		hrTrace("tempHttpRequest.status: <b>" + tempHttpRequest.status + "</b>");
		hrTrace("tempHttpRequest.statusText: <b>" + tempHttpRequest.statusText + "</b>");
		hrTrace("tempHttpRequest.getAllResponseHeaders(): <br /><b>" + tempHttpRequest.getAllResponseHeaders() + "</b>");
		
		if (tempHttpRequest.status) { 
			
			hrTrace(
				"Requested file contents:" +
				"<code>" + 
				tempHttpRequest.responseText.replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\t/g, " ") + 
				"</code>"
			);
			
			// get http status
			var tempHttpRequestStatus = tempHttpRequest.status;
			// process the request even if errors occours
			var processAnyway = false;

			if (tempHttpRequestStatus != 200) {
				// it may be a 404 or 403 or 500... who knows ?
				var alertMessage = "";
				alertMessage += "An error occurred while processing request:" + "\n";
				alertMessage += "HTTP" + tempHttpRequest.status;
				// Some browsers (as Opera) does not have the statusText property
				if ( tempHttpRequest.statusText != undefined ) {
					alertMessage += ": " + tempHttpRequest.statusText;
				}
				alertMessage += "\n";
				alertMessage += "Please contact technical support";
				window.alert( alertMessage );
				// show message if debug is enabled
				if (httpRequestDebugMode) {processAnyway = true;}
			}
			
			// Finish the job
			if (tempHttpRequestStatus == 200 || processAnyway) {
				hrTrace("Inserting requested file contents");
				// process request
				if ( forceMIMEto == "text" ) {
					// return a text
					return tempHttpRequest.responseText;
				} else {
					// return a XML
					return tempHttpRequest.responseXML.documentElement;
				}
			} else {
					return "";
			}
		}
	}
	
	// if not ready yet...
	return null;
} // getDocument
/*
________________________________________________________________________________
ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
*/
