// HAJAX
// a simple and dirty little Ajax Processor
// handles multiple, simultanious Ajax requests
//
// NO WARRANTY
// This code is provided "as is" without warranty of any kind, either
// expressed or implied, including, but not limited to, the implied warranties
// of merchantability and fitness for a particular purpose. You expressly
// acknowledge and agree that use of this code is at your own risk.

// global settings
// allow multiple requests
// hajax_allowMultiple
// This setting will turn on/off the ability to allow mutilpe requests to be processed globally
// this means, if you turn it on then all ajax calls can be run simultaneously
// 		if you turn it off then if a request is currently being processed then all subsequent requests will be blocked
//		until the curren request has been completed
var hajax_allowMultiple = true;
// hajax may also be set on a call by call basis to allow/disallow mutiple simultaneous requests
//		see parameter blockMultiple
// for a discussion of allowing/disallowing multiple simultaneous requests on a funtion by function basis
// in your own functions see the discussion at the end of this document

// if you would like the default alert shown that a request has been blocked
// set the following variable to true
var hajax_showMultipleBlockedMessage = false;

// do not edit these, flag that hajax used to see if a process is currently running or temporarily blocked
var hajax_running = false;
var hajax_temp_blockMultiple = false;

function hajax(url, call_function, parameters, method, pass, blockMultiple) {
	
	// **********************************************************************************************************
	// url = url of the script file on the server
	// can be absolute or reletive from page or doc root
	// can include http://domain
	// absolute urls are best if this will be called from several different levels of a site 
	//
	// call_function is a variable that contains the javascript function that will process whatever is returned from url
	// more info on creating call_function below
	//
	// parameters (optional) are any variable/value pairs that need to be sent to the server
	// example 'x=2&amp;y=3'
	//
	// method = GET or POST (optional default = GET)
	// POST must be used for long argument lists (GET URL's are limited to 256 characters
	// POST may fail, depending on the server, if no parameters are sent
	//
	// pass (optional)
	// anything in pass will be passed to call_function without alteration
	// values in pass would be anything that the called function might need as 
	// parameters other than the server response
	// since it is unaltered, anything that can be passed in a javascript varaible can be passed to the called function
	// including other functions or arrays
	//
	// blockMultiple (optional)
	// This parameter, if set to true will temporarily turn off multiple simultaneous requests
	// This will block the current call from running if there is already a process in progress as well as
	// Prevent any further calls until the current call is completed
	// 			If you call hajax with blockMultiple set to true then if there is no process running the call will be allowed
	//			and subsequect calls will be blocked
	//			If there is already a process running then the current call will blocked as well
	//			for more flexibility in allowing/disallowing multiple simultaneous requests
	//			see the discussion at the end of this document
	//
	// of the above parameters only url and call_function are required. The other three are optional
	// (exception: added a default call_function/response handler - see below 
	//		so now the only required parameter is the URL as long as non-empty element with the id "hajax_default"
	//		is available in the document
	// **********************************************************************************************************
	
	// **********************************************************************************************************
	// returns (sends to call_function) paremeters in the following order
	// 	server_response, pass, httpConnection, httpStatus, statusText, readError
	// 		server_response = the data returned by the called url
	// 		httpConnection = true or false, indicates if an http connection was succesfully created
	// 		httpStatus = the last http status returned by the server. Could indicate errors
	// 		statusText = text of the above http status number
	// 		readError = any errors in reading the response
	// it is completely up to the user and call_function to decide what is done with any of the above values
	// error capturing and handling is completely up to the user to deal with
	// **********************************************************************************************************
	
	// **********************************************************************************************************
	// creating a function to be called when a response is recieved from the server
	// at its simplest, create function as follows
	//
	// var alert_this = function (what) { alert(what); }
	// the parameter "what" will contain whatever was returned by the server
	//
	// more complicated
	// var myfunction = function(server_response, pass, httpConnection, httpStatus, statusText, readError) {
	// 		all instructions for function here
	// }
	//
	// the above function "myfunction" will recieve all paremeters returned by hajax
	// see the discussion about returned values above	
	// **********************************************************************************************************
	
	// **********************************************************************************************************
	// calling hajax
	// simplest form
	// hajax('http://mysite.com/ajax.php', myfunction);
	// the url that is being called and the function that will process the response (see discusion of creating functions above)
	// no parameters are sent to the server, method will default to "GET", and nothing will be passed from the call to the called function
	//
	// more complicated
	// hajax('http://mysite.com/ajax.asp', myfunction, 'x=2&y=5', 'POST', extra_values);
	// url = 'http://mysite.com/ajax.asp'
	// function to process the response = myfunction (see discussion of creating functions above)
	// query string = 'x=2&y=5', values to send to url
	// 'POST' = method to use (can be POST or GET)
	// extra_values = anythig that will be passed, unaltered, to the called function
	// any value not needed may be set to null, for instance if you wish to send no query string and use the 
	// default method of GET but you need to pass values to the called function then call hajax like this
	// hajax('http://mysite.com/ajax.asp', myfunction, '', '', extra_values);
	// **********************************************************************************************************
	
	// **********************************************************************************************************
	// default response handler
	// the default response handler will check for errors and if none exist will simply
	// dump the entire server response into the innerHTML of the element whose id is passed to Hajax
	// no extra formating of the server response is performed
	//
	// example:
	// hajax('http://mysite.com/ajax.asp', hajax_default, 'x=2&y=5', 'POST', 'test_div');
	// call myfunction in the script http://mysite.com/ajax.asp using the POST method and parameters of 'x=2&y=5'
	// dump server response into the element that has the id "test_div"
	//
	// hajax default does not even need to be explicitly called
	// example:
	// hajax('http://mysite.com/ajax.asp', '', 'x=2&y=5', 'POST', 'test_div');
	// is the same as the above example
	// if you do not specify a destination element id the default elment with an id of "hajax_default" will be used
	// example
	// hajax('http://mysite.com/ajax.asp', '', 'x=2&y=5', 'POST');
	// 
	// putting this all together, if you want to call the default handler and us an elment with the id of "hajax_default"
	// and use all other default settings you simply nee to use:
	// hajax('http://mysite.com/ajax.asp');
	//
	// **********************************************************************************************************
	
	// set defaults if not passed to function will recieve all parameters passed by hajax
	// see discussion of returned values above
	// it is up to the user to decide what to do with these values.
	if (blockMultiple) {
		hajax_temp_blockMultiple = true;
	}
	
	// see if multiple requests are allowed and if hajax is running
	
	
	
	if ((hajax_allowMultiple && !hajax_temp_blockMultiple) || !hajax_running) {
		hajax_running = true;
		if (!method || method == '') {
			method = 'GET';
		}
		method = method.toUpperCase();
		if (!parameters) {
			parameters = '';
		}
		if (!pass) {
			pass = false;
		}
		if (!call_function || call_function == '') {
			call_function = 'hajax_default';
		}
		if (call_function == 'hajax_default') {
			if (!pass) {
				pass = 'hajax_default';
			}
			call_function = function(response, id, httpConnection, httpStatus, statusText, readError) {
				if (httpConnection) {
					if (httpStatus == 200) {
						if (readError == '') {
							// call was successfull
							// throw response into inner html of passes div
							// check for existance of div
							if (id != '') {
								if (element = document.getElementById(id)) {
									element.innerHTML = response;
								} else {
									alert('Ajax Error: Element '+id+' Does Not Exist!')
								}
							} else {
								alert('Ajax Error: No Response Location Indicated')
							}
						} else {
							alert('Ajax Error reading http response: '+readError);
						}
					} else {
						alert('Ajax http Error: '+statusText);
					}
				} else {
					alert('Ajax Error: Failed to create an http connection!');
				}
			}
		}
		
		var httpConnection = false;
		var readError = false;
		var httpStatus = false;
		var statusText = false;
		var server_response = false;
		var xmlHttp = hajax_createXmlHttpRequestObject();
		hajax_process();
	} else {
		// multiple simultaneous requests blocked
		if (hajax_showMultipleBlockedMessage) {
			alert('There is already an Ajax Process Running.\nPlease Wait.');
		}
	}
	
	// **********************************************************************************************************
	// Functions to create connection, send request and recieve response
	// **********************************************************************************************************
	
	function hajax_createXmlHttpRequestObject() {
		// create new XMLHttpRequest Object
		xmlHttp == false;
		// will store the reference to the XMLHttpRequest object
		// this should work for all browsers except IE6 and older
		try {
			// try to create XMLHttpRequest object
			xmlHttp = new XMLHttpRequest();
		}
		catch(e) {
			// failed to create XMLHttpRequest object
			// assume IE6 or older
			var XmlHttpVersions = new Array("MSXML2.XMLHTTP.6.0",
																			"MSXML2.XMLHTTP.5.0",
																			"MSXML2.XMLHTTP.4.0",
																			"MSXML2.XMLHTTP.3.0",
																			"MSXML2.XMLHTTP",
																			"Microsoft.XMLHTTP");
			// try every prog id until one works
			for (var i=0; i<XmlHttpVersions.length && !xmlHttp; i++) {
				try { 
					// try to create XMLHttpRequest object
					xmlHttp = new ActiveXObject(XmlHttpVersions[i]);
				} 
				catch (e) {}
				// failed to create object
				// do nothing and try the next
			}
		}
		// return the object
		// returns false if we were unable to create any object
		return xmlHttp;
	}
	
	function hajax_process() {
		// make request to server
		if (xmlHttp) {
			httpConnection = true;
			if (method == 'GET') {
				if (parameters != '') {
					url = url + '?' + parameters;
				}
				post_args = null;
			} else {
				post_args = parameters;
			}
			try {
				xmlHttp.open(method, url, true);
				xmlHttp.onreadystatechange = hajax_handleRequestStateChange;
				if (method == 'POST') {
					//Send the proper header information along with the request
					xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
					xmlHttp.setRequestHeader("Content-length", post_args.length);
					xmlHttp.setRequestHeader("Connection", "close");
				}
				xmlHttp.send(post_args);
			}
			catch (e) {
				// unable error openenng connection
				statusText = 'Ajax Error sending request';
				call_function(server_response, pass, httpConnection, httpStatus, statusText, readError);
				hajax_temp_blockMultiple = false;
				hajax_running = false;
			}
		} else {
			// could not connect, call response handler
			call_function(server_response, pass, httpConnection, httpStatus, statusText, readError);
			hajax_temp_blockMultiple = false;
			hajax_running = false;
		}
	}
	
	function hajax_handleRequestStateChange()  {
		// wait for request to be complete and then process returned data
		readError = '';
		if (xmlHttp.readyState == 4) {
			// when readyState is 4 (done), we also read the server response
			// continue only if HTTP status is "OK"
			if (xmlHttp.status == 200)  {
				httpStatus = 200;
				statusText = xmlHttp.statusText;
				try {
					// read the message from the server
					server_response = xmlHttp.responseText;
				}
				catch(e) {
					// display error message
					//alert("Error reading the response: " + e.toString());
					readError = e.toString();
				}
			} else {
				// display status message
				//alert("There was a problem retrieving the data:\n" + xmlHttp.statusText);
				statusText = xmlHttp.statusText;
				httpStatus = xmlHttp.status;
			}
			// call the function to deal with the server response
			// pass status and errors to server response processor
			// it is up to that function to deal with any errors
			call_function(server_response, pass, httpConnection, httpStatus, statusText, readError);
			hajax_temp_blockMultiple = false;
			hajax_running = false;
		}
	}
}

// the following is an example of a function to process a server response
// this function is not used
function hajax_default(response, id, httpConnection, httpStatus, statusText, readError) {
	if (httpConnection) {
		if (httpStatus == 200) {
			if (readError == '') {
				// call was successfull
				// throw response into inner html of passed div id
				// check for existance of div
				if (id != '') {
					if (element = document.getElementById(id)) {
						element.innerHTML = response;
					} else {
						alert('Ajax Error: Element '+id+' Does Not Exist!')
					}
				} else {
					alert('Ajax Error: No Response Location Indicated')
				}
			} else {
				alert('Ajax Error reading http response: '+readError);
			}
		} else {
			alert('Ajax http Error: '+statusText);
		}
	} else {
		alert('Ajax Error: Failed to create an http connection!');
	}
}

// blocking multiple simultaneous requests on a function-by-function basis
// if you would like to allow multiple simultaneous ajax requests as a general rule
// but there are some request types where you wish to only allow a single request to be processed and 
// force the user to wait until this request is complete before making a new request
// add some varaible that you can use as a flag to test it is running
// for instance:
//			var myFunction_running = false
// add the above outside of any function calls so that it will be available to all JavaScript functions (global)
//
//
// Then, in the script or function that calls hajax, first test this flag and then turn in on:
//			if (!myFunction_running) {
//				myFunction_running = true;
//        // perform statements to call hajax here
//			} else {
//				// you could do something if it is already running, for instance alerting the user that they
//				// will need to try again. This is not necessary, you can simply ignore the request completely
//			}
//
// When your function that is called to process the server response has completed
// turn the flag off as the last statement in the function to allow further requests to this function
//			myFunction_running = false;
//