/** 
 * HTTP.js: A module of AJAX useful functions
 * ver: 1.0
 * author : jdi
 * dt: 2007/10/15
 * prereq: This module does not require other modules.
**/

var HTTP;
if (!HTTP) 
	HTTP = {};	// create namespace
else
	throw new Error("HTTP already exists!");
	
// This is a list of XMLHttpRequest-creation factory functions to try
HTTP._factories = [
	function() { return new XMLHttpRequest(); },
	function() {return new ActiveXObject("Msxml2.XMLHTTP"); },
	function() {return new ActiveXObject("Microsoft.XMLHTTP"); },
];

// When we find a factory that works, store it here.
HTTP._factory = null;

// Create and return a new XMLHttpRequest object
//
// The first time we call, try the list of factory functions until we find 
// one that returns a non-null value and does not throw an exception. Once
// we find a working factory, remember it for later use.
HTTP.newRequest = function () {
	if (HTTP._factory != null) return HTTP._factory();
	
	for (var i=0; i<HTTP._factories.length; i++) {
		try {
			var factory = HTTP._factories[i];
			var request = factory();
			if (request != null) {
				HTTP._factory = factory;
				return request;
			}
		}
		catch(e) { continue; }
	}
	
	// if we get here, none of the factory candidates succeded,
	// so throw an exeption now and for all future calls
	HTTP._factory = function() {
		throw new Error("XMLHttpRequest not supported!");
	}
	HTTP._factory();	// throw an error
}

// use XMLHttpRequest to fetch the contents of the specified URL using a GET request.
// When the response arrives, pass it (as plain text) to the specified callback function.
// This function does not block and has no return value
HTTP.getText = function(url, callback) {
	var request = HTTP.newRequest();
	request.onreadystatechange = function() {
		if (request.readyState == 4 && request.status == 200)
			callback(request.responseText);
	}
	request.open("GET", url);
	request.send(null);
}

// use XMLHttpRequest to fetch the contents of the specified URL using a GET request.
// When the response arrives, pass it (as XML) to the specified callback function.
// This function does not block and has no return value
HTTP.getXML = function(url, callback) {
	var request = HTTP.newRequest();
	request.onreadystatechange = function() {
		if (request.readyState == 4 && request.status == 200)
			callback(request.responseXML);
	}
	request.open("GET", url);
	request.send(null);
}

// looks at the content-type header to determine the form of the response,
// and returns the proper response, i.e. plain text, XML document object, 
// JSON object.
HTTP._getResponse = function(request) {
	// check the content type returned by the server
	switch (request.getResponseHeader("Content-Type")) {
		case "text/xml" :
			// if it is an XML document, use the parsed Document object.
			return request.responseXML;
			
		case "text/json" :
		case "text/javascript" :
		case "application/javascript" :
		case "application/x-javascript" :
			// if the response is js code or a JSON encoded value,
			// call eval() on the text to "parse" it to Javascript value.
			// Note: only do this if the js code comes from a trusted server!
			return eval(request.responseText);
			
		default:
			// otherwise, treat the response as plain text and return as a string.
			return request.responseText;
	}
}

HTTP.encodeFormData = function(data) {
	var pairs = [];
	var regexp = /%20/g;  // a req expr to match an encoded space
	
	for (var name in data) {
		var value = data[name].toString();
		// create a name/value pair, but encode name and value first
		// The global function encodeURIComponent does almost what we want,
		// but it encodes spaces as %20 instead of as "+". We have to fix
		// that with String.replace()
		var pair = encodeURIComponent(name).replace(regexp, "+") + '=' + 
			encodeURIComponent(value).replace(regexp, "+");
		pairs.push(pair);
	}
	
	// concatenate all the name/value pairs, separating them with &
	return pairs.join("&");
}

HTTP.get = function(url, callback, options) {
	var request = HTTP.newRequest();
	var  n = 0;
	var timer;
	if (options.timeout)
		timer = setTimeout( function() {
								request.abort();
								if (options.timeoutHandler)
									options.timeoutHandler(url);
							},
							options.timeout);

	request.onreadystatechange = function() {
		if (request.readyState == 4) {
			if (timer) clearTimeout(timer);
			if (request.status == 200)
				callback(HTTP._getResponse(request));			
			else {
				if (options.errorHandler)
					options.errorHandler(request.status, request.statusText);
				else
					callback(null);
			}
		}
		else if (options.progressHandler) {
			options.progressHandler(++n);
		}
	}
	
	var target = url;
	if (options.parameters)
		target += "?" + HTTP.encodeFormData(options.parameters);
	request.open("GET", target);
	request.send(null);
}

function $(Id)
{
	return document.getElementById(Id);
}

