//	 XML tools jslibrary
//	 copyright 2006 by Marco Balestra - balestra (at) cesmail.net

var XML = {'internal':{} };

XML.internal.busyCount = 0;

XML.internal.busy = function(s) { XML.internal.busyCount += s ? 1 : -1 }

XML.isBusy = function() { return XML.internal.busyCount != 0 }

XML.load = function(url, functionObj, alertForError, sourceDisplay) {
		if (typeof functionObj == 'undefined') return XML.loadSync( url );
		if (typeof alertForError == 'undefined') alertForError = true;
		if (typeof sourceDisplay == 'undefined') sourceDisplay = false;
		return XML.loadAsync( url, functionObj, alertForError, sourceDisplay);
	};

XML.loadSync = function(url) {
		var e,req = XML.internal.newRequestObj();
		try {
			XML.internal.busy(true);
			req.open("GET", url, false);
			req.send(null);
			XML.internal.busy(false);
			return req.responseXML;
		} catch (e) {
			dump('XML.loadSync: ' + e);
			throw(e);
		}
}

XML.loadAsync = function(url,functionObj,alertForError,sourceDisplay) {
		// Load xml document, params:
		// 1. xml URI (must return mime text/xml)
		// 2. reference to function that will process document
		var e,req = XML.internal.newRequestObj();
		XML.internal.busy(true);
		if (typeof alertForError == 'undefined') alertForError = true;
		if (typeof sourceDisplay == 'undefined') sourceDisplay = false;
		if(req) {
			try { req.overrideMimeType("text/xml") } catch(e) { };
			try { req.setRequestHeader("Cookie", document.cookie) } catch(e) { };
			req.onreadystatechange = function() {
				if (req.readyState != 4) return void(0);
				if (XML) { XML.internal.busy(false) } else { return };
				if (req.status != 200) {
					if (alertForError) alert("There was a problem retrieving the XML data:\r\n" + req.statusText);
					return void(0);
				}
				if(sourceDisplay) sourceDisplay.innerHTML='<html:p>Response: '+req.status +' - '+req.statusText+'</html:p><html:pre>'+req.responseText.replace(/</g,"&lt;")+'</html:pre>';
				functionObj(req.responseXML);
			};
			req.open('GET', url, true);
			req.send('');
			return true;
		} else {
			if (XML) { XML.internal.busy(false) } else { return };
			if (alertForError) alert('Cannot load xml:\r\n' + e);
			return false;
		}
	};

XML.post = function(url,functionObj,documentObj,alertForError,sourceDisplay) {
		var e,req = XML.internal.newRequestObj();
		if (typeof alertForError == 'undefined') alertForError = true;
		if (typeof sourceDisplay == 'undefined') sourceDisplay = false;
		try { req.overrideMimeType("text/xml") } catch(e) { };
		try { req.setRequestHeader("Cookie", document.cookie) } catch(e) { };
		try { req.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=utf-8") } catch(e) { };
		//try { req.setRequestHeader("Content-type", "text/xml; charset=utf-8") } catch(e) { };
		if (functionObj) {
			XML.postAsync(url,functionObj,documentObj,alertForError,sourceDisplay, req);
		} else {
			return XML.postSync(url,documentObj,alertForError,sourceDisplay, req);
		}
	};

XML.postSync = function(url,documentObj,alertForError,sourceDisplay, req) {
		var e;
		if (typeof req == 'undefined') req = XML.internal.newRequestObj();
		XML.internal.setTestEscape( documentObj );
		try {
			XML.internal.busy(true);
			req.open("POST", url, false);
			req.send(documentObj);
			XML.internal.busy(false);
			return req.responseXML;
		} catch (e) {
			dump('XML.postSync: ' + e);
			throw(e);
		}
	};
	
XML.postAsync = function(url,functionObj,documentObj,alertForError,sourceDisplay, req) {
		var e;
		if (typeof req == 'undefined') req = XML.internal.newRequestObj();
		XML.internal.setTestEscape( documentObj );
		XML.internal.busy(true);
		if(req) {
			req.onreadystatechange = function() {
				if (req.readyState != 4) return void(0);
				if (XML) { XML.internal.busy(false) } else { return };
				if (req.status != 200) {
					if (alertForError) alert("There was a problem sending XML data:\r\n" + req.status + ' - '+ req.statusText);
					return void(0);
				}
				if(sourceDisplay) sourceDisplay.innerHTML='<html:p>Response: '+req.status +' - '+req.statusText+'</html:p><html:pre>'+req.responseText.replace(/</g,"&lt;")+'</html:pre>';
				functionObj(req.responseXML);
			};
			req.open('POST', url, true);
			//try { req.setRequestHeader("Content-type", "text/xml; charset=utf-8") } catch(e) { };
			try { req.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=utf-8") } catch(e) { };
			req.send(documentObj);
			return true;
		} else {
			if (XML) { XML.internal.busy(false) } else { return };
			if (alertForError) alert('Cannot send xml:\r\n' + e);
			return false;
		}
	};

XML.internal.setTestEscape = function( doc ) {
		var root = doc.documentElement;
		var t = XML.getFirstChildByName( doc, 'testEscapeLevel' );
		if (t) root.removeChild( t );
		root.appendChild( XML.createNode( 'testEscapeLevel', '<', false,  doc ) );
	};

XML.internal.newRequestObj = function() {
		var req = false;
		if(window.XMLHttpRequest) {
			try { req = new XMLHttpRequest() } catch(e) { req = false }
		} else if (window.ActiveXObject) {
			try {
				req = new ActiveXObject("Msxml2.XMLHTTP");
			} catch(e) {
				try { req = new ActiveXObject("Microsoft.XMLHTTP") } catch(e) { req = false }
			}
		}
		return req;
	};

XML.createDocument = function( rootNodeName ) {
		if (typeof rootNodeName != 'string') rootNodeName = "root";
		var e,d = false;
		if (document.implementation && document.implementation.createDocument)
			return document.implementation.createDocument("", rootNodeName, null);
		if (window.ActiveXObject) {
			var ARR_ACTIVEX = ["MSXML4.DOMDocument", "MSXML3.DOMDocument", "MSXML2.DOMDocument", "MSXML.DOMDocument","Microsoft.XmlDom"];
			for (var i=0; i < ARR_ACTIVEX.length; i++) {
				try {
					d = new ActiveXObject(ARR_ACTIVEX[i]);
					return d;
				} catch(e) {}
					alert(e);
				}
			}
		return d;
	};

XML.hasChilds = function(n) { return (n.firstChild) ? true : false };

XML.internal.doeOut = function(t) { return t.replace(/&/g,'&amp;').replace(/&amp;amp;/g,'&amp;').replace(/</g,'&lt;') }

XML.internal.doeIn = function(t) { return t.replace(/&lt;/g,'<').replace(/&gt;/g,'>').replace(/&amp;([a-z0-9]+);/gi,"&$1;"); }

XML.createNode = function(node_name, node_text, node_attr, doc) {
		var e;
		if (typeof node_attr == 'undefined') node_attr = false;
		if (typeof doc == 'undefined') doc = document;
		var nodeObj = doc.createElement(node_name);
		node_text = ( typeof node_text == 'undefined' ) ? false : ( node_text == '' ? false : node_text.toString() );
		if (node_text) nodeObj.appendChild( doc.createTextNode( XML.internal.doeOut(node_text) ) );
		if (node_attr) for (var i in node_attr) nodeObj.setAttribute(i, node_attr[i]);
		return nodeObj;
	};

XML.zapAllChilds = function(n){ while( n.firstChild ) n.removeChild( n.firstChild ) };

XML.getNodeText = function(n,doe) {
		if (! XML.hasChilds(n)) return '';
		if (typeof doe == 'undefined') doe = false;
		var t = XML.internal.collectText( n.childNodes );
		return doe ? XML.internal.doeIn(t) : t ;
	};

XML.internal.collectText = function(cn) {
		// Mozilla has many textnodes with a size of 4096 chars each instead of one large one.
		// They all need to be concatenated.
		var n,i,r = '';
		for (i=0; i< cn.length; i++) {
			n = cn[i].nodeName.toLowerCase();
			if (n == '#text' || n == '#cdata-section') r += cn[i].nodeValue;
		}
		return r;
	}

XML.setNodeText = function(n,t,doc) {
		var cnl = n.childNodes.length;
		t = String( t );
		if (! (doc)) doc = XML.getDocumentObject(n.parentNode);
		// set text, accounting for possible whitespace (carriage return) text nodes
		if (cnl > 1) {
			n.childNodes[1].nodeValue = t;
		} else if (cnl == 1) {
			n.firstChild.nodeValue = t;
		} else {
			//n.appendChild( doc.createTextNode( XML.internal.doeOut(t) ) );
			n.appendChild( doc.createTextNode( t ) );
		}
	};

XML.internal.getChildsByNodeType = function(n,t) {
		var r = new Array();
		if (! XML.hasChilds(n)) return r;
		for (var i=0; (n.childNodes[i]); i++) if (n.childNodes[i].nodeType == t) r.push(n.childNodes[i]);
		return r;
	};

XML.getElementChilds = function(n) { return XML.internal.getChildsByNodeType(n,1) };

XML.getTextChilds = function(n) { return XML.internal.getChildsByNodeType(n,3) };

XML.getCommentChilds = function(n) { return XML.internal.getChildsByNodeType(n,8) };

XML.getDocumentObject = function(n) { return n.nodeType == 9 ? n : XML.getDocumentObject(n.parentNode) };

XML.getChildsByName = function(parent_node,node_name) {
		var r = new Array();
		if (typeof(node_name)!='string') return r;
		if (node_name == '') return r;
		var allChilds = XML.getElementChilds(parent_node);
		for (var i=0; (allChilds[i]); i++) if (allChilds[i].nodeName == node_name) r.push(allChilds[i]);
		return r;
	};

XML.getFirstChildByName = function(parent_node,node_name) {
		if (typeof(node_name)!='string') return false;
		if (node_name == '') return r;
		var allChilds = XML.getElementChilds(parent_node);
		for (var i=0; (allChilds[i]); i++) if (allChilds[i].nodeName == node_name) return allChilds[i];
		return false;
	};

XML.serializer = function( d ) {
		// only works with Geko browsers, included for test/debugging purposes
		return (new XMLSerializer()).serializeToString( d );
	};

