/** Net - XMLHTTP Interface - bfults@gmail.com - 2006-01-25                 **
 ** Code licensed under Creative Commons Attribution-ShareAlike License     **
 ** http://creativecommons.org/licenses/by-sa/2.5/                          **/

/** Net class constructor
 ** Usage:
 **	Net.get("foo.xml", fnWhenDone); or
 **	Net.post("foo.php", "x=1&y=2", fnWhenDone);
 **/
Net = function()
{
	this.Request = Net._createRequestObject() || null;
	if (!this.Request)
	{
		return null;
	}
	return this;
}

/** Net.get(sURL, fnCallback[, fnError]) -- make an HTTP GET request
 ** Returns true on successful request dispatch, false on error.
 ** fnCallback will be called with a single argument (the XMLHTTP object)
 ** Optional fnError: call upon erroneous HTTP status code or timeout.
 **/
Net.get = function(sURL, fnCallback, fnError)
{
	if (!fnError)
	{
		fnError = Net._fnErrorDefault;
	}
	try {
		var N = new Net();
		N.Request.open("GET", sURL, true);
		N._setCallback(fnCallback, fnError);
		N.Request.send('');
	}
	catch (e) { fnError("initialization"); }
	return true;
}

/** Net.post(sURL, sVars, fnCallback[, fnError]) -- make an HTTP POST request
 ** Returns true on successful request dispatch, false on error.
 ** fnCallback will be called with a single argument (the XMLHTTP object)
 ** Optional fnError: call upon erroneous HTTP status code or timeout.
 **/
Net.post = function(sURL, sVars, fnCallback, fnError)
{
	if (!fnError)
	{
		fnError = Net._fnErrorDefault;
	}
	try {
		var N = new Net();
		N.Request.open("POST", sURL, true);
		N._setCallback(fnCallback, fnError);
		N.Request.setRequestHeader("Method", "POST "+sURL+" HTTP/1.1");
		N.Request.setRequestHeader("Content-Type",
			"application/x-www-form-urlencoded");
		N.Request.send(sVars);
	}
	catch (e) { fnError("initialization"); }
	return true;
}

// a default error function showing the structure (does nothing)
Net._fnErrorDefault = function(sType, Request)
{
	if (sType == "timeout")
	{
		// it was a timeout
	}
	else if (sType == "initialization")
	{
		// initialization error
	}
	else
	{
		// other error (HTTP status, etc.)
	}
}

/** Net._setCallback(fnCallback, fnError)
 ** Attaches (and wraps) a request object with a user-defined callback.
 ** Optional fnError: call upon erroneous HTTP status code or timeout.
 **/
Net.prototype._setCallback = function(fnCallback, fnError)
{
	this.Request.onreadystatechange = (function (oNet)
	{
		return function()
		{
			if (oNet.Request.readyState == 4)
			{
				window.clearTimeout(oNet.timeout);

				if (oNet.Request.status === undefined
					|| oNet.Request.status === 0
					|| (oNet.Request.status >= 200 && oNet.Request.status < 300)
					|| oNet.Request.status == 304)
				{
					fnCallback(oNet.Request);
				}
				else
				{
					fnError("other", oNet.Request);
				}
			}
		}
	})(this);

	this.timeout = window.setTimeout(function() { fnError("timeout"); }, 10000);
}

/** Net._createRequestObject()
 ** Creates and returns an XMLHTTP element or null on failure.
 **/
Net._createRequestObject = function()
{
	var xmlhttp;
	try { xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); }
	catch (e) { try { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); }
	catch (e) { try { xmlhttp = new XMLHttpRequest(); }
	catch (e) { xmlhttp = false; }}}
	if (!xmlhttp) return null;
	return xmlhttp;
}
