/*
Author: Andrew Mace
Date: 2005/04/27
Copyright: 2005 Pyramis Studios, Inc.
Description: Generic code to handle multiple simultaneous XMLHttpRequests.
Usage:
	- Use encodeURIComponent to format GET query string
	- Send request to xml file or script
	- Script returns content type text/xml
	xhr_load('script.pl','GET','key=val&key2=val2');
*/

var xhr_serial = true; // whether to allow serial or parallel connects
var xhr_reqs = []; // XMLHttpRequest queue; entries removed when request completed
var xhr_info_ids = ["status", "status2"]; // element ids to use to display status messages; append others if necessary
var xhr_info_id = xhr_info_ids[0]; // the status element id to use by default - displays request status/messages/feedback
var xhr_info_msg = '';

function xhr_error(r)
{ // handle the request error
	if(xhr_error_custom != null) {
		if(xhr_error_custom(r)) { // if returns true, don't follow normal processing
			return;
		}
	}
	if(r == -1) { // XMLHttpRequest not supported
		// should probably redirect
	} else {
		xhr_info(r.status); // update status message
	}
}

function xhr_info(s, id)
{ // update the status on the display
	if(id == null) id = xhr_info_id;
	var el = document.getElementById(id); 
	if(el == null) return;
	if(xhr_info_msg.length) {
		el.innerHTML = xhr_info_msg;
		return;
	}
	if(isNaN(s)) {
		el.innerHTML = s;
	} else {
		if(s == 0) { // sending request
			el.innerHTML = "Sending request&#8230;";
		} else if(s == 200) {
			el.innerHTML = "&nbsp;";
		} else if(s != 200 && s < 500) { // 1xx/2xx/3xx; 4xx/client errors
		 	el.innerHTML = "Error";
		} else if(s >= 500) { // 5xx/server errors
		 	el.innerHTML = "Error";
		} else {
			el.innerHTML = "&nbsp;";
		}
	}
}

function xhr_process(r)
{ // r is an XMLHttpRequest object
	var done = false;
	if(typeof(xhr_process_custom) == 'function') {
		if(xhr_process_custom(r)) { // if returns true, don't follow normal processing
			done = true;
		}
	}
	if(!done) {
		var doc = r.responseXML;
		var nodes = doc.lastChild.childNodes;
		var id;
		for(var i = 0; i < nodes.length; i++) {
			if(nodes[i].nodeName == 'ht') { // replace the contents of the element with specified id
				var el = document.getElementById(nodes[i].getAttribute('id'));
				if(el != null) el.innerHTML = nodes[i].firstChild.nodeValue;
			}
		}
	}
	xhr_info_id = xhr_info_ids[0];
	xhr_info_msg = '';
}

function xhr_load(url, method, data) 
{
	if(xhr_serial) xhr_abort_last();
	var req;
    if(window.XMLHttpRequest) { // branch for native XMLHttpRequest object
        req = new XMLHttpRequest();
    } else if(window.ActiveXObject) { // branch for IE/Windows ActiveX version
       	req = new ActiveXObject("Microsoft.XMLHTTP");
    }
	if(req) {
		xhr_info(0); // Update status message
		xhr_reqs.push(req);
		if(method.charAt(0) == 'G') {
			var d = new Date(); // to make each request unique/prevent caching
			url += "?" + data + "&_t=" + d.getTime();
			data = null;
		}
		req.onreadystatechange = xhr_status;	
		req.open(method, url, true);
		req.send(data);
	} else {
		xhr_error(-1); // XMLHttpRequest method is not supported
	}
}

function xhr_status() 
{ // handle status changes for extant XMLHttpRequest
	for(var k = xhr_reqs.length - 1; k >= 0; k--) {
		switch(xhr_reqs[k].readyState) {
		 case 0: // uninitialized
		 case 1: // loading
		 case 2: // loaded
		 case 3: // interactive
			break;
		 case 4: // complete, only if req shows "loaded"
			if(xhr_reqs[k].status == 200) xhr_process(xhr_reqs[k]);
			else xhr_error(xhr_reqs[k]);
			if(navigator.userAgent.toLowerCase().indexOf("msie") >= 0 && !delete(xhr_reqs[k])) xhr_reqs[k] = null;
			xhr_reqs.splice(k, 1); // remove the completed request
			break;
		}
    }
}


function xhr_abort_last()
{ // kill the last request - useful if we want serial communication only
	var n = xhr_reqs.length;
	if(n) {
		xhr_reqs[n - 1].abort();
		xhr_reqs.splice(n - 1, 1); // remove the aborted request
	}
}
