/*
	Author: Stephen W. Cote
	Email: wranlon@hotmail.com
	Website: www.whitefrost.com

	Copyright 2002, All Rights Reserved.

	version: 1.0.0.11.04.2002
*/


/*

	Usage:
		Synchronous GET:
			[xml_dom_object] = getXml(path);
		Asynchronous GET:
			[int] = getXml(path,handler,1,{optional_id});
		Synchronous POST:
			[xml_dom_object] = postXml(path,data);
		Asynchronous POST:
			[int] = postXml(path,data,handler,1,{optional_id});

*/


// array of xml request data, used primarily for asynchronous actions
var xml_requests = [];

// array used for reverse lookup of xml ids
var xml_requests_map = [];

/*
	handle_xml_request_load(xml_id) invoked by Event or handle_xml_request_readystatechange
	Invokes the user-specified handler with the responseXML data
*/
function handle_xml_request_load(xml_id){
	/*
		xml_id = the id for a given XML request.
		
		o = xml request object
		v = response data sent to the user-specified handler
	*/
	var o,v;

	// verify the xml id is valid
	if(typeof xml_requests_map[xml_id] == "number"){
		// retrieve the request object
		o = xml_requests[xml_requests_map[xml_id]];
		// create a response object to pass to the handler
		v = {"xdom":null,"id":xml_id};
		// retrieve the xml DOMDocument from the responseXML property
		if(o.obj != null && o.obj.responseXML != null){
			v.xdom = o.obj.responseXML;
		}
		// mark a bit indicating the request was completed
		o.completed = 1;
		// invoke the handler with the response data
		if(typeof o.handler=="function") o.handler("onloadxml",v);
		else alert("No handler for request: " + xml_id);

		/*
			clear out the request object
			Note that this is a point to implement caching of XML requests
		*/
		o.obj = 0;

	}	
}

/*
	handle_xml_request_readystatechange(xml_id) invoked by Internet Explorer
	Invokes handle_xml_request_load when the ready_state is 4.
	
	Note: server errors may cause the request to die here for IE
*/
function handle_xml_request_readystatechange(xml_id){
	/*
		xml_id = the id for a given XML request.
		
		o = xml request object
	*/
	var o;
	// verify the xml id is valid	
	if(typeof xml_requests_map[xml_id] == "number"){
		// retrieve the request object
		o = xml_requests[xml_requests_map[xml_id]];
		// verify the readystate as 4, or complete
		if(typeof o.obj == "object" && o.obj.readyState == 4){
			// invoke handle_xml_request_load for this request id
			handle_xml_request_load(xml_id);
		}
	}
}

/*
	getXml(path,handler,id);
	handler is optional for synchronous requests.
	id is optional.  Use the id when two or more xml transactions will be directed through the same handler.
	to specify a custom id for synchronous requests, use null or 0 for the handler, and false or 0 for the async property.	
*/
function getXml(p,h,a,i){
/*
		p = path
		h = handler
		a = async
		i = id
*/
	return doXmlHttpRequest(p,h,a,i,0,null);
}
/*
	postXml(path,data,handler,async,id);
	handler is optional for synchronous requests
	to specify a custom id for synchronous requests, use null or 0 for the handler, and false or 0 for the async property.
	id is optional.
	
*/
function postXml(p,d,h,a,i){
	return doXmlHttpRequest(p,h,a,i,1,d);
}

/*
	doXmlHttpRequest(path,handler,async,id,is_post,data);
	
	doXmlHttpRequest should be invoked by getXml or postXml.
*/
function doXmlHttpRequest(p,h,a,i,x,d){
	/*
		p = path
		h = handler
		a = async
		i = id
		x = is_post as bool
		d = data as string or DomDocument
		
		[internal]
		z = String literal GET or POST based on x
		y = length of xml requests array.
	*/
	
	var f,o=null,v,y,z;

	// if x isn't specified, set the request type to GET
	if(typeof x=="undefined") x = 0;
	// if d isn't specified, set the request data to null
	if(typeof d=="undefined") d = null;

	// set GET or POST based on the x param
	z = (x?"POST":"GET");

	// make up a unique id if one isn't provided
	if(typeof i!="string") i="uid-" + parseInt(Math.random()*10000);

	// get the length of the xml requests array
	y = xml_requests.length;

	// create an object for this request
	xml_requests[y] = {url:p,id:i,obj:null,handler:h,method:(x?1:0),completed:0};

	// Add a reverse lookup based on the id
	xml_requests_map[i]=y;
	
	/* Is an XMLHttpRequest function defined for the client?  If so, use that */
	if(typeof XMLHttpRequest=="function"){
		// set the xml object to a new XMLHttpRequest
		o = xml_requests[y].obj = new XMLHttpRequest();

		// correct the path to use a fully qualified url
		if(!p.match(/:\/\//)){
			var m,e=new RegExp("^/");
			if(!p.match(e)){
				m=location.pathname;
				m=m.substring(0,m.lastIndexOf("/")+1);
				p=m + p;
			}
			p=location.protocol + "//" + location.host + p;
		}

		// copy the url to the request object
		xml_requests[y].url = p;
		// if this is an asynchronous request, specify a handler
		// Note the reliance on the existence of addEventListener for XMLHttpRequest
		if(a){
			f = function(){handle_xml_request_load(i);};
			o.addEventListener("load",f,false);
		}
	}

	/* If not, try using the ActiveX control */
	/* Note: this is a point of failure for downlevel browsers */
	else{
		try{
			// set the xml object to a new XMLHTTP COM object
			o = xml_requests[y].obj = new ActiveXObject("Microsoft.XMLHTTP");
			// if asynchronous, setup a handler for the readystate event.
			if(a){
				f = function(){handle_xml_request_readystatechange(i);};
				o.onreadystatechange=f;
			}
		}
		catch(e){
			// oops, something is broken
			alert("XMLError: " + (e.description?e.description:e.message));
		}
	}
	
	// create a boolean value based on the async param
	var boolean_value = (a?true:false);
	// open the XMLHTTPRequest for GET or POST, the given path, and whether it is asynchronous
	o.open(z,p,boolean_value);
	// send the data, if any was specified
	o.send(d);
	// if this a synchronous request, immediately return the responseXML
	if(!a){
		var temp = xml_requests[y].obj.responseXML;
		xml_requests[y].obj = null;
		return temp;
	}
	// otherwise, return 1
	return 1;

} 



function newXmlDocument(n){
	/*
		n = "root node";
	*/
	
	var r = 0,e;
	if(typeof document.implementation != "undefined" && typeof document.implementation.createDocument != "undefined"){
		r = document.implementation.createDocument("",n,null);
	}
	else{
		r = new ActiveXObject("MSXML.DOMDocument");
		e = r.createElement(n);
		r.appendChild(e);
	}
	return r;
}

function serialize(n){
	var v;
	if(typeof XMLSerializer=="function"){
		return (new XMLSerializer()).serializeToString(n);
	}
	else if(typeof n.xml == "string"){
		return n.xml;
	}
}

function selectSingleNode(d,x,c){
	/*
		d = XmlDocument
		x = xpath
		c = context node
	*/
	var s,i,n;
	if(typeof d.evaluate != "undefined"){
		c = (c ? c : null);
		s = d.evaluate(x,c,null,0,null);

		return s.iterateNext();
	}
	else if(typeof d.selectNodes != "undefined"){
		return (c ? c : d).selectSingleNode(x);
	}

	return 0;

}

function selectNodes(d,x,c){
	/*
		d = XmlDocument
		x = xpath
		c = context node
	*/
	var s,a = [],i,n;
	if(typeof d.evaluate != "undefined"){
		c = (c ? c : null);
		s = d.evaluate(x,c,null,0,null);

		n = s.iterateNext();

		while( typeof n == "object" && n != null){
			a[a.length] = n;
			n = s.iterateNext();
		}

		return a;

	}

	else if(typeof d.selectNodes != "undefined"){
		return (c ? c : d).selectNodes(x);
	}

	return a;

}

function getInnerText(s){
	var r = "",a,i,e;
	if(typeof s == "string") return s;
	if(typeof s=='object' && s.nodeType==3) return s.nodeValue;
	if(s.hasChildNodes()){
		a = s.childNodes;
		for(i=0;i<a.length;i++){
			e = a[i];
			if(e.nodeType==3) r+=e.nodeValue;
			if(e.nodeType==1 && e.hasChildNodes()){
				r+=getInnerText(e);
			}
		}
	}
	return r;
}
function removeChildren(o){
	var i;
	for(i=o.childNodes.length-1;i>=0;i--){
		o.removeChild(o.childNodes[i]);
	}
}
function setInnerXHTML(t,s,p){
	/*
		t = target
		s = source
		p = preserve
	*/
	var y,e,a,l,x,n,v;
	if(!p){
		removeChildren(t);
	}

	y=(s && typeof s=='object')?s.nodeType :(typeof s=="string")?33:-1;
	switch(y){
		case 1:
			e=document.createElement(s.nodeName);
			a=s.attributes;
			l=a.length;
			for(x=0;x<l;x++){
				n=a[x].nodeName;
				v=a[x].nodeValue;
				if(n=="style"){
					e.style.cssText=v;
				}
				else if(n=="id"){
					e.id=v;
				}
				// this is currently broken for the libXmlRequest.js library
				else if(n=="class"){
					e.className=v;
				}
				else if(n.match(/^on/i)){
					eval("e." + n + "=function(){" + v  +"}");
				}
				else{
					e.setAttribute(n,v);
				}
			}

			if(s.hasChildNodes()){
				a=s.childNodes;
				l=a.length;
				for(x=0;x<l;x++){
					setInnerXHTML(e,a[x],1);
				}
			}
			t.appendChild(e);
			break;
		case 3:
			e=s.nodeValue;
			if(e){
				e=e.replace(/^\s*/,"");
				e=e.replace(/\s*$/,"");
				e=e.replace(/\s+/g," ");
				t.appendChild(document.createTextNode(e));
			}
			break;
		case 8:
			/*
				Ignore comments
			*/
			break;
		case 33:
			e=s;
			if(e){
				e=e.replace(/^\s*/,"");
				e=e.replace(/\s*$/,"");
				e=e.replace(/\s+/g," ");
				t.appendChild(document.createTextNode(e));
			}
			break;
		default:
			break;
	}
}