/**
*
* Librería AjacLib v 1.0
*
* Realiza peticiones AJAZ de manera sencilla y automática
*
*/

/** Especificar opciones para tipoRespuesta
*/

var $tipo = {
		XML: 0,
		TEXTO: 1,
		JSON: 2
}

/** Especificar opciones para método
*/

var $metodo = {
		GET: "GET",
		POST: "POST"
}


/**
* Realizar un nuevo requerimiento AJAX a la url específica
* con las opciones dificinas
* @param {String} url		La URL donde realizar la perición
* @param {Object} opciones	Un objeto JSON con los atributos opcionales
* 							que queremos definirle.
*
* Opciones disponibles:
* 	id:				Un identificador interno para ser recibido junto a los datos.
* 	metodo:			$metodo.POST o $metodo.GET
* 	tipoRespuesta:	$tipo.TEXTO, $tipo.JSON o $tipo.XML
* 	parametros:		Un string en formato URL o un objeto Hash.
* 	cache:			true o false
* 	avisoCargando:	Define el id de un elemento que queremos usar como cartel de
* 					"Cargando" mientras la petición se hace.
* 	onfinish:		Función a ejecutarse cuando se recivan los datos. Esta función
* 					recibirá el Texto, JSON o XML recibido y el id de la petición.
* 	onerror:		Función a ejecutarse cuando se produzca un error. Esta función
*					recibe un objeto con detalles del error y el ide de la petición. 									
*/

function $Ajax(url, opciones) {
	// Preguntar si no quiere Caché
	if (__$P(opciones, "cache", true)==false){
		// Agregar un parámetro random a la URL.
		// Poner ? o & según la presencia de parámetros anteriores.
		var caracter = "?";
		if(url.indexOf("?")>0) caracter = "&";
		url += caracter + Math.random();
	}
	var metodo = __$P(opciones, "metodo", $metodo.GET);
	var parametros = __$P(opciones, "parametros");
		
	// Generar JSON de propiedades necesarias para Prototype.
	// En un futuro puede ser reemplazado por otra librería.
	var protoOpc = {
			method: metodo,
			onSuccess: __$AjaxRecibir.bind(this, opciones),
			onException: __$AjaxError.bind(this, opciones),
			onFailure: __$AjaxError.bind(this, opciones)
	}
	
	// Si se definieron los parámetros los agregamos.
	if (parametros != undefined) {
		protoOpc.parameters = parametros;
	}
	
	// Generar la nueva petición Prototype.
	var peticion = new Ajax.Request(url, protoOpc);
	
	// Prender el cartel Cargando, si existiera.
	if (__$P(opciones, "avisoCargando") != undefined) {
		__$AjaxCargando(opciones.avisoCargando, true);
	}
}

/**
 * Función interna que se encarga de recibir la petición lista
 * desde Prototype y ejecutar el evento onfinish de la petición
 */
function __$AjaxRecibir(opciones, xhr){
	// Si se ejecuta este método estamos seguros de que
	// readyState == 4 y status == 200
	
	// Apagar cartel de Cargando si existiera.
	if(__$P(opciones, "avisoCargando")!=undefined){
		__$AjaxCargando(opciones.avisoCargando, false);
	}
	
	// Traer la función onfinish si fue definida.
	var funcionRetorno = __$P(opciones, "onfinish");
	
	// Traer el identificador de la petición si fue definida.
	var id = __$P(opciones, "id");
	
	if(funcionRetorno!=undefined){
		// Si el usuario indicó que quiere recibir la respuesta
		// Suponer TEXTO como tipo por defecto.
		var tipoRespuesta = __$P(opciones, "tipoRespuesta", $tipo.TEXTO);
		switch(tipoRespuesta){
		case $tipo.TEXTO:
			funcionRetorno(xhr.responseText, id);
			break;
		case $tipo.XML:
			funcionRetorno(xhr.responseXML, id);
			break;
		case $tipo.JSON:
			// Intentar evaluar el JSON por si no es válido.
			var objeto;
			try {
				objeto = xhr.responseText.evalJSON();
			} catch(e) {
				__$AjaxError(opciones, xhr, {code: -1, message: "JSON no válido"});
				return
			}
			funcionRetorno(objeto, id);
		}
	}
}

/**
 * Función interna que se encarga de prender o apagar el cartel
 * de Cargando, si existiera
 */
function __$AjaxCargando(cartel, prender){
	if(prender){
		$(cartel).show();
	}else{
		$(cartel).hide();
	}
}

/**
 * Función interna que se encarga de recibir la ejecución cuando se produzca
 * algún error en la petición desde Prototype.
 */
function __$AjaxError(opciones, xhr, excepcion) {
	// Apagar cartel de Cargando si existiera.
	if (__$P(opciones, "avisoCargando") != undefined) {
		__$AjaxCargando(opciones.avisoCargando, false);
	}
	
	// Cuando se trata de un error de servidor, no hay excepción.
	if (excepcion==undefined) {
		// Supongo error de HTTP, genero mensaje propio.
		excepcion = {code: xhr.status, message: "Error del servidor"};
	}
	
	// Consultar si estaba definido el evento onerror.
	var funcionError = __$P(opciones, "onerror");
	if (funcionError != undefined) {
		funcionError(excepcion, __$P(opciones, id));
	}
}

/**
 * Función interna que se encarga de entregar un parámetro opcional
 * desde una colección tipo JSON, con un valor por defecto
 */
function __$P(coleccion, parametro, defecto){
	if(coleccion==undefined){
		return defecto;
	}else{
		if(coleccion[parametro]==undefined){
			return defecto;
		}else{
			return coleccion[parametro];
		}
	}
}
