// Especifica opciones para tipoRespuesta
var $tipo = {
	XML: 0,
	TEXTO: 1,
	JSON: 2
}

// Especifica opciones para metodo
var $metodo = {
	GET: "GET",
	POST: "POST"
}

/*
@param {String} url, la URL donde realizar la petició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:		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 reciban los datos. Esta función recibirá el Texto, JSON o XML recibidos 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 ID de la petición.
*/

function $Ajax(url, opciones){

	// Si la opción de cache es FALSE
	if(__$P(opciones, "cache", true) == false){
		// Agregamos un número aleatorio a la URL
		var caracter = "?";
		if(url.indexOf("?") > 0) caracter = "&";
		url += caracter + Math.random();
	}
	
	var metodo = __$P(opciones, "metodo", $metodo.GET);
	var parametros = __$P(opciones, "parametros");

	// Genera JSON de propiedades necesarias para Prototype
	var prototypeOPC = {
		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){
		prototypeOPC.parameters = parametros;
	}

	// Genera la nueva petición vía Prototype
	new Ajax.Request(url, prototypeOPC);

	// Muestra el LOADING si existiera
	if(__$P(opciones, "avisoCargando") != undefined){
		__$AjaxCargando(opciones.avisoCargando, true);
	}
}

// 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];
		}
	}
}

//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 que readyState == 4 y status == 200
	
	// Oculta el LOADING si existiera
	if(__$P(opciones,"avisoCargando") != undefined){
		__$AjaxCargando(opciones.avisoCargando, false);
	}
	
	// Traemos la función onFinish si fue definida
	var funcionRetorno = __$P(opciones, "onFinish");
	// Traemos el identificador de la petición si fue definido
	var id = __$P(opciones, "id");
	if(funcionRetorno != undefined){
		// Suponemos 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:
				// Intentamos 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 recibir la ejecución cuando se produzca algún error en la petición desde Prototype

function __$AjaxError(opciones, xhr, excepcion){

	// Oculta el LOADING si existiera
	if(__$P(opciones, "avisoCargando") != undefined){
		__$AjaxCargando(opciones.avisoCargando, false);
	}
	// Cuando se trata de un error de servidor, no hay excepción y se asume que es HTTP
	if(excepcion == undefined){
		excepcion = {code: xhr.status, message: "Error del servidor"}
	}
	
	// Consulto 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 mostrar u ocultar el LOADING si existiera
function __$AjaxCargando(aviso, mostrar){
	if(mostrar){
		$(aviso).show();
	}else{
		$(aviso).hide();
	}
}




