// Documento JavaScript

/* Crea el Objecto */
var zXml = {
    useActiveX: (typeof ActiveXObject != "undefined"),
    useDom: document.implementation && document.implementation.createDocument,
    useXmlHttp: (typeof XMLHttpRequest != "undefined")
};

/* Arrays para las versiones de MSXML XmlHttp */
zXml.ARR_XMLHTTP_VERS  = ["MSXML2.XmlHttp.6.0","MSXML2.XmlHttp.3.0"];

/* Array para las versiones de MSXML DOMDocument */
zXml.ARR_DOM_VERS  = ["MSXML2.DOMDocument.6.0","MSXML2.DOMDocument.3.0"];

//-----------------------------------------------------
// Clase estática para la creación de XMLHttp
//-----------------------------------------------------
function zXmlHttp() { }

//------------------------------------------------------------
// Creación de un objeto XMLHttp y devuelve un objeto XMLHttp
//------------------------------------------------------------
zXmlHttp.createRequest = function () {
	
	//Si soporta el objeto XMLHttpRequest nativo
	if (zXml.useXmlHttp) {
		return new XMLHttpRequest();
	} else if (zXml.useActiveX) { //IE anteriores al 7.0 usa use ActiveX
		
		if (!zXml.XMLHTTP_VER) {
			
			for (var i=0; i < zXml.ARR_XMLHTTP_VERS.length; i++) {
				try {
					new ActiveXObject(zXml.ARR_XMLHTTP_VERS[i]);
					zXml.XMLHTTP_VER = zXml.ARR_XMLHTTP_VERS[i];
					break;
				} catch (oError) {                
				}
			}
		}
		
		if (zXml.XMLHTTP_VER) {
			return new ActiveXObject(zXml.XMLHTTP_VER);
		} else {
			throw new Error("No es posible crear peticiones XML HTTP.");
		}
		
	} else {
		throw new Error("Tu explorador no soporta una petición XML HTTP.");
	}

};

//-------------------------------------------------------------------------------------------
// Indica si XMLHttp esta disponible. Devuelve True si está disponible y false si no lo está
//-------------------------------------------------------------------------------------------
zXmlHttp.isSupported = function () {
	return zXml.useXmlHttp || zXml.useActiveX;
};

//-----------------------------------------------------------------------------------------
// Función para construir el objeto Request
// Parametros:
//		reqType: GET o POST.
//		url: URL del programa servidor.
//		asynch: Tipo de envio asincrono o sincrono.
//		handle: Funcion para obtener la respuesta.
//		sQuery: Parametros, null para GET y cadena para POST
//-----------------------------------------------------------------------------------------
function httpRequest(reqType,url,asynch,handle,sQuery){
	
	//Crea el objeto HTTP Request
	request = zXmlHttp.createRequest();
	
	if(request){
		initReq(reqType,url,asynch,handle,sQuery);
	} else {
		alert("Su navegador no permite el uso de todas las funcionalidades de esta aplicación.");
	}
	
}

//------------------------------------------------------------------------------------------
// Inicializa un objeto Request ya construido
//------------------------------------------------------------------------------------------
function initReq(reqType,url,bool,handle,sQuery){
	try{
		
		//Especifica la funcion que será llamada como respuesta
		request.onreadystatechange = handle;
		
		if (reqType == "post") {
			request.open(reqType,url,bool);
			//request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
		} else {
			request.open(reqType,salvarCahe(url),bool);
		}
		
		request.send(sQuery);
	
	} catch (errv) {
			alert("La aplicación no puede contactar con el servidor en estos momentos. Por favor vuelve a intentarlo más tarde.");
	}
}

//------------------------------------------------------------------------------------------
// Obtiene los valores de los campos de un formulario para ser enviados
//------------------------------------------------------------------------------------------
function getRequestBody(oForm) {
	var aParams = new Array();
	
	for (var i=0 ; i < oForm.elements.length; i++) {
		var sParam = encodeURIComponent(oForm.elements[i].name);
		sParam += "=";
		sParam += encodeURIComponent(oForm.elements[i].value);
		aParams.push(sParam);
	}
	
	return aParams.join("&");
	
}

//-------------------------------------------------------
// Función para salvar la cache de los exploradores
//-------------------------------------------------------
function salvarCahe(cUrl) {
	//Necesario para la cache de las páginas
	var myRand = parseInt(Math.random()*99999999);
	var cConector = "";
	
	if (cUrl.indexOf("?") >= 0) {
		cConector = "&";
	}else{
		cConector = "?";
	}
	
	return cUrl + cConector + "rand=" + encodeURIComponent(myRand);
}

//-------------------------------------------------
// Clase estatica para la creación de XML DOM
//-------------------------------------------------
function zXmlDom() {}

//----------------------------------------------------------------------
// Creación de un objeto XML DOM document. Devuelve un XML DOM document
//----------------------------------------------------------------------
zXmlDom.createDocument = function () {
	
	if (zXml.useDom) {
		var oXmlDom = document.implementation.createDocument("","",null);
		
		oXmlDom.parseError = {
			valueOf: function () { return this.errorCode; },
			toString: function () { return this.errorCode.toString() }
		};
		
		oXmlDom.__initError__();
		
		oXmlDom.addEventListener("load", function () {
			this.__checkForErrors__();
			this.__changeReadyState__(4);
		}, false);
		
		return oXmlDom;
	
  } else if (zXml.useActiveX) {
		
		if (!zXml.DOM_VER) {
			for (var i=0; i < zXml.ARR_DOM_VERS.length; i++) {
				try {
					new ActiveXObject(zXml.ARR_DOM_VERS[i]);
					zXml.DOM_VER = zXml.ARR_DOM_VERS[i];
					break;
				} catch (oError) {
				}
			}
		}
    
		if (zXml.DOM_VER) {
			return new ActiveXObject(zXml.DOM_VER);
		} else {
			throw new Error("No es posible crear XML DOM document.");
		}
	} else {
		throw new Error("Tu explorador no soporta un objeto XML DOM document.");
	}
};

//-------------------------------------------------------------------------------------
//Indica si el XML DOM es soportado. Devuelve True si es soportado y false si no lo es
//-------------------------------------------------------------------------------------
zXmlDom.isSupported = function () {
	return zXml.useDom || zXml.useActiveX;
};

//-----------------------------------------------------------------------------------------
// Código para hacer un objeto DOM documents para Mozilla como el objeto MS DOM documents.
//-----------------------------------------------------------------------------------------
var oMozDocument = null;

if (typeof XMLDocument != "undefined") {
    oMozDocument = XMLDocument;
} else if (typeof Document != "undefined") {
    oMozDocument = Document;
}

if (oMozDocument && !window.opera) {
	
	oMozDocument.prototype.readyState = 0;
	oMozDocument.prototype.onreadystatechange = null;
	
	oMozDocument.prototype.__changeReadyState__ = function (iReadyState) {
		this.readyState = iReadyState;
		
		if (typeof this.onreadystatechange == "function") {
			this.onreadystatechange();
		}
	};
	
	oMozDocument.prototype.__initError__ = function () {
		this.parseError.errorCode = 0;
		this.parseError.filepos = -1;
		this.parseError.line = -1;
		this.parseError.linepos = -1;
		this.parseError.reason = null;
		this.parseError.srcText = null;
		this.parseError.url = null;
	};
	
	oMozDocument.prototype.__checkForErrors__ = function () {
		if (this.documentElement.tagName == "parsererror") {
			
			var reError = />([\s\S]*?)Location:([\s\S]*?)Line Number (\d+), Column (\d+):<sourcetext>([\s\S]*?)(?:\-*\^)/;
			
			reError.test(this.xml);
			
			this.parseError.errorCode = -999999;
			this.parseError.reason = RegExp.$1;
			this.parseError.url = RegExp.$2;
			this.parseError.line = parseInt(RegExp.$3);
			this.parseError.linepos = parseInt(RegExp.$4);
			this.parseError.srcText = RegExp.$5;
		}
	};
	
	oMozDocument.prototype.loadXML = function (sXml) {
		
		this.__initError__();
		
		this.__changeReadyState__(1);
		
		var oParser = new DOMParser();
		var oXmlDom = oParser.parseFromString(sXml, "text/xml");
		
		while (this.firstChild) {
			this.removeChild(this.firstChild);
		}
		
		for (var i=0; i < oXmlDom.childNodes.length; i++) {
			var oNewNode = this.importNode(oXmlDom.childNodes[i], true);
			this.appendChild(oNewNode);
		}
		
		this.__checkForErrors__();
		this.__changeReadyState__(4);
	};
	
	oMozDocument.prototype.__load__ = oMozDocument.prototype.load;
	
	oMozDocument.prototype.load = function (sURL) {
		this.__initError__();
		this.__changeReadyState__(1);
		this.__load__(sURL);
	};
	
	Node.prototype.__defineGetter__("xml", function () {
		var oSerializer = new XMLSerializer();
		return oSerializer.serializeToString(this, "text/xml");
	});
	
	Node.prototype.__defineGetter__("text", function () {
		var sText = "";
		for (var i = 0; i < this.childNodes.length; i++) {
			if (this.childNodes[i].hasChildNodes()) {
				sText += this.childNodes[i].text;
			} else {
				sText += this.childNodes[i].nodeValue;
			}
		}
		
		return sText;
	});
}

//-------------------------------------------------------------------
//Clase estatica para la creación de un objeto XSLT transformations.
//-------------------------------------------------------------------
function zXslt() {}

//--------------------------------------------------------------------
// Transforma un XML DOM a texto usando un XSLT DOM.
// Parametro: oXml el objeto XML DOM a transformar.
// Parametro: oXslt el objeto XSLT DOM a usar para la transformacion.
// Devuelve la transformación como un cadena
//--------------------------------------------------------------------
zXslt.transformToText = function (oXml , oXslt) {
	if (typeof XSLTProcessor != "undefined") {
		var oProcessor = new XSLTProcessor();
		oProcessor.importStylesheet(oXslt);
		
		var oResultDom = oProcessor.transformToDocument(oXml);
		var sResult = oResultDom.xml;
		
		if (sResult.indexOf("<transformiix:result") > -1) {
			sResult = sResult.substring(sResult.indexOf(">") + 1, sResult.lastIndexOf("<"));
		}
		
		return sResult;     
	}else if (zXml.useActiveX) {
		return oXml.transformNode(oXslt);
	} else {
		throw new Error("No encontrado motor XSLT.");
	}
};

//---------------------------------------------------
// Clase estatica para la manipulación del XPath
//---------------------------------------------------
function zXPath() {}

//------------------------------------------------------------------------------------------------------
// Selecciona el primer que coincida en una expresión XPath.
// Parametro: oRefNode, El nodo del cual se va a evaluar la expresión.
// Parametro: xPath, La expresión XPath.
// Parametro: oXmlNs, Objeto que contiene los nombres utilizados en la expresión. Opcional
// Devuelve Un nodo XML correspondiente a la expresión o nulo en caso de que no se encuentre resultado.
//-------------------------------------------------------------------------------------------------------
zXPath.selectNodes = function (oRefNode, sXPath, oXmlNs) {
	if (typeof XPathEvaluator != "undefined") {
		
		oXmlNs = oXmlNs || {};
		
		var nsResolver = function (sPrefix) {
			return oXmlNs[sPrefix];
		};
		
		var oEvaluator = new XPathEvaluator();
		var oResult = oEvaluator.evaluate(sXPath, oRefNode, nsResolver, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
		
		var aNodes = new Array;
		
		if (oResult != null) {
			var oElement = oResult.iterateNext();
			while(oElement) {
				aNodes.push(oElement);
				oElement = oResult.iterateNext();
			}
		}
		
		return aNodes;
	
	} else if (zXml.useActiveX) {
		if (oXmlNs) {
			var sXmlNs = "";
			
			for (var sProp in oXmlNs) {
				sXmlNs += "xmlns:" + sProp + "=\'" + oXmlNs[sProp] + "\' ";
			}
			
			oRefNode.ownerDocument.setProperty("SelectionNamespaces", sXmlNs);
		}
		
		return oRefNode.selectNodes(sXPath);
		
  } else {
		throw new Error("Motor XPath no encontrado.");
	}
};

//--------------------------------------------------------------------------------------------------------
// Selecciona el primer nodo encontrado en la expresión XPath
// Parametro: oRefNode, Nodo a partir del cual se evalua la expresión.
// Parametro: sXPath, la expresión XPath
// Parametro: oXmlNs, Un objeto que contiene el nombre usado un la expresión.
// Devuelve: Un nodo XML correspondiente a la expresión o null en caso de que no se encuentre resultado.
//--------------------------------------------------------------------------------------------------------
zXPath.selectSingleNode = function (oRefNode, sXPath, oXmlNs) {
	if (typeof XPathEvaluator != "undefined") {            
		
		oXmlNs = oXmlNs || {};
		
		var nsResolver = function (sPrefix) {
			return oXmlNs[sPrefix];
		};
		
		var oEvaluator = new XPathEvaluator();
		var oResult = oEvaluator.evaluate(sXPath, oRefNode, nsResolver,
																			XPathResult.FIRST_ORDERED_NODE_TYPE, null);
		
		if (oResult != null) {
			return oResult.singleNodeValue;
		} else {
			return null;
		}
	
	} else if (zXml.useActiveX) {
		if (oXmlNs) {
			var sXmlNs = "";
			for (var sProp in oXmlNs) {
				sXmlNs += "xmlns:" + sProp + "=\'" + oXmlNs[sProp] + "\' ";
			}
			
			oRefNode.ownerDocument.setProperty("SelectionNamespaces", sXmlNs);
		}    
		
    return oRefNode.selectSingleNode(sXPath);
		
	} else {
		throw new Error("Motor XPath no encontrado.")
	}
};

//----------------------------------------------------
// Serializando XML
//----------------------------------------------------
function zXMLSerializer() {}

//-----------------------------------------------------------------
// Serializa el nodo XML dado a una cadena XML
// Parametro: oNode, El nodo XML a serializar.
// Devuelve una cadena XML
//-----------------------------------------------------------------
zXMLSerializer.prototype.serializeToString = function (oNode) {
	
	var sXml = "";
	
	switch (oNode.nodeType) {
		case 1: //element
			sXml = "<" + oNode.tagName;
			
			for (var i=0; i < oNode.attributes.length; i++) {
				sXml += " " + oNode.attributes[i].name + "=\"" + oNode.attributes[i].value + "\"";
			}
			
			sXml += ">";
			
			for (var i=0; i < oNode.childNodes.length; i++){
				sXml += this.serializeToString(oNode.childNodes[i]);
			}
			
			sXml += "</" + oNode.tagName + ">";
			break;
            
		case 3: //text node
			sXml = oNode.nodeValue;
			break;
		case 4: //cdata
			sXml = "<![CDATA[" + oNode.nodeValue + "]]>";
			break;
		case 7: //processing instruction
			sXml = "<?" + oNode.nodevalue + "?>";
			break;
		case 8: //comment
			sXml = "<!--" + oNode.nodevalue + "-->";
			break;
		case 9: //document
			for (var i=0; i < oNode.childNodes.length; i++){
				sXml += this.serializeToString(oNode.childNodes[i]);
			}
			
			break;
	}  
	
	return sXml;
};