﻿// JScript File
/**
*
*   Librería AjaxLib v 1.0
*
*   Realiza peticiones AJAX de manera sencilla y automática.
*
*   @autor Francisco J. Alvarez - alvarez.francisco@enchanting-group.com
*
*/

/** Especifica opciones para tipoRespuesta
*/
var $tipo = {
    XML: 0,
    TEXTO: 1,
    JSON:2
}

/** Especifica opciones para método
*/
var $metodo = {
    GET: "GET",
    POST: "POST"
}

/** 
* Realiza un nuevo requerimiento AJAX a la url especificada
* con las opciones definidas
* @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 recibidos 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 reciban 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 id de la petición.
*/

function $Ajax(url, opciones){
    // Preguntamos si no quiere Caché
    if(__$P(opciones, "cache", true) == false){
        // Agregamos un parámetro random a la URL
        // Ponemos ? 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");
    
    // Genera 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;
    }
    
    // Genera la nueva petición vía Prototype
    var peticion = new Ajax.Request(url, protoOpc);
    
    // Prende el cartel de 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 nuevo onfinish de la petición
*/
function __$AjaxRecibir(opciones, xhr){
    // Si se ejecuta este método estamos seguros de que
    // readyState == 4 y status == 200
    
    // Apagamos cartel de Cargando si existiera
    if (__$P(opciones, "avisoCargando")!= undefined){
        __$AjaxCargando(opciones.avisoCargando, false);
    }
    
    // Traemos la función onfinish se fe definida
    var funcionRetorno = __$P(opciones, "onfinish");
    
    // Traemos el identificador de la petición se fue definido
    var id = __$P(opciones, "id");
    
    if (funcionRetorno != undefined){
        // Si el usuario indicó que quiere recibir la respuesta
        // 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 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){
    // Apagamos 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"}
    }
    
    // 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 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];
        }        
    }
}