// Lewjax 0.2
// - A Simple Ajax Framework
// Dependencies: lewjax.util.js

var scriptroot = 'http://'+document.location.host+'/lewlibs/lewjax/';


function lewjax() {
	this.handler='echo';
	this.request = false;
	this.enctype = 'xml';
	this.debug = false;
	this.callback = function() { };
	this.onstart = function() { };
	this.oncomplete = function() { };
	this.abortrequest = false;
	this.busy = false;
	this.sendqueue=null;
	this.processqueue=null;
	var req;
    if(window.XMLHttpRequest) {
    	try {
			this.request = new XMLHttpRequest();
        } catch(e) {
			this.request = false;
        }
    } else if(window.ActiveXObject) {
       	try {
        	this.request = new ActiveXObject("Msxml2.XMLHTTP");
      	} catch(e) {
        	try {
          		this.request = new ActiveXObject("Microsoft.XMLHTTP");
        	} catch(e) {
          		this.request = false;
        	}
		}
    }
}

lewjax.prototype.send = function (data) {
	if (arguments.length!=2 && this.sendqueue) {
		// eek - theres already something queued. we have a problem.
		clearTimeout(this.sendqueue);
	}
	if (!this.busy) {
		var firstpass=true;
		if (arguments.length==2) {// cope with queued request
			data = arguments[1];
			firstpass=false
		}
		this.abortrequest = false;
		this.busy=true;

		var req = this.request;
		if (req.readyState != 4 && req.readyState != 0) {
			if (firstpass && !this.sendqueue) {// this shouldn't happen often.. let's wait a mo and try again.
				this.sendqueue = setTimeout(associateObjWithTimer(this,'send',data),500);
			}
			return false;
		}
		if(req) {
			this.onstart();
			switch (this.enctype) {
				case 'xml':
					var xmldecl = '<?xml version="1.0" encoding="ISO-8859-1" ?>';
					if (this.debug)
						alert('Sending:\r\n'+xmldecl+'<request namespace="'+xmlescape(this.handler)+'">'+data+'</request>');
					data = 'xml='+escape(xmldecl+'<request namespace="'+xmlescape(this.handler)+'">'+data+'</request>');
					break;
				case 'json':
					if (this.debug)
						alert('namespace='+escape(this.handler)+'&json='+escape(data.toJSONString()));
					data = 'namespace='+escape(this.handler)+'&json='+escape(data.toJSONString());
					break;
			}
			req.open("POST", scriptroot+"widgets/director.php", true);
			req.onreadystatechange = associateObjWithEvent(this,'docallback',null);
			req.setRequestHeader('Content-type','application/x-www-form-urlencoded');
			req.setRequestHeader('Content-length',data.length);
			req.send(data);
		}
		else {
			alert('HttpRequest object unavailable');
			return false;
		}
	}
	else {
		this.abort();
		this.sendqueue = setTimeout(associateObjWithTimer(this,'send',data), 200);
	}
}


lewjax.prototype.docallback = function() {
	if (!arguments[2] && this.processqueue) {
		// eek - theres already something queued. we have a problem.
		clearTimeout(this.processqueue);
	}
	if (this.request.readyState == 4 && !this.abortrequest) {
		try {
			var status = this.request.status;
		}
		catch (e) {
			// hmm. lets have a snooze and try once more, just in case.
			if (this.processqueue)
				clearTimeout(this.processqueue);
			this.processqueue=setTimeout(associateObjWithTimer(this,'docallback',null),200);
			return false;
		}
		if (status == 200) {
			this.oncomplete();
			if (this.debug)
				alert('Response:\r\n'+this.request.responseText);
			switch (this.enctype) {
				case 'xml':
					var xml = this.request.responseXML;
					if (xml == null) {
						// seems this only happens when theres a request.abort()?
						return false;
					}
					var i=0;
					if (xml.nodeType == 9) {
						for (i=0; i<xml.childNodes.length;i++) {
							if (xml.childNodes[i].nodeType == 1) {
								xml = xml.childNodes[i];
								break;
							}
						}
					}
					if (xml.tagName != 'response') {
						if (this.debug)
							alert('There was a problem(1) retrieving the data:\r\n'+this.request.responseText);
						return false;
					}
					if (this.debug)
						alert('Status: '+xml.attributes.getNamedItem('status').value);
					if (!xml.attributes.getNamedItem('status')) {
						if (this.debug)
							alert('There was a problem(2) retrieving the data:\r\n'+this.request.responseText);
						return false;
					}
					if (xml.attributes.getNamedItem('status').value == 'error') {
						alert(xml.childNodes[0].childNodes[0].nodeValue);
					}
					else {
						if (this.debug)
							alert('Passing \''+xml.tagName+'\' node to callback function');
						this.callback(xml);
					}
					break;
				case 'json':
					var json = eval('('+this.request.responseText+');');
					alert(json);
					if (json.k != 'response') {
						if (this.debug)
							alert('There was a problem(1) retrieving the data:\r\n'+this.request.responseText);
						return false;
					}
					if (this.debug)
						alert('Status: '+json.p.status);
					if (!json.p.status) {
						if (this.debug)
							alert('There was a problem(2) retrieving the data:\r\n'+this.request.responseText);
						return false;
					}
					if (json.p.status == 'error') {
						alert(json.v);
					}
					else {
						if (this.debug)
							alert('Passing \''+json.k+'\' node to callback function');
						this.callback(json);
					}
					break;
			}
		} else {
			if (this.processqueue)
				clearTimeout(this.processqueue);
			this.processqueue=setTimeout(associateObjWithTimer(this,'docallback',true),200);	
			return false;
		}
		this.busy=false;
	}
}

lewjax.prototype.abort = function () {
	this.abortrequest = true;
	if (this.request) {
		this.request.onreadystatechange = function () {};
		this.request.abort();
		this.clearqueue();
		this.busy = false;
	}
}

lewjax.prototype.clearqueue = function () {
	if (this.sendqueue)
		clearTimeout(this.sendqueue);
	if (this.processqueue)
		clearTimeout(this.processqueue);
}