/**
 *  Librería KAJAX (no necesita salvavidas) 
 * 
 */ 

var __KajaxCache = [];

/**
 * Genera una petición AJAX 
 */
function KAjax() {  // ********* CLASE **********

	// ***** ENUMERACIONES *****
	this.tipo = {
		XML: 1,
		TEXTO: 2,
		JSON: 3,
		HTML: 4
	}
	
	this.metodo = {
		GET: "GET",
		POST: "POST"
	}
		
	/**
	 * Ejecuta la petición
	 * @param url URL del archivo a invocar en el servidor
	 * @param opc Datos opcionales en formato JSON: metodo, funcionRespuesta, 
	 * 		parametrosPOST, tipoRespuesta, funcionError, idCargando, idRespuesta, 
	 *      cache
	 */
	this.ejecutar = function(url, opc) {
		this.opcionales = opc;
		this.cambiarCargando(true);
		this.url = url;
		
		
		var hagoPeticion;
		// Si no quiere cache forzamos URLs distintas
		if (this.$opcional("cache", false) == false) {
			// OPCION A: No quiere cache
			var separador = "?";
			if (url.indexOf("?")>0)
				separador = "&";
			url = url + separador + Math.random();
			hagoPeticion = true;
		} else {
			// OPCION B: Quiere cache
			if (__KajaxCache[url]!=undefined) {
				// OPCION B1: Quiere cache y está disponible en cache
				if (this.$opcional("funcionRespuesta")!=undefined) {
					var funcion = this.$opcional("funcionRespuesta");
					funcion(__KajaxCache[url]);
				} 
				hagoPeticion = false;
			} else {
				// OPCION B2: Quiere cache, pero no está
				hagoPeticion = true;
			}
		}
		if (hagoPeticion) {
			this.xhr.open(this.$opcional("metodo", this.metodo.GET), url, true);
			this.xhr.onreadystatechange = this.procesarReadyState.bind(this);
			// Cabecera para parámetros POST
			this.xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
			this.xhr.send(this.$opcional("parametrosPOST", null));
		}
	}
		
	// ***** FUNCIONES AUXILIARES DE LA LIBRERIA *****
	
	this.procesarReadyState = function() {
		if (this.xhr.readyState==4) {
			this.cambiarCargando(false);
			if (this.xhr.status==200) {
				this.procesarRespuesta();
			} else {
				var fError = this.$opcional("funcionError");
				if (fError!=undefined) {
					fError(this.xhr.status);
				}else{
					alert("Server Error. Please retry later.")
				}
			}
		}
	}
	
	this.procesarRespuesta = function() {
		var tipo = this.$opcional("tipoRespuesta", this.tipo.TEXTO);
		var respuesta;
		switch (tipo) {
			case this.tipo.TEXTO:
				respuesta = this.xhr.responseText;
				break;
			case this.tipo.XML:
				respuesta = this.xhr.responseXML;			
				break;
			case this.tipo.JSON:
				try {
					respuesta = eval("(" + this.xhr.responseText + ")");			
				} catch (error) {
					// JSON inválido
					var fError = this.$opcional("funcionError");
					if (fError!=undefined) {
						fError(-10, error);
					}	
					return;				
				}
				break;
			case this.tipo.HTML:
				respuesta = this.xhr.responseText;							
				idRespuesta = this.$opcional("idRespuesta");
				respuestaHtmlTipo = this.$opcional("respuestaHtmlTipo");
				if (idRespuesta!=undefined) {
					var elemento = document.getElementById(idRespuesta);
					if (elemento!=undefined) {
						if (respuestaHtmlTipo!=undefined && respuestaHtmlTipo == "replace") {
							$(elemento).replace(respuesta);
						}else{
							elemento.innerHTML = respuesta;
						}
						
					}
				}
				break;			
		}
		// Chequeo de cache
		if (this.$opcional("cache", false)==true) {
			__KajaxCache[this.url] = respuesta;
		}
		
		var funcion = this.$opcional("funcionRespuesta");
		if (funcion!=undefined) {
			funcion(respuesta);
		}
		
	}
	
	this.obtenerXHR = function() {
		return Try.these(
	      function() {return new XMLHttpRequest()},
	      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
	      function() {return new ActiveXObject('Microsoft.XMLHTTP')}
	    ) || false;

	}
	
	this.$opcional = function(queBusco, porDefecto) {
		if ((this.opcionales==undefined) || (this.opcionales[queBusco]==undefined)) {
			return porDefecto;
		} else {
			return this.opcionales[queBusco];
		}
	}
	
	this.cambiarCargando = function(prendido) {
		var id = this.$opcional("idCargando");
		if (id!=undefined) {
			var elemento = $(id);
			if (elemento!=undefined) {
				if (prendido)
					elemento.style.display = "block";
				else	
					elemento.style.display = "none";
			}
		}
	}
	
	// ***** CONSTRUCTOR ******
	this.xhr = this.obtenerXHR();
	// *** FIN CONSTRUCTOR ***
	
	
}


				  
  
