/******************************************************************************
 * callToServer(url[, method, data]) - makes an ajax call to the server
 * 		url 	= the url  to the php page that is acting as the handler
 * 		method 	= (optional) used to set the send method, either GET or POST
 * 				  defaults to GET.
 * 		data 	= if method was explicitly set (usually to POST) then data is
 * 				  the content to be used to post.
 ******************************************************************************/
function callToServer(url) {
	var httpRequest;
	
	if (window.XMLHttpRequest) { // Mozilla, Safari, ...
		httpRequest = new XMLHttpRequest();
		if (httpRequest.overrideMimeType) {
			httpRequest.overrideMimeType("text/xml");
			// See note below about this line
		}
	} else if (window.ActiveXObject) { // IE
		try {
			httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try {
				httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (e) {}
		}
	} else {
		return false;
	}
	
	// lets get method, default to GET
	var method = "GET";
	var data = null;
	if (callToServer.arguments.length > 1) {
		method = callToServer.arguments[1];
		data = callToServer.arguments[2];
	}
	// generally we would have a referer, but if we are secure we won't, so add it to the query string
	if (!window.location.href.match(/^http:/)) {
		url += '&referer='+window.location.toString();
	}
	httpRequest.onreadystatechange = function() { handleResponse(httpRequest); };
	httpRequest.open(method, url, true);
	method == "POST"? httpRequest.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8"):false;
	httpRequest.send(data);
	return true;
}

/******************************************************************************
 * handleResponse(httpRequest) - event handler for returning XMLHttpRequests	 	  
 ******************************************************************************/
function handleResponse(httpRequest) {
	/******************************************************************************
	 * getNodeValue(nodes) - used internally only.  combines multiple nodes that 
	 * 		result from the data being returned in the call being larger then the
	 * 		XML node can contain in one node.	 	  
	 ******************************************************************************/
	function getNodeValue(nodes) {
		var str = "";
		for (var i = 0; i < nodes.length; i++) {
			str += nodes[i].nodeValue;
		}
		return str;
	}
	/******************************************************************************
	 * copyStyle(fromobj,toobj) - copies the class and inline style attributes from
	 * 		one node to another.	 
	 ******************************************************************************/
	function copyStyle(fromobj,toobj) {
		// first we need to grab any class attributes
		toobj.className = fromobj.className;
		
		// now lets walk across any inline style rules
		var inline = fromobj.style['cssText'].split(";");
		for (var i in inline) {
			// filter out the empty trailing entry
			if (inline[i].match(/^\s*$/)) {
				continue;
			}
			// now lets split this rule into name(0) and value(1)
			var tmpstyle = inline[i].split(':');
			// lets convert the style name from normal format to script format
			var namearr = tmpstyle[0].split("-");
			var cssname = "";
			for (var j = 0; j < namearr.length; j++) {
				var f_letter = namearr[j].charAt(0).toUpperCase();
				var rest = namearr[j].slice(1,namearr[j].length);
				cssname = cssname + (j>0? f_letter+rest:namearr[j]);
			}
			// trim spaces off the string
			cssname = cssname.replace(/^\s+|\s+$/g,'');
			cssvalue = tmpstyle[1].replace(/^\s+|\s+$/g,'');
			eval("toobj.style."+cssname+" = '"+cssvalue+"';");
		}
	}
	if (httpRequest.readyState == 4) {
		if (httpRequest.status == 200) {
			var xmldoc = httpRequest.responseXML;
			var response = xmldoc.getElementsByTagName("response");
			for (var i = 0; i < response.length; i++) {
				var action = getNodeValue(response[i].getElementsByTagName("action")[0].childNodes);
				switch(action) {
					/*************************************************************************
					 * append - appends PAYLOAD to TARGET inside a new div with id = NEW_ID
					 *************************************************************************/
					case "append":
						var target = getNodeValue(response[i].getElementsByTagName("target")[0].childNodes);
						var new_id = getNodeValue(response[i].getElementsByTagName("new_id")[0].childNodes);
						var content = getNodeValue(response[i].getElementsByTagName("payload")[0].childNodes);
						var cssclass = false;
						getNodeValue(response[i].getElementsByTagName("cssclass"))? cssclass = getNodeValue(response[i].getElementsByTagName("cssclass")[0].childNodes):false;
						var newdiv = document.createElement("div");
						var editdiv = document.getElementById(target);
						newdiv.id = new_id;
						newdiv.innerHTML = content;
						newdiv.className = cssclass? cssclass:"";
						editdiv.appendChild(newdiv);
						break;
					/*************************************************************************
					 * append - appends PAYLOAD to TARGET inside a new div with id = NEW_ID
					 *************************************************************************/
					case "prepend":
						var target = getNodeValue(response[i].getElementsByTagName("target")[0].childNodes);
						var new_id = getNodeValue(response[i].getElementsByTagName("new_id")[0].childNodes);
						var content = getNodeValue(response[i].getElementsByTagName("payload")[0].childNodes);
						var cssclass = false;
						getNodeValue(response[i].getElementsByTagName("cssclass"))? cssclass = getNodeValue(response[i].getElementsByTagName("cssclass")[0].childNodes):false;
						var newdiv = document.createElement("div");
						var editdiv = document.getElementById(target);
						newdiv.id = new_id;
						newdiv.innerHTML = content;
						newdiv.className = cssclass? cssclass:"";
						editdiv.insertBefore(newdig,editdiv.firstChild);
						break;
					/*************************************************************************
					 * execute - evals the content of PAYLOAD. can be used to run returned 
					 * 			 JavaScript Code
					 *************************************************************************/
					case "execute":
						var content = getNodeValue(response[i].getElementsByTagName("payload")[0].childNodes);
						eval(content);
						break;
					/*************************************************************************
					 * remove - removes TARGET from its parent
					 *************************************************************************/
					case "remove":
						var target = getNodeValue(response[i].getElementsByTagName("target")[0].childNodes);
						var editdiv = document.getElementById(target);
						editdiv.parentNode.removeChild(editdiv);
						break;
					/*************************************************************************
					 * replace - replaces node TARGET or the PARENT of target with a new div
					 * 			 with id = TARGET containing PAYLOAD					 
					 *************************************************************************/
					case "replace":
						var target = "";
						var parent = false;
						// target a node, or target the parent of a node based on which is provided
						if (response[i].getElementsByTagName("target").length) {
							target = getNodeValue(response[i].getElementsByTagName("target")[0].childNodes);
						} else if (response[i].getElementsByTagName("parent").length) {
							target = getNodeValue(response[i].getElementsByTagName("parent")[0].childNodes);
							parent = document.getElementById(target).parentNode;
							target = parent.id;
						}
						var content = getNodeValue(response[i].getElementsByTagName("payload")[0].childNodes);
						var newdiv = document.createElement("div");
						var editdiv = parent? parent:document.getElementById(target);
						newdiv.id = target;
						newdiv.innerHTML = content;
						copyStyle(editdiv,newdiv);
						editdiv.parentNode.replaceChild(newdiv,editdiv);
						break;
					/*************************************************************************
					 * replace-prepend - if a node exists replace new_id, else appends PAYLOAD 
					 *   				to TARGET inside a new div with id = NEW_ID
					 *************************************************************************/
					case "status-msg":
					case "replace-prepend":
						var target = getNodeValue(response[i].getElementsByTagName("target")[0].childNodes);
						var new_id = getNodeValue(response[i].getElementsByTagName("new_id")[0].childNodes);
						var content = getNodeValue(response[i].getElementsByTagName("payload")[0].childNodes);
						var editdiv;
						var newdiv = document.createElement("div");
						newdiv.id = new_id;
						newdiv.innerHTML = content;
						
						if (document.getElementById(new_id)) {
							target = new_id;
							editdiv = document.getElementById(target);
							copyStyle(editdiv,newdiv);
							editdiv.parentNode.replaceChild(newdiv,editdiv);
						} else {
							editdiv = document.getElementById(target);
							editdiv.insertBefore(newdiv,editdiv.firstChild);
						}
						break;
					default:
				}
			}
		}
	}
}

/*************************************************************************
 * cancel(editdiv,gotoanchor) - empties the contents of editdiv and
 * 		moves the page to gotoanchor 
 *************************************************************************/	
function cancel(editdiv,gotoanchor) {
	editdiv.innerHTML = '';
	gotoanchor? window.location.hash = gotoanchor:void(0);
}

/*************************************************************************
 * getFormData(fobj) - takes a handle to a form and creates a key/value list
 * 		for use as data in a POST using the callToServer() function 
 *************************************************************************/	
function getFormData(fobj) {
	var str = "";
	for(var i = 0;i < fobj.elements.length;i++) {
		var element_name = escape(fobj.elements[i].name);
		switch(fobj.elements[i].type) {
			case "hidden":
			case "text":
			case "textarea":
			case "password":
				str += element_name + "=" + escape(fobj.elements[i].value) + "&";
				break;
			case "select-one":
			case "select-multiple":
				for (var j = 0; j < fobj.elements[i].options.length; j++) {
					if (fobj.elements[i].options[j].selected) {
						str += element_name + "=" + escape(fobj.elements[i].options[j].value) + "&";
					}
				}
				break;
			case "radio":
			case "checkbox":
				if (fobj.elements[i].checked) {
					str += element_name + "=" + escape(fobj.elements[i].value) + "&";
				}
				break;
			case "file":
				alert(fobj.elements[i].type+" inputs are not supported by getFormData.");
		}
	}
	str = str.substr(0,(str.length - 1));
	return str;
}

