//****************************************************************************************
//
//	http_manager.js
//
//	Object to support AJAX based server interaction
//
//	Depends On:
//				
//
//	Copyright: 	David Horne, Tuross Technologies Australia P/L
//				dkhorne@bigpond.net.au
//
//****************************************************************************************


//****************************************************************************************
//	Callback Support
//****************************************************************************************

	var cbUninitialised = 0;		//The object has been created but the open() method hasn't been called. 
	var cbLoading = 1;				//The open() method has been called but the request hasn't been sent. 
	var cbLoaded = 2;				//The request has been sent. 
	var cbInteractive = 3;			//A partial response has been received. 
	var cbComplete = 4;				//All data has been received and the connection has been closed. 

	var HTTPStatus_Lookup = 
		{ 
			100: "Continue",
			101: "Switching Protocols",
			200: "OK",
			201: "Created",
			202: "Accepted",
			203: "Non-Authoritative Information",
			204: "No Content",
			205: "Reset Content",
			206: "Partial Content",
			300: "Multiple Choices",
			301: "Moved Permanently",
			302: "Found",
			303: "See Other",
			304: "Not Modified",
			305: "Use Proxy",
			306: "(Unused)",
			307: "Temporary Redirect",
			400: "Bad Request",
			401: "Unauthorized",
			402: "Payment Required",
			403: "Forbidden",
			404: "Not Found",
			405: "Method Not Allowed",
			406: "Not Acceptable",
			407: "Proxy Authentication Required",
			408: "Request Timeout",
			409: "Conflict",
			410: "Gone",
			411: "Length Required",
			412: "Precondition Failed",
			413: "Request Entity Too Large",
			414: "Request-URI Too Long",
			415: "Unsupported Media Type",
			416: "Requested Range Not Satisfiable",
			417: "Expectation Failed",
			500: "Internal Server Error",
			501: "Not Implemented",
			502: "Bad Gateway",
			503: "Service Unavailable",
			504: "Gateway Timeout",
			505: "HTTP Version Not Supported"
		}

//****************************************************************************************
//
//	Basic single shot HTTP Object
//
//****************************************************************************************
	function HTTPRequest(action, targetURL, onChangeState, callback) {
//*********************************
//	Properties
		this.action = action;										//	Unique Request ID
		this.targetURL = targetURL + "?Action=" + action;			//	URL for request
		this.method = "Get";										//	Default method
		this.contentType = "application/x-www-form-urlencoded";		//	Default Content Type
		this.callback = callback;									//	Post request processing object
		this.processed = false;										//	Processed flag
		this.timeoutID = null;										//	ID for timeout timer

		this.httpObj = HTTPRequestObj(onChangeState);				//	Actual HTTP object
//		this.httpObj.request = this;								//	Link to this request for use at callback.

		this.execute = HTTPRequest_Execute;							//	Executes teh request
		this.abort = HTTPRequest_Abort;								//	Aborts request
		
		this.response = HTTPRequest_Response;						//	Returns the HTTP response/header
		this.xml = HTTPRequest_XML;									//	Returns the HTTP response xml

		this.result = HTTPRequest_Result;							//	Returns the Result object of this request
	}

//****************************************************************************************
//	Create the HTTP Request object
//****************************************************************************************
	function HTTPRequestObj(changeState) {
		var versions = new Array("MSXML2.XMLHttp.5.0", "MSXML2.XMLHttp.4.0","MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp","Microsoft.XMLHttp");
		var httpObj = null;
		
		if (window.XMLHttpRequest) {
			httpObj = new XMLHttpRequest();
			if (httpObj.overrideMimeType)
                httpObj.overrideMimeType('text/xml');
		} else {
			if (window.ActiveXObject) {
				for (var i = 0; i < versions.length; i++) {
					try {
						httpObj = new ActiveXObject(versions[i]);
					} catch (err) {
					}
				}
			}
		}
		if (httpObj != null) {
			httpObj.onreadystatechange = changeState;
			return httpObj;
		} else {
			alert("This browser does not support XMLHTTP.");
			return null;
		}
	}

//****************************************************************************************
//	Executes a request
//****************************************************************************************
	function HTTPRequest_Execute(query, dataType, data, async) {
		if (this.httpObj == null) {
			alert("HTTP Communications failed.");
			return;
		}
		
		var url = this.targetURL + (query != null ? "&" + query : "");
		data = (data != null ? data : "");
		async = (async != null ? async : false);
		
		switch (this.method.toLowerCase()) {
			case "get":
				this.httpObj.open("GET", url, async);
				this.httpObj.setRequestHeader("Content-Type", this.contentType);
				this.httpObj.setRequestHeader("DatasetType", dataType);
				this.httpObj.send("");
				break;

			case "post":
				this.httpObj.open("POST", url, async);
				this.httpObj.setRequestHeader("Content-Type", this.contentType);
				this.httpObj.setRequestHeader("DatasetType", dataType);
				this.httpObj.setRequestHeader("Content-Length", data.toString().length);
				this.httpObj.setRequestHeader("Connection", "close");
				this.httpObj.send(data);
				break;
		}

		if (!async) {
			if (!this.processed)
				HTTPManager.process(this.httpObj.status, this);
				
			return this.result();
		} else {
			return null;
		}
	}

//****************************************************************************************
//	Call for aborting request.
//****************************************************************************************
	function HTTPRequest_Abort() {
		alert("Callback Request aborted.");
		this.httpObj.abort();
	}
	

//****************************************************************************************
//	Return the required HTTP object response.
//****************************************************************************************
	function HTTPRequest_Response(targetHeader) {
		try {
			if (targetHeader != null) {
				var reHeader = new RegExp(targetHeader + "\s*: \s*([^\n]*?)\n", "gim");
				var headers = this.httpObj.getAllResponseHeaders().replace(/\r/gim, "");

				var strValue = "";
				var match;
				while ((match = reHeader.exec(headers)) != null)
					strValue += (strValue != "" ? "\n" : "") + match[1];
					
				return strValue;
			} else {
				return this.httpObj.responseText;
			}
		}
		catch(e) {}
	}

//****************************************************************************************
//	Return the required HTTP object response as XML.
//****************************************************************************************
	function HTTPRequest_XML() {
		return this.httpObj.responseXML;
	}

//****************************************************************************************
//	Return the result as an object
//****************************************************************************************
	function HTTPRequest_Result() {
		return	{
					action:		this.action,
					ok:			((this.httpObj.readyState == cbComplete) && (this.response("Result").toLowerCase() == "ok")),
					result:		this.response("Result"),
					count:		this.response("Count"),
					error:		this.response("Error"),
					warning:	this.response("Warning"),
					info:		this.response("Info"),
					debug:		(message.debugOn ? this.response("Debug") : ""),
					data:		this.response()
				};
	}

	
//****************************************************************************************
//
//	Basic multi shot Callback Object
//
//****************************************************************************************

	var HTTPManager = new function() {
		return {
			requests:		new Array(),
			add:			HTTPManager_Add,										//	Creates a new request object.
			changeState:	HTTPManager_ChangeState,								//	Manage HTTP change state calls.
			process: 		HTTPManager_Process										//	Processes request and calls Callback.
		}
	}();

//****************************************************************************************
//	Sets up a template for this request
//****************************************************************************************
	function HTTPManager_Add(action, targetURL, callback) {
		var request = new HTTPRequest(action, targetURL, HTTPManager.changeState, callback);
		this.requests.push(request);
		return request;
	}
	
//****************************************************************************************
//	Called by the request to manage change state
//****************************************************************************************
	function HTTPManager_ChangeState() {
		for (var i = 0; i < HTTPManager.requests.length; i++) {
		    var request = HTTPManager.requests[i];
			if ((request != null) && (request instanceof HTTPRequest)) {
				if ((!request.processed) && (request.httpObj.readyState == cbComplete)) {
					HTTPManager.process(request.httpObj.status, request);
					request.processed = true;
				}
				if (request.processed)
					HTTPManager.requests.splice(i, 1);
			}
		}
	}

//****************************************************************************************
//	Callback function to process post request data
//****************************************************************************************
	function HTTPManager_Process(status, request) {
		var result = request.result();

		if (status != 200) 
			message.raise("HTTPRequest", "Error", HTTPStatus_Lookup[status], result.debug + "\r\n" + result.response, false);

		switch (result.result.toLowerCase()) {
			case "session_timeout":
				message.raise("HTTPRequest", "Info", "Your server session has timed out. You will need to login again.", false); 
				break;

			case "database_connection":
				message.raise("HTTPRequest", "Error", "Could not find remote database server. Please logout and login again.", false); 
				break;
		}

		if (request.callback != null)
			request.callback(result);
	}
