// JavaScript Document

/*
Clase AJAX
 Creada el 29 de Agosto de 2006;
 Por: LI. Ivan Emilio Andrade Aguilar
 Version 1.2
*/

/*Cambios de version


1.0 > 1.2
* se agrega compatibiliad con objetos, se incluyen 2 metodos y 1 atributo
	AJAXClassCargada ->
	ObjetoEnvio(obj) ->
	EnviaAObjeto() ->

*/

AJAXClassCargada = true;

//Varible Global Para determinar el mensaje de error
var AJAXMensajeDeError = "Su navegador no tiene soporte para visualizar este contenido";
//Metodo a emplearse en el envio de datos
AJAXGet = "GET";
AJAXPost = "POST";

//Estados
AJAXEnvioOk = 4;
AJAXRespuestaOk = 200;
//Variables para el manejo de la informacion
AJAXDespliegaErrores=false;
AJAXClassCargada=true;
//Para pasar las variables que no estan seleccionadas
// se requieren2 valores:
//El usuario decide si se pasan o no
AJAXCamposEnviarTodos = false;
//Si eleigió envia todos los campos cual es el valor por omision
AJAXCamposValorPorOmision = -1;

AJAXVersionRevision = 1.2;


//Modos de transferencia

AJAXTransURL = 0;
AJAXTransEnt = 1;
AJAXTransCar = 2;


//Constructor de la clase
function AJAX(){
	//Valores por Omision
	//Metodo GET
	this._Metodo = AJAXPost;
	//Modo Asincrono
	this._ModoAsincrono = true;
	// Se inicializa URL
	this._URL = "";
	//Se inicializa el arreglo de parametros
	this.Parametros = new Array();
	//Se inicializa la funcion de procesamiento
	this._Funcion = false;
	//Se inicializa el objeto de respuesta HTTP
	this._HttpRequest = false;
	//Para la autenticacion
	this._Autenticacion=false;
	this._Usuario=false;
	this._Password=false;
	this._ObjetoEnvio = "";
	this._TransferenciaEnvia   = AJAXTransURL;
	this._TransferenciaProcesa = AJAXTransEnt;
	this._TransferenciaRecibe  = AJAXTransURL;
}
//Metodo de la clase que permite asignar el metodo de envio de datos
// al objeto HttpRequest
function AJAX_Metodo(strMetodo){
	//Se define el metodo
	//Se emplea unescape para obtener los datos en caso de que la informacion
	// cuente con esta tecnica de cifrado básico
	this._Metodo = unescape(strMetodo); 
}
//Metodo de la clase que establece la URL en donde se realizara la coexión del
// objeto httprequest
function AJAX_URL(strURL){
	//Se define el la URL
	//Se emplea unescape para obtener los datos en caso de que la informacion
	// cuente con esta tecnica de cifrado básico
	this._URL = unescape(strURL);
}
// Se definen lo parametros a enviar den la conexion que se realiza a través 
// del objeto HttpRequest
//Metodo que permite realizar la asignacion de la funcion que procesa el resultado
// contenido en el objeto HttpRequest.responseXML
// NOTA: La ejecución de esta funcion esta condicionada por el modo de envio
//       Generalmente se ejecuta cuando el modo Asincrono es activado.
function AJAX_Funcion(funcion){
	//Se define el la Funcion
	this._Funcion=funcion;
	}
//Metodo que crea la instancia objeto XMLHttpRequest y la asigna el objeto HttpRequest
function AJAX_CreaObjeto(){
	//Verifica si puede crearse el objeto
	this._HttpRequest = false;
	//Plataformas no IE
	if (window.XMLHttpRequest) { // Mozilla, Safari,...
    	// Crea el objeto y lo asigna al atibuto del objeto
		this._HttpRequest = new XMLHttpRequest();
		//Verifica si se puede establecer el tipo de respuesta
        if (this._HttpRequest.overrideMimeType) {
			//Establece que la respuesta se manipulara como XML
        	this._HttpRequest.overrideMimeType('text/xml');
        }
     } else if (window.ActiveXObject) { // Plataforma IE
        try {
			//Intenta crear el objeto para Veriiones anteriores a la 6.1
			this._HttpRequest = new ActiveXObject("Msxml2.XMLHTTP");
        } catch (e) { //Si no se pudo crear el objeto
        	try {
				//intenta crearlo con la libreria para 6.1+
            	this._HttpRequest = new ActiveXObject("Microsoft.XMLHTTP");
            } catch (e) {}
        }
     }
	 //Si no pudo crearse la instancia
	if (!this._HttpRequest) {
    	return false;
    }else{
		// Si pudo crearse la instancia
		return true;
	}
}
//Metodo qeu realiza la conexion en funcion de la informacion proporcionada 
function AJAX_Conecta(){
	
	
	//Implementacion para codificacion de transferencia 8/Nov/07
	//  - Inicia
	this.Parametros.Agrega("mr" ,this._TransferenciaEnvia);
	this.Parametros.Agrega("msp",this._TransferenciaProcesa);
	this.Parametros.Agrega("msr",this._TransferenciaRecibe);
	//  - Termina
	
	
	//Verifica si se pudo crear el objeto HttpRequest;
	if	(this._CreaObjeto()){
		//Se Asigna la funcion que procesará el resultado
		this._HttpRequest.onreadystatechange = this._Funcion;
		//Se leen los posibles parametros enviados
		strParametros = "";
		// se obtine la totalidad de los parametros enviados
		totalParametros = this.Parametros.length;
		//Para cada uno de los parametros
		for(i=0;i< totalParametros;i++){
				// Si no es el primer parametro se asigna & antes de inicluir el parametro
				strParametros+= (i>0) ? "&" : "";
				//Se incluye el parametro varible=valor
				// Se emplea el metodo unescape para los valores que se emplean cifrados bajo esta
				// metodo basico
				strParametros+= unescape(this.Parametros[i][0])+"="+ this.Parametros[i][1];
		}
		// Se codifican la cadena con los valores y variables para enviarse a la URL destino	
		strAdcional="";
		strEnvio="";
		strParametros = encodeURI(strParametros);
		strAdicional = (this._Metodo==AJAXGet) ? "?"+ strParametros : "";
		strEnvio = (this._Metodo==AJAXPost) ? strParametros : null;
		//Se abre la peticion de la url, con el metodo POST ys si esta es asincrona
		// Si se emplea el metodo GET
		this._HttpRequest.open(this._Metodo, this._URL+strAdicional, this._ModoAsincrono, this._Usuario, this.Password);
		if(this._Metodo==AJAXPost){
			this._HttpRequest.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
		}
		this._HttpRequest.send(strEnvio);
		
	}
	else{
		//Alerta de Error de Version de JS
		alert(AJAXMensajeDeError);
	}
}

//Metodo que regresa el objeto que contiene la respuesta XML
function AJAX_RespuestaXML(){
	// Retorna el objeto generado
	return this._HttpRequest.responseXML;
}
//Metodo que permite conocer el Estado del Envio de la Informacion
function AJAX_EstadoEnvio(){
	// Se retorna el estado
	return this._HttpRequest.readyState;
}
//Metodo que permite conocer el Estado de la respuesta de la informacion
function AJAX_EstadoRespuesta(){
	// se retorna el estado
	return this._HttpRequest.status;
}
//Metodo que permite acceder al la Respuesta XML del objeto HttpRequest a través de DOM
// Y regresa todos los nodos que contengan la etiqueta definida
function AJAX_NodosPorEtiqueta(strTag){
	//Regresa los nodos de la etiqueta definida en strTag
	return this._HttpRequest.responseXML ? this._HttpRequest.responseXML.getElementsByTagName(strTag) : false;
	}
// Metodo que establece que el modo de envio es sincrono
// Generalmente empleado para almacenar informacion a través de ajax
function AJAX_ModoSincrono(){
		// Desactiva el modo Asincrono
		this._ModoAsincrono = false;
}
// Metodo que establece que el modo de envio es Asincrono
// Generalmente empleado para consultar informacion a través de ajax
// Cuando se requiere obtener la respuesta de ajax y procesarla, es 
// necesario activar este modo
function AJAX_ModoAsincrono(){
		// Activa el modo asincrono;
		this._ModoAsincrono = true;
}

function AJAX_AlertaDatosEnvio(){
	if(AJAXDespliegaErrores){
		if (confirm("Esta por desplegar "+ this.Parametros.length+ " Mensaje(s), desea continuar")){
			for(i=0;i<this.Parametros.length;i++){
				alert(this.Parametros[i][0]+"="+this.Parametros[i][1]);
			}
		}
	}
}
	
function AJAX_Autenticar(usr,pass){
	this._Usuario = unescape(usr);
	this._Password = unescape(pass);
	this._Autenticacion = true;
}

function AJAX_NoAutenticar(){
	this._Autenticacion = false;	
}
//Agregados para el objeto array
//Complementos para objeto
function Array_AgregaCampo(elemento){
	booAgrega = true;
	var campo = "";
	var valor = "";
	if (document.getElementById(elemento)){
		obj = document.getElementById(elemento);
		switch (obj.tagName){
			case "INPUT": switch (obj.getAttribute("type")){
									case "text": campo = obj.name;
												  valor = obj.value;
												break;
									case "password": campo = obj.name;
												  valor = obj.value;
												break;
									case "radio": if (document.getElementsByName(obj.name).lenght<=1){ 
												  campo = obj.name;
												  valor = obj.value;
												  }
												  else{
													  campo = obj.name;
													  valor = false;
													  for (i=0;i<document.getElementsByName(obj.name).length;i++){
														  	valor = (document.getElementsByName(obj.name)[i].checked) ? document.getElementsByName(obj.name)[i].value : valor; 
														  }
													  }
													  booAgrega = valor;
												break;
									case "hidden": campo = obj.name;
												  valor = obj.value;
												break;
									case "checkbox":if (obj.checked){ 
														campo = obj.name;
														valor = obj.value;
													}else{
														booAgrega = false;
													}
												break;
									case "button":campo = obj.name;
												valor = obj.value;
												break;
									case "submit":campo = obj.name;
												valor = obj.value;
												break;
									case "reset":campo = obj.name;
												valor = obj.value;
												break;
									case  "file": if (AJAXDespliegaErrores){ 
													alert("No hay soporte para envio de archivos a traves de esta version de AJAXClass\n la variable ["+obj.name+"] no será enviada");
												}
												booAgrega= false;
												break;
								}
					break;
			case "SELECT": campo = obj.name;
							valor = obj.value;
					break;
			
			case "TEXTAREA":campo = obj.name;
							 valor = obj.value;
					break;
			default: alert( elemento + " no es un objeto de formulario para procesar");
			
		}
		// Si el campo se puede agrgar
		if(booAgrega){
			this.Agrega(elemento,valor);
		}else{
			//Si el usuario desea enviar los valores por omision.
			if(AJAXCamposEnviarTodos){
				this.Agrega(elemento,AJAXCamposValorPorOmision);
			}
		}
	}
	else{
		if(AJAXDespliegaErrores){
			alert("No se encontro "+ elemento + " dentro de la colección de objetos del documento actual");
		}
	}
}

function Array_Agrega(Campo,Valor){
	this[this.length]= new Array();
	this[this.length-1][0]=unescape(Campo);
	this[this.length-1][1]=unescape(this.LimpiaContenido(String(Valor)));
}
function Array_Vacia(){
	this.length = 0;	
}

function Array_AgregaDesdeFormulario(strIdFormulario){
	frmData = document.getElementById(strIdFormulario);
	for(i=0;i<frmData.elements.length;i++){
		this.AgregaCampo(frmData.elements[i].name);
	}
}

//Implementacion para interaccion con otras clases 
//Aplicado por LI Ivan Emilio Andrade Aguilar (11-May-07)
/*
Observaciones: dada la estructura y la asincronia de AJAX es dificil mantener la integracion de la clase con otras
(Subclase), con lo anterior requiere establecer conectividad.
*/

//Se debe de obtener el id del Objeto, dado que no se permite el paso por referencia, se pasa el nombre del objeto
//que invoca la peticion
function AJAX_ObjetoEnvio(strIdObjeto){
	this._ObjetoEnvio = strIdObjeto;
}

function AJAX_EnviaAObjeto(){
	//Necesariamente el objeto que emplea este metodo de recuperacion, necesita contar con un metodo llamado RecuperaAJAX(XMLDoc)
	// lo anterior para la compatibilidad con esta clase
	eval(this._ObjetoEnvio + ".RecuperaAJAX(this.RespuestaXML())");
}
function ValidaFormulario(elemento){
	if (document.getElementById(elemento)){
		var obj  = document.getElementById(elemento);
		var intTotal = obj.elements.length;
		var strSalida = "";
		var strEnter = "\n";
		for(i=0;i<intTotal;i++){
		var strLong = obj.elements[i].getAttribute("minimo");
		var strError= obj.elements[i].getAttribute("enerror");
		switch (obj.elements[i].tagName){
			case "INPUT": switch (obj.elements[i].getAttribute("type")){
							case "text":	 strSalida += obj.elements[i].value.length< parseInt(strLong) ? "- " + strError+strEnter : "";
										break;
							case "radio":	 strSalida += obj.elements[i].checked ? strSalida : "";
										break;
							case "hidden":	 strSalida += obj.elements[i].value.length< parseInt(strLong) ? "- " + strError + strEnter : "";
										break;
							/*case "checkbox":strSalida += obj.elements[i].checked ? "- " + strError : "";
										break;*/
						}
					break;
			//case "SELECT":	 strSalida += obj.elements[i].options[obj.elements[i].selectedIndex].text == "Elija" ? "- " + strError + strEnter : "";
			case "SELECT":	 strSalida += obj.elements[i].options[obj.elements[i].selectedIndex].text.search(/Elija/)>-1 ? "- " + strError + strEnter : "";
					break;
			case "TEXTAREA":strSalida += obj.elements[i].value.length< parseInt(strLong) ? "- " + strError + strEnter : "";
					break;
			
		}
	}
  }
  return strSalida;
}
//Fin de implementacion

//Implementacion para la validación de caracteres no codificables

function Array_LimpiaContenido(strContenido){
	//Para que viaje apropiadamente la informacion y al momento de recuperar sea lo mas parecido a lo que el usuario escribio originalemnte
	// Se eliminan caracteres como el acento invertido, la direresis fuera de la u el cedil etc.
	// Mismos que serán reemplazados por un espacio en blanco.
	//Para el caso de los caracteres acentuados y la ñ y ü se codifican para pasar sin problemas.
	//Se eliminan todos los caracteres no reconocibles
	strSalida = strContenido;
	//Se convierten los caracteres validos no identificados dentro del UTF-8
	strSalida = strSalida.replace(/á/g,"%25E1");
	strSalida = strSalida.replace(/é/g,"%25E9");
	strSalida = strSalida.replace(/í/g,"%25ED");
	strSalida = strSalida.replace(/ó/g,"%25F3");
	strSalida = strSalida.replace(/ú/g,"%25FA");
	strSalida = strSalida.replace(/ü/g,"%25FC");
	strSalida = strSalida.replace(/ñ/g,"%25F1");
	strSalida = strSalida.replace(/Á/g,"%25C1");
	strSalida = strSalida.replace(/É/g,"%25C9");
	strSalida = strSalida.replace(/Í/g,"%25CD");
	strSalida = strSalida.replace(/Ó/g,"%25D3");
	strSalida = strSalida.replace(/Ú/g,"%25DA");
	strSalida = strSalida.replace(/Ü/g,"%25DC");
	strSalida = strSalida.replace(/Ñ/g,"%25D1");
	strSalida = strSalida.replace(/[^a-zA-Z0-9 áéíóúñüÁÉÍÓÚÑÜ@|'*-_+=#%$().,;\n\r\t\/]+/g," ");
	return strSalida;
}

function AJAX_RecuperaNodo(strNodo, indice, objNodo){
	var objTMP =  this.NodosPorEtiqueta(strNodo);
	if(objNodo!=null){
		objTMP = objNodo.length>1 ? objNodo[indice].getElementsByTagName(strNodo) : objNodo.getElementsByTagName(strNodo) ;
		//indice = 0;
	}
	return objTMP[indice].firstChild ? unescape(objTMP[indice].firstChild.data) : false;
}

function AJAX_TotalNodos(strNodo){
	if (strNodo.indexOf){ //Es cadena?
		strNodo = this.NodosPorEtiqueta(strNodo);
	}
	return strNodo.length ? strNodo.length : false;
}

function AJAX_SugerirTransferencia(intProc, intResp){
	this._TransferenciaProcesa = intProc;
	this._TransferenciaRecibe  = intResp;
}

//Fin de la implementacion


// Declaracion de prototipos
AJAX.prototype.Metodo = AJAX_Metodo;
AJAX.prototype.URL = AJAX_URL;
AJAX.prototype.Funcion = AJAX_Funcion;
AJAX.prototype._CreaObjeto = AJAX_CreaObjeto; //Para que el usuario comun no la emplee
AJAX.prototype.Conecta = AJAX_Conecta;
AJAX.prototype.RespuestaXML = AJAX_RespuestaXML;
AJAX.prototype.EstadoEnvio= AJAX_EstadoEnvio;
AJAX.prototype.EstadoRespuesta = AJAX_EstadoRespuesta;
AJAX.prototype.NodosPorEtiqueta = AJAX_NodosPorEtiqueta;
AJAX.prototype.ModoAsincrono = AJAX_ModoAsincrono;
AJAX.prototype.ModoSincrono = AJAX_ModoSincrono;
AJAX.prototype.AlertaDatosEnvio = AJAX_AlertaDatosEnvio;
AJAX.prototype.Autenticar = AJAX_Autenticar;
AJAX.prototype.NoAutenticar = AJAX_NoAutenticar;
AJAX.prototype.ObjetoEnvio = AJAX_ObjetoEnvio;
AJAX.prototype.EnviaAObjeto = AJAX_EnviaAObjeto;
AJAX.prototype.RecuperaNodo = AJAX_RecuperaNodo;
AJAX.prototype.TotalNodos = AJAX_TotalNodos;
AJAX.prototype.SugerirTransferencia = AJAX_SugerirTransferencia;
//Para futuros metodos
//AJAX.prototype. = AJAX_;

//Implementos para Array
Array.prototype.Agrega = Array_Agrega;
Array.prototype.Vacia = Array_Vacia;
Array.prototype.AgregaCampo = Array_AgregaCampo;
Array.prototype.AgregaDesdeFormulario = Array_AgregaDesdeFormulario;
Array.prototype.LimpiaContenido = Array_LimpiaContenido;