// Debugging //

var debugLogBox;
function debugLog(message) {
	if (!debugLogBox) {
		debugLogBox = document.getElementById("debug_log");
	}
	if (debugLogBox) {
		var date = String(new Date());
		var ary = date.match(/^(.*) \w{3}[-+]\d{4}/);
		if (ary) {
			date = ary[1];
		}
		message = "[" + date + "] " + message;
		var item = document.createElement("div");
		showTextIn(item, message);
		debugLogBox.insertBefore(item, debugLogBox.firstChild);
	}
}

// Basic wrapping //

function _getElementById(id) {
	return document.all[id];
}
if (!document.getElementById) {
	document.getElementById = _getElementById;
}

function showTextIn(element, text) {
	if (typeof element == "string") {
		element = document.getElementById(element);
	}
	while (element.lastChild) {
		element.removeChild(element.lastChild);
	}
	element.appendChild(document.createTextNode(text));
}

function showTextInWithHint(element, text) {
	if (typeof element == "string") {
		element = document.getElementById(element);
	}
	showTextIn(element, text);
	element.title = text;
}

function show(element) {
	if (typeof element == "string") {
		element = document.getElementById(element);
	}
	element.style.display = "";
}

function hide(element) {
	if (typeof element == "string") {
		element = document.getElementById(element);
	}
	element.style.display = "none";
}

function focus(element) {
	if (typeof element == "string") {
		element = document.getElementById(element);
	}
	element.focus();
}

// Event handling wrapper //

function addListener(element, event, handler) {
	debugLog("addListener(" + element + ", " + event + ", " + handler + ")");
	if (element.addEventListener) {
		element.addEventListener(event, handler, false);
	} else {
		element.attachEvent("on" + event, handler);
	}
}

function removeListener(element, event, handler) {
	debugLog("removeListener(" + element + ", " + event + ", " + handler + ")");
	if (element.removeEventListener) {
		element.removeEventListener(event, handler, false);
	} else {
		element.detachEvent("on" + event, handler);
	}
}

// XMLHttpRequest wrapper //

var webRequestQueue = new Array();
var webRequestRunning = new Array();
var webRequestMaxRunning = 1;
var lastQebRequestRunningCount = 0;

function webRequestSorter(a, b) {
	if (a.priority > b.priority)
		return -1;
	if (a.priority < b.priority)
		return 1;
	return 0;
}

function checkWebRequestQueue() {
	// Remove items which have finished.
	for (var i = 0; i < webRequestRunning.length; i++) {
		if (webRequestRunning[i].state == "finished") {
			webRequestRunning.splice(i, 1);
			i--;
		}
	}
	
	if ((webRequestRunning.length < webRequestMaxRunning) && (webRequestQueue.length > 0)) {
		webRequestQueue.sort(webRequestSorter);
		var req = webRequestQueue.shift();
		webRequestRunning.push(req);
		req._load();
	}
	if (webRequestRunning.length != lastQebRequestRunningCount) {
		debugLog("WebRequest: now " + webRequestRunning.length + " request" +
				(webRequestRunning.length == 1 ? "" : "s") + " running");
	}
	lastQebRequestRunningCount = webRequestRunning.length;
}
setInterval("checkWebRequestQueue()", 5000);

if (typeof XMLHttpRequest == "undefined") {
	XMLHttpRequest = function XMLHttpRequest() {
		return new ActiveXObject('Microsoft.XMLHTTP');
	};
}

function WebRequest(method, url, onload, onerror) {
	this.req = new XMLHttpRequest();
	this.method = method;
	this.url = url;
	this.priority = 0;
	this.userOnload = onload;
	this.userOnerror = onerror;
	this.state = "";
}
WebRequest.proxyURL = "/temp/proxy.pl?url=";

WebRequest.prototype._setState = function(state) {
	this.state = state;
	debugLog("WebRequest(" + this.url + ", " + this.priority + ") -> " + state);
	if (state == "finished") {
		setInterval("checkWebRequestQueue()", 100);
	}
}

WebRequest.prototype.load = function(postdata) {
	this.postdata = postdata;
	this._setState("wait");
	webRequestQueue.push(this);
}

WebRequest.prototype._load = function() {
	this.state = "running";
	this._setState("running");
	
	// Proxy non-local requests.
	var url = this.url;
	if (/^\w+:/.test(this.url)) {
		url = WebRequest.proxyURL + escape(this.url);
	}
	if (/\?/.test(url)) {
		url += "&dummy=" + Number(new Date());
	} else {
		url += "?dummy=" + Number(new Date());
	}
	debugLog("WebRequest(" + this.url + ", " + this.priority + ") " + this.method + " " + url);
	
	try {
		this.req.open(this.method, url);
	} catch (ex) {
		this._setState("finished");
		debugLog("WebRequest(" + this.url + ", " + this.priority + ") failed (open exception: " + ex + ")");
		if (this.userOnerror) {
			this.userOnerror(null, this, ex);
		}
		return;
	}
	
	var self = this;
	
	this.onload = function(e) {
			self._setState("finished");
			if (/^2/.test(self.req.status)) {
				if (self.userOnload) {
					self.userOnload(e, self, self.req.responseText);
				}
			} else {
				debugLog("WebRequest(" + this.url + ", " + this.priority + ") failed (HTTP status: " + + self.req.status + ")");
				if (self.userOnerror) {
					self.userOnerror(e, self);
				}
			}
		};
	
	this.onerror = function(e) {
			self._setState("finished");
			debugLog("WebRequest(" + this.url + ", " + this.priority + ") failed (onerror)");
			if (self.userOnerror) {
				self.userOnerror(e, self);
			}
		};
	
	try {
		this.req.onload  = function(e) { self.onload(e)  };
		this.req.onerror = function(e) { self.onerror(e) };
	} catch(ex) {
		this.req.onreadystatechange = function() {
			if (self.req.readyState == 4) {
				if (self.req.status == 200) {
					self.onload(null);
				} else {
					self.onerror(null);
				}
			}
		};
	}
	
	try {
		this.req.send(this.postdata || null);
	} catch (ex) {
		this._setState("finished");
		debugLog("WebRequest(" + this.url + ", " + this.priority + ") failed (send exception: " + ex + ")");
		if (this.userOnerror) {
			this.userOnerror(null, this, ex);
		}
	}
}

