/**
 * This file must be included for using Ajax support. When an instance of the Ajax class is created, the request function
 * may be used to post a request. Some handlers (onLoad, onSuccess & onFailure) may be passed as arguments.
 * 
 * @version 2010-11-08
 * @author <a href="mailto:r.tennapel@griponservice.nl?SUBJECT=ajax.js">R. ten Napel, ing.</a>
 **/

/**
 * Create an XML HTTP object.
 * 
 * @return					The XML HTTP object.
 **/
function createXmlHttpObject() {
	var xmlHttp;
	
	// Internet Explorer:
	if (window.ActiveXObject) {
		var ie_versions = [
		        "MSXML2.XMLHttp.6.0", 
				"MSXML2.XMLHttp.5.0", 
				"MSXML2.XMLHttp.4.0", 
				"MSXML2.XMLHttp.3.0", 
				"MSXML2.XMLHttp", 
				"Microsoft.XMLHttp"
			];
		
		// Detect the right ActiveXObject:
		for (var i = 0; i < ie_versions.length; i++) {
			try {
				xmlHttp = new ActiveXObject(ie_versions[i]);
				
				break;
			} catch (error) {
				xmlHttp = null;
			}
		}
		
		// Show error if no Ajax:
		if (xmlHttp == null) {
			alert("Error: Did not find Ajax-support!");
		}
	// Firefox, Opera 8.0+, Safari:
	} else if (window.XMLHttpRequest) {
		xmlHttp = new XMLHttpRequest();
	}
	
	return xmlHttp;
}

/**
 * The class that handles Ajax requests. Instantiate this class for Ajax support / calls. Multiple callBacks are supported.
 * 
 * @param element			The element to place the response of the request in.
 * @param url				The URl to request.
 * @param callBack			The callBack function.
 * @param onLoad			Called before the actual request.
 * @param onSuccess			Called when the request was successfull.
 * @param onFailure			Called when the request has failed.
 * @param async				If the Ajax request should be asynchronous or not.
 * @param method			The Ajax open method.
 **/
function Ajax(element, url, callBack, onLoad, onSuccess, onFailure, async, method) {
	// Create the XML HTTP object:
	this.xmlHttp = createXmlHttpObject();
	
	// Store the destination element, URL and callBack function:
	this.element = element;
	this.url = url;
	this.callBacks = (callBack == null) ? new Array() : new Array(callBack);
	
	// Define the onLoad handler:
	if (onLoad == null) {
		onLoad = function() {
			// TODO ...
		};
	}
	this.onLoad = onLoad;
	
	// Define the onSuccess handler:
	if (onSuccess == null) {
		onSuccess = function(response, callBacks) {
			element.innerHTML = response;
			
			// Iterate through each callBack:
			for (var i = 0; i < callBacks.length; i++) {
				// Handle the callBack function if it exists:
				if (callBacks[i] != null) {
					callBacks[i].call(this, response);
				}
			}
		};
	}
	this.onSuccess = onSuccess;
	
	// Define the onFailure handler:
	if (onFailure == null) {
		onFailure = function(response) {
			alert("Failure: " + response);
		};
	}
	this.onFailure = onFailure;
	
	// Define if the Ajax request is asynchronous or not:
	this.async = true;
	if (async == false) {
		this.async = false;
	}
	
	// Define the Ajax open method, std. = "GET":
	if (method == null) { method = "POST"; }
	this.method = method;
}

/**
 * Add a callBack function to the callBack stack.
 * 
 * @param callBack			The callBack that is added to the callBack stack which is handled after the request completes.
 **/
Ajax.prototype.addCallBack = function(callBack) {
	this.callBacks.add(callBack);
};

/**
 * Clear the callBack stack.
 **/
Ajax.prototype.clearCallBacks = function() {
	this.callBacks.clear();
};

/**
 * This function requests the contents of an URL to the given element.
 **/
Ajax.prototype.request = function() {
	// If AJAX is not supported:
	if (this.xmlHttp == null) {
		alert("Your browser does not support AJAX!");
		
		return;
	}
	
	// Call the function that handles the on load event:
	this.onLoad();
	
	// Load the stated page by it's URL:
	if (this.url.indexOf("?", 0) == -1) {
		url = this.url + "?";
	} else {
		url = this.url + "&";
	}
	
	// Add a SID to the url:
	url = url + "sid=" + Math.random();
	
	// Retrieve the page:
	this.xmlHttp.open(this.method, url, this.async);
	
	// The params must be extracted when using the POST-method and a special header must be send:
	if (this.method == "POST") {
		var params = url.substr(url.indexOf("?") + 1);
		
		// Send the proper header information along with the request:
		this.xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
		this.xmlHttp.setRequestHeader("Content-length", params.length);
		this.xmlHttp.setRequestHeader("Connection", "close");
	}
	
	// Add a ready state handler to the XML HTTP object:
	var xmlHttp = this.xmlHttp;
	var element = this.element;
	var onSuccess = this.onSuccess;
	var onFailure = this.onFailure;
	var callBacks = this.callBacks;
	this.xmlHttp.onreadystatechange = function() {
		if (xmlHttp.readyState == 0) {
			// The request is uninitialized (before you've called open()):
		} else if (xmlHttp.readyState == 1) {
			// The request is set up, but hasn't been sent (before you've called send()):
		} else if (xmlHttp.readyState == 2) {
			// The request was sent and is being processed (you can usually get content headers from the response at this point):
		} else if (xmlHttp.readyState == 3) {
			// The request is being processed; often some partial data is available from the response, but the server hasn't finished with its response":
		} else if (xmlHttp.readyState == 4) {
			// When success call the onSuccess handler:
			if (xmlHttp.status == 200) {
				onSuccess(xmlHttp.responseText, callBacks);
			// When access denied call the onFailure handler:
			} else if (xmlHttp.status == 403) {
				onFailure("AJAX error: Access denied to page!");
			// When page not found call the onFailure handler:
			} else if (xmlHttp.status == 404) {
				onFailure("AJAX error: Page '" + url + "' not found!");
			// When unknown error call the onFailure handler:
			} else if (xmlHttp.status != 0) {
				onFailure("AJAX error: Unknown error " + xmlHttp.status + "!");
			}
		}
	};
	
	// Send the request (with params when using the "POST"-method):
	this.xmlHttp.send((this.method == "POST") ? params : null);
};

/**
 * Abort the request.
 **/
Ajax.prototype.abort = function() {
	try {
		this.xmlHttp.abort();
	} catch(e) {
		alert("Exception on aborting ajax request: " + e.message);
	}
};
