/**
 * @package focus.common
 *
 * XMLDom 工具包
 *
 * @author J. Jiang <jiangjing@focus.cn>
 * @create 2006-4-14
 * @update 
 *
 * 类型为 U_XML_SOURCE 的参数，可以是以下情形之一
 *   + XML文件路径(字符串)
 *   + XML文本
 *   + MSXML DOM对象
 *
 * @depend on
 *   /common/js/user_agent.js
 */

if (typeof __USER_AGENT__ == "undefined") {
	// 定义当前浏览器
	var __USER_AGENT__ = "UNKNOWN";
	if (window.ActiveXObject) {
		__USER_AGENT__ = "IE";
	}
	else if (navigator.appName == "Netscape") {
		__USER_AGENT__ = "Netscape";
	}
	else if (navigator.userAgent.indexOf("Opera") >= 0) {
		__USER_AGENT__ = "Opera";
	}

	// 当前浏览器是否符合 DOM Conformance
	var __DOM_CONFORM__ = (document.implementation && document.implementation.createDocument);

	// throw new Error("UserAgent not examined. Please load /common/js/user_agent.js in advance.");
}

// XMLDocument 对象构造函数
function XMLDocument() {
	var dom = null;
	if (window.ActiveXObject) {	// IE
		var arrSignatures = [
			"MSXML2.DOMDocument",
			"Microsoft.XMLDOM"];
		for (var i = 0; i < arrSignatures.length; i++) {
			try {
				dom = new ActiveXObject(arrSignatures[i]);
			}
			catch (ex) {
			}
		}
	}
	else if (document.implementation && document.implementation.createDocument) {	// DOMConformance
		dom = document.implementation.createDocument("", "", null);
	}
	if (dom != null) {
		dom.async = true;	// as what IE|Netscape do
		return dom;
	}
	throw new Error("XMLDOMDocument not found.");
}

// IE region
if (__USER_AGENT__ == "IE") {
	// 使用条件编译的方式排斥其他浏览器
	/*@cc_on	

		// XMLHttpRequest 对象构造函数
		function XMLHttpRequest() {
			var arrSignatures = [
				"Microsoft.XMLHTTP",
				"MSXML2.XMLHTTP"];
			for (var i = 0; i < arrSignatures.length; i++) {
				try {
					return new ActiveXObject(arrSignatures[i]);
				}
				catch (ex) {
				}
			}
			throw new Error("MSXMLHttpRequest not found.");
		}

		// XSLTProcessor 对象构造函数
		function XSLTProcessor(src) {
			try {
				var oXslDom = new ActiveXObject("MSXML2.FreeThreadedDOMDocument");

				oXslDom.async = false;
				if (!oXslDom.load(src)) {
					return null;
				}

				var oTemplate = new ActiveXObject("MSXML2.XSLTemplate");
				oTemplate.stylesheet = oXslDom;
				return oTemplate.createProcessor();
			}
			catch (ex) {
				return false;
			}
		}
	@*/	
}

// DOMConformance region: for UAs meet DOM Conformance
if (__DOM_CONFORM__) {

	/**
	 * 利用给定的 XML 流生成新的 XMLDOM 对象
	 *
	 * @param string str XML 流
	 *
	 * @return
	 *   object(XMLDOM) 解析成功
	 *   bool(false) 解析失败
	 */
	function __DOM_GetDomFromString__(s) {
		if (typeof s != "string") {
			return false;
		}

		var oParser = new DOMParser();
		try {
			var newDom = oParser.parseFromString(s, "text/xml");

			/**
			 * 在下列浏览器中发现，解析过程中出现的错误无法被捕捉(un-catchable)而被强制抛出
			 * 但不影响后续代码的执行，因此可用特殊的语句来判断解析是否成功
			 * userAgent: Mozilla/5.0 (Windows; U; Windows NT 5.0; zh-CN; rv:1.8.0.7) Gecko/20060909 Firefox/1.5.0.7	st
			 */
			if (newDom.documentElement.tagName == "parsererror") {
				return false;	// 解析失败
			}
		}
		catch (ex) {
			return false;	// 解析失败
		}
		return newDom;
	}

	//---------------------------------------------------------------------------
	// simulate the behaviors of MSXMLDOM

	// 仅能模拟状态 0, 1 (LOADING), 4(COMPLETED)
	Document.prototype.readyState = 0;
	Document.prototype.onreadystatechange = null;
	Document.prototype.__changeReadyState__ = function(nReadyState)  {
		this.readyState = nReadyState;
		if (typeof this.onreadystatechange == "function") {	// 若定义了 onreadystatechange 方法，则执行之
			this.onreadystatechange();
		}
	}

	// 从指定 XMLDocument 对象中复制节点
	Document.prototype.__copy__ = function(newDom) {
		if (newDom == null) {
			return false;
		}

		/**
		 * 为什么不直接返回 dom ?
		 * 1.在对象函数中不允许直接对对象本身进行赋值
		 * 2.Document 对象除了子节点外，还有其他属性、方法等特性，需要保留
		 */

		// 移除对象的全部子节点
		while (this.firstChild) {
			this.removeChild(this.firstChild);
		}

		// 将新对象的全部子节点移入当前对象
		for (var i = 0; i < newDom.childNodes.length; i++) {
			this.appendChild(this.importNode(newDom.childNodes[i], true));	// @?
		}

		this.__changeReadyState__(4);	// 模拟状态 4 (COMPLETED)	
		return true;
	}

	// * an extension to the W3C DOM
	Document.prototype.loadXML = function(sXml) {
		this.__changeReadyState__(1);	// 模拟状态 1 (LOADING)
		
		var newDom = __DOM_GetDomFromString__(sXml);
		if (newDom == false) {
			this.__changeReadyState__(0);
			return false;
		}

		this.__copy__(newDom);
		return true;
	}

	//---------------------------------------------------------------------------
}

// Netscape region: for UAs based on Netscape
// Netscape usually meet DOM Conformance so that code in DOMConformance region can be used here
if (__USER_AGENT__ == "Netscape") {

	//---------------------------------------------------------------------------
	// simulate some behaviors of MSXMLDOM
	
	Node.prototype.__defineGetter__(
		"xml",
		function() {
			return (new XMLSerializer).serializeToString(this, "text/xml");
		}
	);

	// * an extension to the W3C DOM
	Node.prototype.transformNode = function(oXslDom) {
		var oProcessor = new XSLTProcessor();
		oProcessor.importStylesheet(oXslDom);
		oProcessor.setParameter(null, "__USER_AGENT__", __USER_AGENT__);

		var oResultDom = oProcessor.transformToDocument(this);
		var sResult = oResultDom.xml;
		
		return sResult;
	}

	// * an extension to the W3C DOM
	Node.prototype.selectSingleNode = Node.prototype.__selectSingleNode__;

	// * an extension to the W3C DOM
	Node.prototype.selectNodes = Node.prototype.__selectNodes__;

	// * an extension to the W3C DOM
	Node.prototype.__defineGetter__(
		"text",
		function() {
			return this.textContent;
		}
	);

	// * an extension to the W3C DOM
	Node.prototype.__defineSetter__(
		"text",
		function(s) {
			this.textContent = s;
		}
	);

	//---------------------------------------------------------------------------
}

// Opera region: for Opera 
if (__USER_AGENT__ == "Opera") {

	// @todo 扩展 XMLDOMNode 的 xml 属性

	// * an extension to the W3C DOM
	// 利用 XMLHttpRequest 对象实现从文件载入数据的功能
	Document.prototype.load = function(url) {
		this.__changeReadyState__(1);	// 模拟状态 1 (LOADING)

		var xmlhttp = new XMLHttpRequest();
		xmlhttp.open("GET", url, this.async);
		xmlhttp.send("");

		if (this.async) {	// 异步方式
			var dom = this;	// @tip 规避在 xmlhttp.onreadystatechange() 中使用 this 引起歧义
			xmlhttp.onreadystatechange = function() {
				if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
					dom.__copy__(xmlhttp.responseXML);
				}
			}
		}
		else {
			return this.__copy__(xmlhttp.responseXML);
		}
	}

	// * an extension to the W3C DOM
	Node.prototype.transformNode = function(oXslDom) {
		// @todo Opera doesn't support XSLT till now 2006-10-26
	}
}

/**
 * 读取 XMLDOM 的内容
 *
 * @param XMLDOM dom
 *
 * @return 
 *   string - 转换后的文本
 *   bool(false) - 转换失败
 */
function myxml_read(dom) {
	try {
		if (dom.xml) {
			return dom.xml;
		}
		else {
			return (new XMLSerializer).serializeToString(dom, "text/xml");
		}
	}
	catch (ex) {
		return false;
	}
}

/**
 * 生成 XMLDOM 对象
 *
 * @param U_XML_SOURCE xml
 *
 * @return 
 *   object - 载入XML源的 DOM 对象
 *   null - 生成 DOM 对象失败
 *   bool(false) - 载入 XML 资源失败
 */
function myxml_newdom(xml, async) {
	if (typeof xml == "object") {
		return xml;
	}
	
	var dom = new XMLDocument();
	if (async != true) {
		dom.async = false;
	}
	
	if (__USER_AGENT__ == "IE") {
		dom.setProperty("SelectionLanguage", "XPath");	// @debug
	}

	if (typeof xml == "string") {
		if (xml.charAt(0) == "<") {	// 判断给定参数为 XML 流
			if (!dom.loadXML(xml)) {
				return false;	// 解析失败
			}
		}
		else {	// 给定参数为 XML 资源地址
			if (!dom.load(xml)) {	// 不同浏览器中的 XMLDOM 均支持
				return false;	// 解析资源失败
			}
		}
	}

	if (__USER_AGENT__ == "Netscape") {
		// 在 onload 事件中模拟 MSXMLDOM.prototype.onreadystatechange 事件
		dom.addEventListener(
			"load", 
			function() { this.__changeReadyState__(4); },
			false
		);
	}

	return dom;
}

/**
 * 利用 XSLT 转换 XML
 *
 * @param U_XML_SOURCE xml 数据源
 * @param U_XML_SOURCE xslt 转换脚本源
 *
 * @return
 *   string - 转换后的文本
 *   bool(false) - 转换失败
 */
function myxml_transform(xml, xslt) {
	domXML = myxml_newdom(xml);
	domXSLT = myxml_newdom(xslt);
	
	if (typeof domXML == "object" && typeof domXSLT == "object") {
		return domXML.transformNode(domXSLT);
	}
	else {
		return false;
	}
}

/**
 * 取得节点属性
 *
 * @param IXMLDOMNode node 节点对象
 * @param string attr_name 属性名称
 *
 * @return 
 *   null - 无此属性
 *   string - 属性值
 */
function myxml_getAttribute(node, attr_name) {
	try {
		var nodeAttr = node.attributes.getNamedItem(attr_name);
		if (nodeAttr == null) {
			return null;
		}
		else {
			return nodeAttr.value;
		}
	}
	catch (ex) {
		return null;
	}
}

/**
 * 更改/设置节点属性
 *
 * @param IXMLDOMNode node 节点对象
 * @param string attr_name 属性名称
 * @param string attr_value 属性值
 *
 * @return bool 是否设置成功
 */
function myxml_setAttribute(node, attr_name, attr_value) {
	try {
		var nodeAttr = node.attributes.getNamedItem(attr_name);
		if (nodeAttr == null) {
			nodeAttr = node.ownerDocument.createAttribute(attr_name);
			node.attributes.setNamedItem(nodeAttr);
		}
		nodeAttr.value = attr_value;
	}
	catch (ex) {
		return false;
	}
	return true;
}

/**
 * 在函数中完成客户端同 http 服务器的通讯
 *
 * @param string url 请求的 URL 地址，可以为绝对地址也可以为相对地址，可包含参数
 * @param string method HTTP 请求方式
 * @param string response_type default "status" 返回的内容
 *   "XML" - 服务器返回的 XML 构成的 XMLDOMDocument 对象 (返回内容必须指定 "Content-type: text/xml"
 *   "Text" - 服务器返回的文本字符串
 *   "status" - HTTP 状态码
 *
 * @return 见关于参数 response_type 的说明
 */
function myxmlhttp(url, method, response_type, body) {
	if (method == null) {
		method = "POST";
	}
	
	var xmlhttp = new XMLHttpRequest();
	xmlhttp.open(method, url, false);
	xmlhttp.send(body);
	switch(response_type) {
		case "XML":
			xmlhttp.responseXML.setProperty("SelectionLanguage", "XPath");
			return xmlhttp.responseXML;
		case "Text":
			return xmlhttp.responseText;
		case "status":
		default:
			return xmlhttp.status;
	}
}

/**
 * 在函数中请求 http 服务器并将返回内容(文本)填充到指定容器中
 *
 * @param mixed element	容器句柄或其 Id
 * @param string url 
 * @param optional bool bAsync default false 是否采用异步方式
 *
 * @return bool 是否执行成功
 */
function myxmlhttp_fill(element, url, bAsync) {
	if (bAsync == null) {
		bAsync = false;
	}
	
	if (typeof element == "string") {
		element = document.getElementById(element);
	}
	if (element == null) {
		return false;
	}
	else {
		var xmlhttp = new XMLHttpRequest();
		if (bAsync) {			
			xmlhttp.onreadystatechange = function() {
				if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
					element.innerHTML = xmlhttp.responseText;
				}
			}
		}
		
		xmlhttp.open("GET", url, bAsync);		
		xmlhttp.send(null);
		if (!bAsync) {
			element.innerHTML = xmlhttp.responseText;
		}
		return true;
	}
}