//*****************************************************************************
// Script library, provides tools used by other scripts.
//*****************************************************************************

//=============================================================================
// This sets DOM constants for any browser (such as IE) that doesn't already
// reflect them.
//=============================================================================
if (document.ELEMENT_NODE == null) {
	document.ELEMENT_NODE = 1;
	document.TEXT_NODE    = 3;
}

//=============================================================================
// Define the XHR object.
//
// This object is basically a wrapper for the XMLHttpRequest object. It is
// designed to simplify the process of making asynchronous HTTP requests.
//
// Example usage (simple GET reqeust):
//
//   // Create a new request.
//   var myXhr = new XHR();
//
//   // Set the URL and include a query string.
//   myXhr.url = "myPage.asp";
//   myXhr.queryString = "name1=value1&name2=value2";
//
//   // Set up the callback functions.
//   myXhr.successCallback = function (xhrObj) {
//
//     // Show the response text.
//     alert(xhrObj.responseText)
//   }
//   myXhr.failureCallback = function (xhrObj) {
//
//     // Show the status code and description.
//     alert(xhrObj.status + " " + xhrObj.statusText);
//   }
//
//   // Make the request.
//   myXhr.get();
//
// Example usage (POST request with data, expecting an XML response):
//
//   // Create a new request.
//   var myXhr = new XHR();
//
//   // Set the URL.
//   myXhr.url = "myPage.asp";
//
//   // Set up the POST data, note that we must specify the Content-Type
//   // request header.
//   var myData = "name1=value1&name2=value2";
//   myXhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
//
//   // Set up the callback functions.
//   myXhr.successCallback = function (xhrObj) {
//
//     // Display the tag name of the root node.
//     var xmlDoc = xhrObj.responseXML;
//     alert(xmlDoc.documentElement.nodeName);
//   }
//   myXhr.failureCallback = function (xhrObj) {
//
//     // Show the status code and description.
//     alert(xhrObj.status + " " + xhrObj.statusText);
//   }
//
//   // Make the request.
//   myXhr.post(myData);
//=============================================================================

// Constants for request ready states.
XHR.prototype.READY_STATE_UNINITIALIZED = 0;
XHR.prototype.READY_STATE_LOADING       = 1;
XHR.prototype.READY_STATE_LOADED        = 2;
XHR.prototype.READY_STATE_INTERACTIVE   = 3;
XHR.prototype.READY_STATE_COMPLETED     = 4;

// Public properties.
XHR.prototype.successCallback = null;
XHR.prototype.failureCallback = null;
XHR.prototype.url             = null;
XHR.prototype.queryString     = null;
XHR.prototype.username        = null;
XHR.prototype.password        = null;
XHR.prototype.requestHeaders  = [];

XHR.prototype.status          = null;
XHR.prototype.statusText      = null;
XHR.prototype.responseXML     = null;
XHR.prototype.responseText    = null;

//-----------------------------------------------------------------------------
// Constructor.
//-----------------------------------------------------------------------------
function XHR() {

	// Create an XMLHttpRequest object.
	this.xmlHttpRequest = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();

	// ------------------------------------------------------------------------
	// Internal function to make the actual request.
	// ------------------------------------------------------------------------
	this.initiateRequest = function (method, data) {

		// For IE, abort any current request.
		if (domUtils.isIE)
			this.abort();

		// Clear all response fields.
		this.status       = null;
		this.statusText   = null;
		this.responseText = null;
		this.responseXML  = null;

		// Set up the callback functions.
		var refObj = this;
		this.xmlHttpRequest.onreadystatechange = function () {
			try {
				refObj.readyState = refObj.xmlHttpRequest.readyState
				if (refObj.readyState == XHR.prototype.READY_STATE_COMPLETED) {
					refObj.status       = refObj.xmlHttpRequest.status;
					refObj.statusText   = refObj.xmlHttpRequest.statusText;
					refObj.responseText = refObj.xmlHttpRequest.responseText;
					refObj.responseXML  = refObj.xmlHttpRequest.responseXML;

					// Make the appropriate callback depending on whether the
					// call was successful or not.
					if (refObj.status == 200) {
						if (refObj.successCallback != null)
							refObj.successCallback(refObj);
					}
					else {
						if (refObj.failureCallback != null)
							refObj.failureCallback(refObj);
					}
				}
			}
			catch (ex) {}
		}

		// Initialize the request.
		var url = this.url;
		if (this.queryString != null)
			url = url + "?" + this.queryString;
		this.xmlHttpRequest.open(method, url, true, this.username, this.password);

		// Set request headers (this must be done after the request is opened).
		for (var i = 0; i < this.requestHeaders.length; i++) {
			var pair = this.requestHeaders[i].split("\n");
			this.xmlHttpRequest.setRequestHeader(pair[0], pair[1]);
		}

		// Start the request, passing any POST data.
		this.xmlHttpRequest.send(data);
	}
}

//-----------------------------------------------------------------------------
// Public methods.
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Aborts a request.
//-----------------------------------------------------------------------------
XHR.prototype.abort = function () {

	this.xmlHttpRequest.abort();
}

//-----------------------------------------------------------------------------
// Sets a request header.
//-----------------------------------------------------------------------------
XHR.prototype.setRequestHeader = function (name, value) {

	// If the header name already exists, replace the value.
	for (var i = 0; i < this.requestHeaders.length; i++) {
		var pair = this.requestHeaders[i].split("\n");
		if (pair[0].toLowerCase() == name.toLowerCase()) {
			this.requestHeaders[i] = name + "\n" + value;
			return;
		}
	}

	// Otherwise, add it as a new item.
	var n = this.requestHeaders.length;
	this.requestHeaders.push(name + "\n" + value);
}

//-----------------------------------------------------------------------------
// Clears all request headers.
//-----------------------------------------------------------------------------
XHR.prototype.clearRequestHeaders = function () {

	this.requestHeaders = [];
}

//-----------------------------------------------------------------------------
// Performs a GET request.
//-----------------------------------------------------------------------------
XHR.prototype.get = function () {

	this.initiateRequest("GET", null);
}

//-----------------------------------------------------------------------------
// Performs a POST request.
//-----------------------------------------------------------------------------
XHR.prototype.post = function (data) {

	this.initiateRequest("POST", data);
}

//-----------------------------------------------------------------------------
// Returns the value of the specified response header.
//-----------------------------------------------------------------------------
XHR.prototype.getResponseHeader = function (name) {

	return this.xmlHttpRequest.getResponseHeader(name);
}

//-----------------------------------------------------------------------------
// Returns a string containing all the response headers.
//-----------------------------------------------------------------------------
XHR.prototype.getAllResponseHeaders = function () {

	return this.xmlHttpRequest.getAllResponseHeaders();
}

//=============================================================================
// Module: domUtils
//
// Provides properties and methods useful for manipulating the DOM.
//=============================================================================
var domUtils = function () {

	// Browser flags.
	var isIE     = (document.all && window.innerWidth == null ? true : false);
	var isOpera  = (window.opera ? true : false);
	var isSafari = (navigator.userAgent.indexOf("Safari") >= 0 ? true : false);

	// Document ready flag.
	var isReady = false;

	// Array for onready event handlers.
	var readyList = [];

	//-------------------------------------------------------------------------
	// Document ready event handler.
	//-------------------------------------------------------------------------
	function readyExecute(e) {

		// Mark the document as ready.
		isReady = true;

		// Call every function on the waiting list.
		for (var i = 0; i < readyList.length; i++)
			readyList[i](e);

		// Clear the list.
		readyList = [];
	}

	//=========================================================================
	// Initialization code.
	//=========================================================================

	// Set up an event handler to fire once the document is ready.
	//
	// When possible, use the DOMContentLoaded event (or the IE equivalent)
	// instead of the window onload event to avoid waiting for external objects
	// to load.
	if (document.addEventListener != null)
		document.addEventListener("DOMContentLoaded", readyExecute, false);
	else
		if (isIE) {
			document.write("<script id=\"IEWindowOnload\" defer src=\"javascript:void(0)\"><\/script>");
			var script = document.getElementById("IEWindowOnload");
			script.onreadystatechange = function () {
				if (this.readyState == "complete")
					readyExecute(window.event);
			}
		}
		else
			window.onload = readyExecute;

	//=========================================================================
	// Public properties and methods.
	//=========================================================================
	return {

		//---------------------------------------------------------------------
		// Browser flags.
		//---------------------------------------------------------------------
		isIE     : isIE,
		isOpera  : isOpera,
		isSafari : isSafari,

		//---------------------------------------------------------------------
		// Adds the specified function to the list of onready event handlers.
		//---------------------------------------------------------------------
		onready : function (fn) {

			// If the ready event has fired, execute the function immediately.
			// Otherwise, add it to the waiting list.
			if (isReady)
				fn.call();
			else
				readyList[readyList.length] = fn;
		},

		//---------------------------------------------------------------------
		// Returns true if the given element has the specified class.
		//---------------------------------------------------------------------
		hasClass : function (el, name) {

			if (el.className != null) {
				var list = el.className.split(" ");
				for (var i = 0; i < list.length; i++)
					if (list[i] == name)
						return true;
			}
			return false;
		},

		//---------------------------------------------------------------------
		// Adds the specified class to the given element.
		//---------------------------------------------------------------------
		addClass : function (el, name) {
	
			if (!this.hasClass(el, name))
				el.className += (el.className.length > 0 ? " " : "") + name;
		},

		//---------------------------------------------------------------------
		// Removes the specified class from the given element.
		//---------------------------------------------------------------------
		removeClass : function (el, name) {

			if (el.className == null)
				return;

			var newList = [];
;
			var curList = el.className.split(" ");
			for (var i = 0; i < curList.length; i++)
				if (curList[i] != name)
					newList.push(curList[i]);
			el.className = newList.join(" ");
		},

		//---------------------------------------------------------------------
		// Returns true if the first node contains the second.
		//---------------------------------------------------------------------
		contains : function (nodeA, nodeB) {

			// Return false if either node is null.
			if (nodeA == null || nodeB == null)
				return false;

			// Return true if nodes A and B are the same node.
			if (nodeA == nodeB)
				return true;

			// Return true if node B is a descendant of node A.
			while (nodeB.parentNode)
				if ((nodeB = nodeB.parentNode) == nodeA)
					return true;
			return false;
		},

		//---------------------------------------------------------------------
		// Returns the coordinates of the given element relative to the page.
		//---------------------------------------------------------------------
		offset : function (el) {

			// Use the bounding client rectangle, if available.
			if (el.getBoundingClientRect != null) {
				var rect = el.getBoundingClientRect();

				// This will adjust the coordinates for any offset in IE.
				var dx = 0, dy = 0;
				if (domUtils.isIE) {
					if (window.XMLHttpRequest == null) {

						// For IE6.
						dx = 2;
						dy = 2;
					}
					else {

						// For IE7+.
						var docRect = document.documentElement.getBoundingClientRect();
						dx += Math.max(docRect.left, 0);
						dy += Math.max(docRect.top,  0);
					}
				}

				// Adjust for any page scrolling and return the coordinates.
				return {
					x : rect.left - dx + (document.body.scrollLeft || document.documentElement.scrollLeft),
					y : rect.top  - dy + (document.body.scrollTop  || document.documentElement.scrollTop )
				};
			}

			// Otherwise, add up the left and top offsets of all positioned
			// containing elements.
			var x = 0, y = 0;
			while (el != null) {
				x += el.offsetLeft;
				y += el.offsetTop;
				el = el.offsetParent;
			}

			// Return the coordinates.
			return {
				x : x,
				y : y
			};
		},

		//---------------------------------------------------------------------
		// Sets a cookie.
		//---------------------------------------------------------------------
		setCookie : function (name, value, expires) {

			document.cookie = name + "=" + escape(value) + (expires != null ? "; expires=" + expires.toGMTString() : "");
		},

		//---------------------------------------------------------------------
		// Returns the value of the named cookie.
		//---------------------------------------------------------------------
		getCookie : function (name) {

			var start = document.cookie.indexOf(name + "=")
			if (start != -1) {
				start = start + name.length + 1;
				var end = document.cookie.indexOf(";", start);
				if (end == -1)
					end = document.cookie.length;
				return unescape(document.cookie.substring(start, end))
		    } 
		    return "";
		}
	}
}();


