function parseForm(form){
	if (typeof form == 'string') form = get(form);
	var str = "";
	var elements = form.elements;
	var names = new Array();
	var values = new Array();
	var index = 0;

	var getValue = function(e){
		if (e.type=="text" || e.type=="hidden" ||
		e.type=="password" || e.type=="textarea" ||
		e.type=="select-one") return e.value;
		else if (e.type=="checkbox" && e.checked) return e.value;
		else if(e.type=="radio" && e.checked) return e.value;
		else return false;
	}

	for (var i=0; i<elements.length; i++){//for each element
		e = elements[i];
		if (!e.name || getValue(e)===false) continue;
		names[index] = e.name;
		val = getValue(e);
		val = val.replace(/\&/g, "%26");
		values[index++] = val;
	}

	for (var i=0; i<names.length; i++){
		str = str + "&" + names[i] + "=" + values[i];
	}

	return str.substring(1, str.length);
}


//driver for the Ajax class.
function doAjax(functionName, params, statusDiv, waitMsg, completeMsg){
	req = new Ajax(functionName, params, statusDiv, waitMsg, completeMsg);
	req.enqueue();
}


/********************** AJAX CLASS ******************/
ajaxQueue = new Array();
function Ajax(functionName, params, statusDiv, waitMsg, completeMsg){
	/****** use can set these *********/
	this.handleResponse = null;
	this.onComplete = function(){};
	this.onSend = function(){};

	/******** constructor *************/
	this.id = functionName;
	this.http = this.getXMLHttpRequest();
	this.params = encodeURI(params + "&doAjax=" + functionName);
	this.statusDiv = (typeof this.statusDiv == 'string') ? get(this.statusDiv) : this.statusDiv;
	this.cover = null;
	this.waitMsg = waitMsg;
	this.completeMsg = completeMsg;

	//set up our http req.
	this.http.open('POST', window.location.href, true);
	this.http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
	this.http.setRequestHeader("Content-length", this.params.length);
	this.http.setRequestHeader("Connection", "close");
	var me = this;
	this.http.onreadystatechange = function(){
		if (me.http.readyState == 4) {
			if (me.cover) me.cover.kill();
			var ajaxResponse = me.http.responseText;
			if(get('AjaxDebug')) get('AjaxDebug').value = ajaxResponse;
			if (me.handleResponse) me.handleResponse(ajaxResponse);
			else me.handleXMLResponse(ajaxResponse);
			if (get('AjaxWorking') && get('AjaxComplete') && (me.waitMsg || me.completeMsg)){
				var aw = get('AjaxWorking');
				var ac = get('AjaxComplete');
				ac.innerHTML = me.completeMsg;
				if(me.completeMsg == '') Fade(aw, .3, 0, function(){aw.style.display="none";}); // fade working if no complete
				else { // else hide working, show complete for a second, then fade
					aw.style.display="none";
					Fade(ac, -.1, 0, function(){ac.style.display='none'});
				}
			}
			me.onComplete();
			ajaxQueue.shift();
			if (ajaxQueue.length>0) ajaxQueue[0].send();
		}
	}
}

//enqueues the ajax
Ajax.prototype.enqueue = function(){
	var i;	//find and replace
	for (var i=0; i<ajaxQueue.length; i++){
		if (i==0) { if (ajaxQueue[0].id==0 && this.id==0) return; }
		else if(ajaxQueue[i].id==this.id){
			ajaxQueue[i] = this;
			return;
	}}
	ajaxQueue.push(this); //unique ajax gets pushed onto queue
	if (ajaxQueue.length==1) ajaxQueue[0].send(); //start the queue if needed
}
//sends the ajax away.
Ajax.prototype.send = function(){
	if (this.statusDiv) {
		this.cover = new Cover(this.statusDiv);
		this.cover.show();
	}
	if (get('AjaxWorking') && get('AjaxComplete') && (this.waitMsg || this.completeMsg)){
		var aw = get('AjaxWorking');
		var ac = get('AjaxComplete');
		aw.innerHTML = this.waitMsg;
		aw.style.display = "block";
		aw.style.opacity = 0;
		Fade(aw, .15, .8);
	}
	this.http.send(this.params);
	this.onSend();
}
//gets an XMLRequest object.
Ajax.prototype.getXMLHttpRequest = function(){
	var temp;if (window.XMLHttpRequest){//Mozilla, Safari,...
		temp = new XMLHttpRequest();
		if (temp.overrideMimeType) temp.overrideMimeType('text/xml');
	}else if (window.ActiveXObject){//IE
		try {temp = new ActiveXObject("Msxml2.XMLHTTP");} catch (e) {
			try {temp = new ActiveXObject("Microsoft.XMLHTTP");} catch (e){}
		}
	};return temp
}
//interprets the XML commands from server.
Ajax.prototype.handleXMLResponse = function(strXML){
	//pieces together a multipart XMLNode and returns the string.
	var getNodeString = function(XMLNode){
		var str = "";if (XMLNode.getAttribute("multipart")=="true"){
			parts = XMLNode.getElementsByTagName("part");
			for(var i=0;i<parts.length;i++){
				str += parts[i].firstChild.data;
			}
		}else {
			str = XMLNode.firstChild.data;
		};return str
	}
	//searches for any javascript in the string and evaluates it.
	var evalScriptsInString = function(s){
		var re = /(?:<script.*?>)((\n|.|\r)*?)(?:<\/script>)/img;
		var scripts = s.match(re);
		s = s.replace(re,'');
		re = /(?:<script.*?>)((\n|.|\r)*?)(?:<\/script>)/im;
		if (scripts) for (var i=0; i<scripts.length; i++) {
			eval(scripts[i].match(re)[1]);
		}
		return s;
	}

	//get the commands.
	if (window.ActiveXObject) {
		var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
		xmlDoc.loadXML(strXML);
	}else {
		var parser = new DOMParser();
		var xmlDoc = parser.parseFromString(strXML,"text/xml");
	}
	var commands = xmlDoc.getElementsByTagName('command');

	for (var n=0; n<commands.length; n++){//for each command
		var command = commands[n];
		var type = commands[n].getAttribute('type');
		var doc = commands[n].getAttribute('useparent')=='true' ? parent.document : document;
		if (type=='replace'){//replace old element
			var replacements = command.getElementsByTagName('replacement');
			for (var i=0; i<replacements.length; i++){
				var oldDiv = doc.getElementById(replacements[i].getAttribute('id'));
				if (!oldDiv) { alert("Command 'replace' Error -- Invalid ElementID returned: " + replacements[i].getAttribute('id')); return; }
				var newDiv = doc.createElement("div");
				newDiv.innerHTML = evalScriptsInString(getNodeString(replacements[i]));
				oldDiv.parentNode.replaceChild(newDiv, oldDiv);
			}
		}else if (type=='popup'){//show a popup
			var title = getNodeString(command.getElementsByTagName('title')[0]);
			var body = evalScriptsInString(getNodeString(command.getElementsByTagName('body')[0]));
			showPopUp(title, body);
		}else if (type=='forward'){//forward user
			var url = command.getElementsByTagName('url')[0].firstChild.data;
			window.location.href = url;
		}else if (type=='script'){//execute some JS
			eval(getNodeString(command));
		}
	}
}
/***********************************************************/

/***************** LITTLE COVER CLASS **********************/
function Cover(divToCover){
	divToCover.style.position = "relative";

	var bgDiv = document.createElement("div");
	bgDiv.className = 'coverDiv';
	bgDiv.style.visibility = 'hidden';
	bgDiv.style.width = divToCover.offsetWidth + 'px';
	bgDiv.style.height = divToCover.offsetHeight + 'px';

	//note: not themeable at the moment!
	var imgDiv = document.createElement("div");
	imgDiv.className = 'coverDivImg';
	imgDiv.style.visibility = 'hidden';
	imgDiv.style.width = bgDiv.style.width;
	imgDiv.style.height = bgDiv.style.height;

	this.bgDiv = bgDiv;
	this.imgDiv = imgDiv;
	this.divToCover = divToCover;
}
Cover.prototype.show = function(){
	this.divToCover.appendChild(this.bgDiv);
	this.divToCover.appendChild(this.imgDiv);

	this.bgDiv.style.display = "block";
	this.imgDiv.style.display = "block";
	var randNum= Math.round(Math.random()*1000000000); // tack a big random number on to the loading gif so it always starts over
	this.imgDiv.style.background = 'url('+theme+'/loading.gif?x='+randNum+') no-repeat center center';

	var relTop = (this.bgDiv.offsetHeight - this.imgDiv.offsetHeight)/2;
	var relLeft = (this.bgDiv.offsetWidth - this.imgDiv.offsetWidth)/2;
	this.imgDiv.style.top = relTop + 'px';
	this.imgDiv.style.left = relLeft + 'px';

	Fade(this.imgDiv, .5, 1);
	Fade(this.bgDiv, .1, .6);
}
Cover.prototype.kill = function(){
	try{ this.divToCover.removeChild(this.bgDiv) } catch (e){};
	try{ this.divToCover.removeChild(this.imgDiv) } catch(e){};
}
/***********************************************************/
