/*
 * Javascript pseudo-class to build assynchronous HTTP requests to webservers.
 *
 * You must inform the HTTP request Method and URL on AjaxObject's constructor,
 * and, optionally, you can inform your Javascript function witch will receive
 * and process the webserver response (callback function) and an array of 
 * arguments that will be assigned to each function parameter.
 *
 * This callback function is necessary also if you (whe think so) intend to 
 * process the server's response to add funcionality to your application.
 * Without it, your script will not perceive anything absolutely.
 * It accept parameters that you have to pass as an array, but simply consider
 * as parameter on your callback function.
 * 
 * You can, optionally, pass request values (as key/value pairs) or request form 
 * input objects that will be encoded and can be had access by the webserver.
 * 
 * Also it's possible to define a function witch will handle the XMLHttpRequest
 * object's onreadystatechange event and another function witch will be called
 * when something gone wrong, for examplo, request for Page Not Found (404).
 * 
 * To send an Ajax request, call load() method on your AjaxObject object.
 *
 * Usage examples:
 * <code>
 *	getObj = new AjaxObject("GET", "ajaxtest.php"); // request for some URL on GET method - try it with POST too
 *	getObj.setCallBackFunction(callback); // defining the callback function
 *	getObj.setLoadingFunction(loading); // setting loading function
 *	getObj.addRequestValue('foo', 'bar'); // some request parameter
 * 	getObj.addRequestObject(document.forms['aForm'].elements['anElement']); // other request parameter
 * 	getObj.addAllRequestObjects(document.forms['anotherForm']); // pass all enabled form elements to request
 * 	getObj.load(); // sending the assychronous request
 * </code>
 * 
 * @author Jose Berardo <berardo@especializa.com.br>
 * @author Eduardo Lundgren <braeker@gmail.com>
 * @version 1.0
 * @copyleft Jose Berardo - Especializa Treinamentos - www.especializa.com.br
 * @copyleft Eduardo Lundgren - Especializa Treinamentos - www.especializa.com.br
 */
// class AjaxObject {
var AjaxObject;
AjaxObject.INVALID_REQUEST_OBJECT = 1;

/*
 * AjaxObject Constructor
 * 
 * @param method Request method (GET or POST)
 * @param url url requested on load() function
 * @param xmlResponse enables xml format to response
 * @param callback function inform your script function whitch will receive the server response
 * @see load()
 */
function AjaxObject(method, url) {
	// setting attributes
	this.method = method;
	this.url = url;
	this.requestObjects = new Array();
	this.requestValues = new Array();
	this.responseFormat = (AjaxObject.arguments[2]) ? "xml" : "text";

	// setting methods
	this.addRequestObject = addRequestObject;
	this.addRequestValue = addRequestValue;
	this.setCallBackFunction = setCallBackFunction;
	this.setLoadingFunction = setLoadingFunction;
	this.setExceptionFunction = setExceptionFunction;
	this.buildRequestString = buildRequestString;
	this.addAllRequestObjects = addAllRequestObjects;
	this.load = load;

	// setting callback function
	this.callBackFunction = AjaxObject.arguments[3];
	this.callBackArguments = AjaxObject.arguments[4];
}

/*
 * AjaxObject's method that adds an input object to pass in the request
 * 
 * @param requestObject
 */
function addRequestObject(requestObject) {
	this.requestObjects[this.requestObjects.length] = requestObject;
}

/*
 * AjaxObject's method that adds a key-value pair to pass in the request as a parameter
 * 
 * @param requestObject
 */
function addRequestValue(requestKey, requestValue) {
	this.requestValues[this.requestValues.length] = new Array(requestKey,
			requestValue);
}

/*
 * AjaxObject's method that sets the Javascript's function
 * assigned to be onreadstatechange event listener
 * 
 * @param callBackFunction
 * @param arrayArguments Some arguments used by the method
 */
function setCallBackFunction(callBackFunction) {
	this.callBackFunction = callBackFunction;
	this.callBackArguments = setCallBackFunction.arguments[1];
}

/*
 * AjaxObject's method that sets the Javascript's function
 * called within the load() to change loading status
 * 
 * @param loadingFunction
 * @param loadingFunction Your loading function
 */
function setLoadingFunction(loadingFunction) {
	this.loadingFunction = loadingFunction;
}

/*
 * AjaxObject's method that sets the Javascript's function
 * called within the load() when someting gone wrong
 * 
 * @param exceptionFunction
 * @param exceptionFunction Your exception function
 */
function setExceptionFunction(exceptionFunction) {
	this.exceptionFunction = exceptionFunction;
}

/*
 * AjaxObject's method that processes requestObjects and requestValues
 * arrays and builds the return string used on GET's URL or POST's request parameters
 * 
 * @return the new URL string
 */
function buildRequestString() {
	var regexArray = /.*\[\]/;

	returnString = ((this.url.indexOf('?') > 0) ? "&" : "?") + "requestTime="
			+ new Date().getTime();
	for (x = 0; x < this.requestValues.length; x++) {
		returnString += '&' + this.requestValues[x][0] + '='
				+ encodeURIComponent(this.requestValues[x][1]);
	}
	for (x = 0; x < this.requestObjects.length; x++) {
		try {
			if (this.requestObjects[x].type == 'select-multiple') {

				for ( var i = 0; i < this.requestObjects[x].options.length; i++) {
					if (this.requestObjects[x].options[i].selected == true) {
						newName = regexArray.test(this.requestObjects[x].name) ? this.requestObjects[x].name
								: this.requestObjects[x].name + '[]';
						returnString += '&'
								+ newName
								+ '='
								+ encodeURIComponent(this.requestObjects[x].options[i].value);
					}
				}
			} else {
				returnString += '&' + this.requestObjects[x].name + '='
						+ encodeURIComponent(this.requestObjects[x].value);
			}
		} catch (e) {
			if (this.exceptionFunction) {
				for (x in e) {
					alert(x)
				}
				this
						.exceptionFunction(
								AjaxObject.INVALID_REQUEST_OBJECT,
								'The object ' + x + ' passed is not a valid form input object!');
			}
		}
	}
	return returnString;
}

/*
 * AjaxObject's method that adds all fields of a form passed as parameter
 * 
 * @param aForm HTML form object
 */
function addAllRequestObjects(aForm) {
	for (x = 0; x < aForm.elements.length; x++) {
		if (!aForm.elements[x].disabled) {
			if ((aForm.elements[x].type != 'checkbox' && aForm.elements[x].type != 'radio')
					|| aForm.elements[x].checked) {
				this.addRequestObject(aForm.elements[x]);
			}
		}
	}
}

/**
 * AjaxObject's method that loads the new thread of XMLHttpRequest
 */
function load() {
	var xmlHttpRequest = new XmlHttpRequestObject(this);
	returnString = this.buildRequestString();
	if (this.method.toUpperCase() == "POST") {
		xmlHttpRequest.thread.open("POST", this.url, true);
		xmlHttpRequest.thread.setRequestHeader('Content-Type',
				'application/x-www-form-urlencoded');
		xmlHttpRequest.thread.setRequestHeader('Content-Length',
				returnString.length);
	} else if (this.method.toUpperCase() == "GET") {
		this.url += this.buildRequestString();
		xmlHttpRequest.thread.open("GET", this.url, true);
	}
	xmlHttpRequest.thread.send(returnString);

	xmlHttpRequest.thread.onreadystatechange = function() {
		if (xmlHttpRequest.thread.readyState == 0) {
			state = 'uninitialized'
		}
		if (xmlHttpRequest.thread.readyState == 1) {
			state = 'loading'
		}
		if (xmlHttpRequest.thread.readyState == 2) {
			state = 'loaded'
		}
		if (xmlHttpRequest.thread.readyState == 3) {
			state = 'interactive'
		}
		if (xmlHttpRequest.thread.readyState == 4) {
			state = 'complete'
		}
		if (xmlHttpRequest.ajaxObject.loadingFunction)
			xmlHttpRequest.ajaxObject.loadingFunction(state);

		if (xmlHttpRequest.thread.readyState == 4) {
			if (xmlHttpRequest.thread.status == 200) {
				params = "";
				if (xmlHttpRequest.ajaxObject.callBackArguments) {
					for (x = 0; x < xmlHttpRequest.ajaxObject.callBackArguments.length; x++) {
						params += ", xmlHttpRequest.ajaxObject.callBackArguments["
								+ x + "]";
					}
				}
				if (xmlHttpRequest.ajaxObject.callBackFunction) {
					if (xmlHttpRequest.ajaxObject.responseFormat == 'text')
						eval("xmlHttpRequest.ajaxObject.callBackFunction( unescape(xmlHttpRequest.thread.responseText)"
								+ params + " )");
					else {
						eval("xmlHttpRequest.ajaxObject.callBackFunction( unescape(xmlHttpRequest.thread.responseXML)"
								+ params + " )");
					}
				}
			} else {
				if (xmlHttpRequest.ajaxObject.exceptionFunction) {
					eval("xmlHttpRequest.ajaxObject.exceptionFunction(xmlHttpRequest.thread.status, xmlHttpRequest.thread.statusText)");
				}
			}
		}

	}
}

// }

/**
 * Private class to help AjaxObject in its job
 *
 */
// private class XmlHttpRequestObject {
/*
 * XmlHttpRequestObject Constructor
 * 
 * @param callBackFunction function loaded when response status code is 200 - OK
 * @param callBackArguments array of arguments passed to the callback function
 * @param loadingFunction function called on every change of request state
 */
function XmlHttpRequestObject(ajaxObject) {
	try {
		this.thread = new XMLHttpRequest();
	} catch (e) {
		try {
			this.thread = new ActiveXObject("Microsoft.XMLHTTP");
		} catch (e) {
		}
	}

	this.ajaxObject = ajaxObject;
}

//}
