//##########################################################################################
//                                                                                         #
//  powerHTTP(tm) 2.0                                                                      #
//                                                                                         #
//  Copyright (C) 2006 - 2007 Reza Akhavan, Exodus Web, Inc.                               #
//  Website: www.exodusweb.com / www.weblegs.net                                           #
//                                                                                         #
//  This program is free software; you can redistribute it and/or modify it under the      #
//  terms of the GNU General Public License as published by the Free Software              #
//  Foundation; either version 2 of the License, or (at your option) any later version.    #
//                                                                                         #
//  This program is distributed in the hope that it will be useful, but WITHOUT ANY        #
//  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A        #
//  PARTICULAR PURPOSE. See the GNU General Public License for more details.               #
//                                                                                         #
//  You should have received a copy of the GNU General Public License along with this      #
//  program; if not, write to the Free Software Foundation, Inc., 59 Temple Place,         #
//  Suite 330, Boston, MA 02111-1307 USA                                                   #
//                                                                                         #
//##########################################################################################
//  NOTES / UPDATES / MISC                                                                 #
//##########################################################################################
//                                                                                         #
//   Created: January 2006                                                                 #
//   Last Updated: June 2007                                                               #
//   Author: Reza Akhavan - Exodus Web, Inc.                                               #
//   Email: reza@exodusweb.com                                                             #
//                                                                                         #
//   -----------------------------------------------------------------------------------   #
//   CHANGE LOG ------------------------------------------------------------------------   #
//   -----------------------------------------------------------------------------------   #
//   v2.0 - 2007-06-16                                                                     #
//    > Large overhaul, almost a re-write. Previous versions don't support asynchronus     #
//      requests due to a huge oversight on my part. Its all over now! We can now take     #
//      over the world easier. The approach in 2.0 is 100% different. We have dumped the   #
//      request queue, and also dropped some old status handler methods, you also initiate #
//      state handlers different. We've also added an anonymous error function so you can  #
//      have custom error call-back functions for each request.                            #
//                                                                                         #
//   v1.4 - 2007-01-14                                                                     #
//    > We now initialize a global "engine" simply by including powerHTTP inside the       #
//      <head> tag of the (X)HTML document. This will allow for "application wide"         #
//      functionalities without having scope problems.                                     #
//                                                                                         #
//    > We have also implemented a "request queue". Now you don't have to use the          #
//      "is_busy()" method to control queuing your requests.                               # 
//                                                                                         #
//   v1.3 - 2006-08-13                                                                     #
//    > Removed the check for HTTP status 200 for the response & response_xml method.      #
//      You may now get the response content when the server throws an error.              #
//                                                                                         #
//   v1.2 - 2006-08-12                                                                     #
//    > Modified encode_form_data to support radio buttons.                                #
//                                                                                         #
//   v1.2 - 2006-08-01                                                                     #
//    > Added the is_busy function.                                                        #
//                                                                                         #
//   v1.1 - 2006-07-19                                                                     #
//    > Added encode_form_data function for GET & POST requests.                           #
//                                                                                         #
//   v1.0 - 2006-03-18                                                                     #
//    > Added descriptive comments.                                                        #
//    > Implemented 'throw error' where appropriate.                                       #
//                                                                                         #
//##########################################################################################

//create the _powerHTTP function (this is our "XHR factory")
function _powerHTTP() {
	//initialize (W3C) XMLHttpRequest object
	if(window.XMLHttpRequest) {
		return new XMLHttpRequest();
	}
	else {
		var MsXMLEngines = [
			'Msxml2.XMLHTTP.5.0',
			'Msxml2.XMLHTTP.4.0',
			'Msxml2.XMLHTTP.3.0',
			'Msxml2.XMLHTTP',
			'Microsoft.XMLHTTP'
		];
		for(var i = 0 ; i < MsXMLEngines.length ; i++) {
			try{
				return new ActiveXObject(MsXMLEngines[i]);
			}
			catch(e) {
				//do nothing
			}
		}
	}
	throw new Error("Could not create an XMLHttpRequest object.");
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -//

function powerHTTP() {
	//An ajaxid appends a semi-unique id to a GET request
	//to help stop chaching when its not appropriate.
	this._use_ajaxid = true;
	
	//This trigger will tell the response_xml() function
	//to remove white space from our xml response. This helps
	//to make parsing the xml response easier across browsers.
	this._strip_xml_whitespace = true;
	
	//This trigger allows the user to control if a request is 
	//made asynchronous or not.
	this._is_async = true;
	
	//This trigger lets us know if our object is busy
	this._is_busy = false;
	
	//Here we create a (multi-dimensional) stack which gets populated
	//using the set_request_header() function. After the request()
	//function opens a 'GET' request we loop through the elements and
	//set a request headers for each element. [["name","value"]]
	this._request_headers = [];
	
	//Here we create a JSON style object to store data
	this._data = {};
	
	//Here we create an xmlHttp object for this instance.
	this._xmlHttp = _powerHTTP();
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -//

//create the request (GET) method
powerHTTP.prototype.get = function(URL) {
	var instance = this;
	
	//use ajax_id?
	if(this._use_ajaxid == true) {
		var ajaxid = new Date().getTime();
		if(URL.indexOf("?") > 0) {
			URL = URL +"&ajaxid="+ ajaxid;
		}
		else {
			URL = URL +"?ajaxid="+ ajaxid;
		}
	}
	
	//setup the state handler
	this._xmlHttp.onreadystatechange = function() {
		switch(instance._xmlHttp.readyState) {
			case 1:
				instance._is_busy = true;
				instance.loading();
				break;
			case 2:
				instance._is_busy = true;
				instance.loaded();
				break;
			case 3:
				instance._is_busy = true;
				instance.interactive();
				break;
			case 4:
				instance._is_busy = false;
				
				//return the response or bail out
				try {
					instance.complete({
						"status": instance._xmlHttp.status,
						"statusText": instance._xmlHttp.statusText,
						"text": instance._xmlHttp.responseText,
						"xml": instance._xmlHttp.responseXML
					});
				}
				catch(this_error) {
					instance.error(this_error);
				}
				
				//save us from memory leaks
				instance.onreadystatechange = null;
				break;
		}
	};
	
	//open this request
	this._xmlHttp.open("GET", URL, this._is_async);
	
	//set specified request headers
	for(var i = 0 ; i < this._request_headers.length ; i++) {
		this._xmlHttp.setRequestHeader(this._request_headers[i][0], this._request_headers[i][1]);
	}
	
	//send request
	this._xmlHttp.send(null);
};

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -//

//create the request (POST) method
powerHTTP.prototype.post = function(URL, FormData) {
	var instance = this;
	
	//use ajax_id?
	if(this._use_ajaxid == true) {
		var ajaxid = new Date().getTime();
		if(URL.indexOf("?") > 0) {
			URL = URL + "&ajaxid="+ ajaxid;
		}
		else {
			URL = URL + "?ajaxid="+ ajaxid;
		}
	}
	
	instance._data.url = URL;
	
	//setup the state handler
	this._xmlHttp.onreadystatechange = function() {
		switch(instance._xmlHttp.readyState) {
			case 1:
				instance._is_busy = true;
				instance.loading();
				break;
			case 2:
				instance._is_busy = true;
				instance.loaded();
				break;
			case 3:
				instance._is_busy = true;
				instance.interactive();
				break;
			case 4:
				instance._is_busy = false;
				
				//return the response or bail out
				try {
					instance.complete({
						"status": instance._xmlHttp.status,
						"statusText": instance._xmlHttp.statusText,
						"text": instance._xmlHttp.responseText,
						"xml": instance._xmlHttp.responseXML
					});
				}
				catch(this_error) {
					instance.error(this_error);
				}
				
				//save us from memory leaks
				instance.onreadystatechange = null;
				break;
		}
	};
	
	//open this request
	this._xmlHttp.open("POST", URL, this._is_async);
	
	//set specified request headers
	for(var i = 0 ; i < this._request_headers.length ; i++) {
		this._xmlHttp.setRequestHeader(this._request_headers[i][0], this._request_headers[i][1]);
	}
	
	//set the content type request header for POSTing
	this._xmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded;");
	
	//send request
	this._xmlHttp.send(FormData);
};

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -//

//create the post_multipart post method
powerHTTP.prototype.post_multipart = function(URL, PostData, StateHandler) {
	//********************* build me
};

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -//

//create empty state handler functions
powerHTTP.prototype.loading = function() {};
powerHTTP.prototype.loaded = function() {};
powerHTTP.prototype.interactive = function() {};
powerHTTP.prototype.complete = function(response) {};
powerHTTP.prototype.error = function(error) {};

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -//

//extend the xmlHttp abort method
powerHTTP.prototype.abort = function() {
	this._xmlHttp.abort();
};

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -//

powerHTTP.prototype.get_response_header = function(alt) {
	var instance = this;
	
	if(instance._xmlHttp.readyState == 4) {
		if(alt != undefined) {
			return instance._xmlHttp.getResponseHeader(alt)
		}
		return instance._xmlHttp.getAllResponseHeaders();
	}
	else {
		return undefined;
	}
};

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -//

powerHTTP.prototype.was_successful = function() {
	var instance = this;
	if(instance._xmlHttp.readyState == 4) {
			return instance._xmlHttp.status == 200 ? true : false;
	}
	else {
		return false;
	}
};

//$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ //
//$ HELPER FUNCTIONS  $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ //
//$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ //

//create the encode_form_data method
powerHTTP.prototype.encode_form_data = function(formRef) {
	var formParameters = new Array();
	for(var i = 0 ; i < formRef.elements.length ; i++) {
		var addParameter = false;
		if(formRef.elements[i].type == "radio") {
			if(formRef.elements[i].checked) {
				addParameter = true;
			}
		}
		if(formRef.elements[i].type == "checkbox") {
			if(formRef.elements[i].checked) {
				addParameter = true;
			}
		}
		else if(formRef.elements[i].type == "submit" || formRef.elements[i].type == "button") {
			addParameter = false;
		}
		else {
			addParameter = true;
		}
		
		if(addParameter) {
			var thisNameValue = "";
			thisNameValue = encodeURIComponent(formRef.elements[i].name);
			thisNameValue += "=";
			thisNameValue += encodeURIComponent(formRef.elements[i].value);
			formParameters.push(thisNameValue);
		}
	}
	return formParameters.join("&");
};

//$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ //

//remove_xml_whitespace function(s)
function remove_xml_whitespace(xml_node) {
	delete_these_nodes = Array();
	locate_whitespace(xml_node, 0);
	for(i = delete_these_nodes.length-1 ; i >= 0 ; i--) {
		delete_these_nodes[i].parentNode.removeChild(delete_these_nodes[i])
	}
}
function locate_whitespace(xml_node, node_index) {
	for(i = 0 ; i < xml_node.childNodes.length ; i++) {
		if(xml_node.childNodes[i].nodeType == 3 && is_whitespace(xml_node.childNodes[i])) {
			delete_these_nodes[delete_these_nodes.length] = xml_node.childNodes[i];
		}
		if(xml_node.childNodes[i].hasChildNodes()) {
			locate_whitespace(xml_node.childNodes[i], i);
		}
	}
	i = node_index;
	xml_node = xml_node.parentNode;
}
function is_whitespace(node) {
	return !(/[^\t\n\r ]/.test(node.data));
}

//##########################################################################################
//                                                                                         #
//  powerHTTP(tm) 2.0                                                                      #
//  Copyright (C) 2006 - 2007 Reza Akhavan, Exodus Web, Inc.                               #
//  Website: www.exodusweb.com / www.weblegs.net                                           #
//                                                                                         #
//##########################################################################################