//ajaxShell.js
//(c) John Bell
//Generic ajax request shell
//I still hate that name.

function AjaxShell(){
	//AjaxShell constructor
	//Do some browser checking to get the right version of XMLHttpRequest
	this.fail = false;
	try {
		this.port=new ActiveXObject("Msxml2.XMLHTTP");
	} catch (e) {
		try {
			this.port=new ActiveXObject("Microsoft.XMLHTTP");
		} catch (oc) {
			this.port=null;
		}
	}
	if(!this.port && typeof XMLHttpRequest != "undefined") this.port = new XMLHttpRequest();
	//If none of these options work, Ajax is not available in this browser
	if(!this.port){
		this.fail = true;
		return false;
	}
	
	//Assuming everything has worked, set up the rest of the object
	this.statusDiv = document.getElementById('AjaxStatusTag');
	//this.pendingRequests = 0;			//Number of ajax requests currently being processed
	this.queue = new Array();			//Queue of ajax requests (since you can't do more than one at a time.)
	this.active = false;				//Is there currently a request pending?
}

AjaxShell.prototype.post = function(phpName, phpData, callBack){
	//phpName is the name of the PHP function you wish to call
	//	it is in the format of pageName::functionName
	//phpData is an array with the data you wish to send
	//callBack is the function (The function itself, not the name!) you wish to call after data is loaded
	
	//scope check
	if(!defined(this.post)){
		ajax.post.apply(ajax, arguments);
		return;
	}
	
	//this.addRequest();
	var ajaxHandler = phpName.split("::");
	var postData = "";
	for(var phpField in phpData){
		var dataString = phpData[phpField].toString()
		postData += phpField + "=" + encodeURIComponent(dataString) + "&";
		//postData += phpField + "=" + dataString +"&";
	}
	var date = new Date();
	if(ajaxHandler.length > 1) postData += "handler=" + ajaxHandler[1] 
	postData += "&time=" + date.getTime();
	
	//Add the new request to the queue
	this.queue.push({method: 'post', url: ajaxHandler[0], data: postData, callBack: callBack});
	this.doQuery();
//	this.port.open("POST", ajaxHandler[0], true);
//	this.port.setRequestHeader("Method", "POST " + ajaxHandler[0] + " HTTP/1.1");
//	this.port.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
//	this.port.onreadystatechange = function(){
//		if(ajax.port.readyState != 4) return;
//		ajax.removeRequest();
//		callBack(ajax.port.responseText);
//	}
//	this.port.send(postData);
}

AjaxShell.prototype.doQuery = function(){
	//Runs a query from the front of the query queue
	//scope check
	if(!defined(this.doQuery)){
		ajax.doQuery.apply(ajax, arguments);
		return;
	}
	
	//If the port is busy, don't try to use it.
	if(this.active == true){
		if(this.retry == null) this.retry = setInterval(ajax.doQuery, 100);
		return;
	}
	//Run the first request in the queue
	if(this.queue.length > 0){
		this.active = true;
		setTimeout(ajax.toggleStatusDiv, 10);
		var request = this.queue.shift();
		if(request.method == 'post'){
			this.port.open("POST", request.url, true);
			this.port.setRequestHeader("Method", "POST " + request.url + " HTTP/1.1");
			this.port.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
			this.port.onreadystatechange = function(){
				if(ajax.port.readyState != 4) return;
				request.callBack(ajax.port.responseText);
				ajax.active = false;
				if(ajax.queue.length == 0) clearInterval(this.retry);
				setTimeout(ajax.toggleStatusDiv, 10);
			}	
			this.port.send(request.data);
		} else {
			this.port.open("GET", request.url, true);
			this.port.onreadystatechange = function(){
				if(ajax.port.readyState != 4) return;
				request.callBack(ajax.port.responseText);
				ajax.active = false;
				if(ajax.queue.length > 0) setTimeout(ajax.doQuery, 100);	
				else ajax.active = false;
				setTimeout(ajax.toggleStatusDiv, 10);
			}
			this.port.send(null);
		}
	}	
}

AjaxShell.prototype.get = function(phpName, phpData, callBack){
	//Same as the post function, only with get

	//scope check
	if(!defined(this.get)){
		ajax.get.apply(ajax, arguments);
		return;
	}

	//this.addRequest();
	var ajaxHandler = phpName.split("::");
	ajaxHandler[0] += "?";
	for(var phpField in phpData){
		var dataString = phpData[phpField].toString()
		ajaxHandler[0] += phpField + "=" + encodeURIComponent(dataString) + "&";
	}
	var date = new Date();
	if(ajaxHandler.length > 1) ajaxHandler[0] += "handler=" + ajaxHandler[1] 
	ajaxHandler[0] += "&time=" + date.getTime();
	this.queue.push({method: 'get', url: ajaxHandler[0], callBack: callBack});
	this.doQuery();
//	this.port.open("GET", ajaxHandler[0], true);
//	this.port.onreadystatechange = function(){
//		if(ajax.port.readyState != 4) return;
//		ajax.removeRequest();
//		callBack(ajax.port.responseText);
//	}
//	this.port.send(null);
}

AjaxShell.prototype.toggleStatusDiv = function(){
	//Toggles the statusDiv, if it exists
	if(document.getElementById('AjaxStatusTag')){
		if(ajax.active == false) document.getElementById('AjaxStatusTag').style.display = "none";
		else document.getElementById('AjaxStatusTag').style.display = "block";
		//document.getElementById('AjaxStatusTag').style.display = "block";
	}
}
//AjaxShell.prototype.addRequest = function(){
////Adds a request to the queue
//	this.pendingRequests++;
//	setTimeout(ajax.toggleStatusDiv, 10);
//}
//
//AjaxShell.prototype.removeRequest = function(){
//	this.pendingRequests--;
//	setTimeout(ajax.toggleStatusDiv, 10);
//}

AjaxShell.prototype.parseForm = function(){
	//parses the passed form into an associative array and posts it
	//This requires that the form has a hidden field 'target' with the path to the PHP handler
	var formData = {};
	
	for(var i=0; i<this.length; i++){
		if(this[i].name != 'target'){
			//alert(this[i].type+' '+this[i].name);
			switch(this[i].type){
				case 'password':	formData[this[i].name] = this[i].value; break;
				case 'input':		formData[this[i].name] = this[i].value;	break;
				case 'hidden':		formData[this[i].name] = this[i].value;	break;
				case 'textarea':	formData[this[i].name] = this[i].value;	break;
				case 'text':		formData[this[i].name] = this[i].value; break;
				case 'select-one':	if(this[i].selectedIndex > -1) formData[this[i].name] = this[i][this[i].selectedIndex].value;
									else formData[this[i].name] = '';
									break;
				case 'checkbox':	if(!defined(formData[this[i].name])) formData[this[i].name] = new Array();
									if(this[i].checked == true){
										formData[this[i].name].push(this[i].value);
									}
									break;
				case 'radio':		if(this[i].checked == true) formData[this[i].name] = this[i].value; break;
			}
		}
	}
	
	for(var field in formData) if(defined(formData[field])!='string') formData[field] = formData[field].join('|');
	//for(var field in formData) alert(field+': '+formData[field]);
	
	
	var responseHandler = function(ajaxData){
		//This is left generic, all JS should be returned in the ajax response
		eval(ajaxData);
	}
	
	ajax.post(this.target.value, formData, responseHandler);
	 
	return false;
}

ajax = new AjaxShell();