
/**
 * TESTAR NOS NAVEGADORES, PUBLICAR + divulgar
 *
 * @author Rodrigo Alegre - www.rodrigoalegre.com.br
 * @version 1.0
 *
 * RAJAX
 * Class for working AJAX requests
 * UTF-8
 *
 * Working on:
 *  - Google Chrome 4.0.223.5 (Linux Ubuntu 9.10)
 *  - Google Chrome 2.0.172.43 (Windows XP Professional 2002 SP3, Windows Vista Home Premium SP1)
 *  - Windows Internet Explorer 8.0.6001.18702 (Windows XP Professional 2002 SP3, Windows Vista Home Premium SP1)
 *  - Apple Safari 4.0.3 (531.9.1) (Windows XP Professional 2002 SP3, Windows Vista Home Premium SP1)
 *  - Opera 10.01 4682 (Windows XP Professional 2002 SP3, Windows Vista Home Premium SP1)
 *  - Opera 9.64 10487 (Windows XP Professional 2002 SP3, Windows Vista Home Premium SP1)
 *  - Mozilla Firefox 3.5.4 (Linux Ubuntu 9.10)
 *  - Mozilla Firefox 3.0.14 (Windows XP Professional 2002 SP3, Windows Vista Home Premium SP1)
 *
 * To work, the only obligation is to instantiate the class and enter a destination.
 *
 * Sorry for my english ;)
 *
 */

/**
 * Start class creating a connection.
 */
function RAJAX(){

    this.varDestination = false;
    this.varSendMode = "POST";
    this.varReturnMode = "TXT";
    this.varParameters = false;
    this.varParametersForm = false;
    this.varAsynchronous = true;
    this.varIdLoader = false;
    this.varIdLoaderLine = false;
    this.varSafeMode = false;
    this.varSafeModeAlert = false;
    this.varLine = false;
    this.varLineInLoader = false;
    this.varLineExecution = false;
    this.arrLine = new Array();
    this.funLoading = false;
    this.funResponse = false;
    this.funCancel = false;

    var fixVarDestination = false; // Fix error when changing the characteristics of the application in a single connection

    try {
        this.connection = new XMLHttpRequest();
    } catch (e){
        try {
            this.connection = new ActiveXObject("Msxml2.XMLHTTP");
        } catch (ee){
            try {
                this.connection = new ActiveXObject("Microsoft.XMLHTTP");
            } catch (eee){
                this.connection = false;
            }
        }
    }

    if (!this.connection){
        this.showError("Browser not support AJAX.");
    }

}

RAJAX.prototype = {

    /**
     * Execute the request.
     */
    execute : function(){

        if (!this.varDestination){

            this.showError("Destination not configurated.");

        } else if (!this.varLine && this.varSafeMode && this.connection.readyState != 0 && this.connection.readyState != 4){

            if (this.varSafeModeAlert){
                this.showError("Processing, please wait.");
            }

        } else if (!this.varLineExecution && this.varLine && this.connection.readyState != 0 && this.connection.readyState != 4){

            this.arrLine.push({
                varDestination : this.varDestination,
                varSendMode : this.varSendMode,
                varReturnMode : this.varReturnMode,
                varParameters : this.varParameters,
                varParametersForm : this.varParametersForm,
                varAsynchronous : this.varAsynchronous,
                varIdLoader : this.varIdLoader,
                funLoading : this.funLoading,
                funResponse : this.funResponse,
                funCancel : this.funCancel,
                varSafeMode : this.varSafeMode,
                varSafeModeAlert : this.varSafeModeAlert
            });

        } else {

            if (this.varLineExecution){
                this.varLineExecution = false;
            }

            if (this.varParametersForm){
                this.getParametersForm(this.varParametersForm);
            }

            if (this.varParameters && this.varSendMode == "GET"){
                this.connection.open(this.varSendMode, this.varDestination + "?" + encodeURI(this.varParameters), this.varAsynchronous);
            } else {
                this.connection.open(this.varSendMode, this.varDestination, this.varAsynchronous);
            }

            if(typeof this.funResponse == "function"){

                if(typeof this.funLoading == "function"){
                    this.funLoading.call();
                }

                if (this.varIdLoader){
                    this.showLoader();
                }

                var TC = this;

                fixVarDestination = this.varDestination; // Fix error when changing the characteristics of the application in a single connection

                this.connection.onreadystatechange = function(){
                    if(TC.connection.readyState == 4){
                        if (TC.varIdLoader){
                            TC.hideLoader();
                        }
                        if (TC.connection.status == 200 || TC.connection.status == 0){
                            TC.funResponse.call();
                            TC.connection.abort();
                            if (TC.arrLine.length){
                                TC.varLineExecution = true;
                                TC.varDestination = TC.arrLine[0].varDestination;
                                TC.varSendMode = TC.arrLine[0].varSendMode;
                                TC.varReturnMode = TC.arrLine[0].varReturnMode;
                                TC.varParameters = TC.arrLine[0].varParameters;
                                TC.varParametersForm = TC.arrLine[0].varParametersForm;
                                TC.varAsynchronous = TC.arrLine[0].varAsynchronous;
                                TC.varIdLoader = TC.arrLine[0].varIdLoader;
                                TC.funLoading = TC.arrLine[0].funLoading;
                                TC.funResponse = TC.arrLine[0].funResponse;
                                TC.funCancel = TC.arrLine[0].funCancel;
                                TC.varSafeMode = TC.arrLine[0].varSafeMode;
                                TC.varSafeModeAlert = TC.arrLine[0].varSafeModeAlert;
                                TC.arrLine.shift();
                                TC.execute();
                            }
                        } else {
                            TC.showError(TC.getFailureDescription());
                        }
                    }
                };

            }

            this.connection.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
            this.connection.setRequestHeader("Cache-Control", "no-store, no-cache, must-revalidate");
            this.connection.setRequestHeader("Cache-Control", "post-check=0, pre-check=0");
            this.connection.setRequestHeader("Pragma", "no-cache");

            if (this.varParameters && this.varSendMode == "POST"){
                this.connection.send(encodeURI(this.varParameters));
            } else {
                this.connection.send(null);
            }

        }

        if (this.varLineInLoader){
            if (this.arrLine.length){
                document.getElementById(this.varIdLoaderLine).style.display = "inline";
                document.getElementById(this.varIdLoaderLine).innerHTML = "&nbsp;(in line " + this.arrLine.length + ")";
            } else {
                document.getElementById(this.varIdLoaderLine).style.display = "none";
            }
        }

    },

    /**
     * Cancel the request.
     */
    cancel : function(){
        if (this.varIdLoader){
            this.hideLoader();
        }
        this.connection.onreadystatechange = function(){};
        this.connection.abort();
        if(typeof this.funCancel == "function"){
            this.funCancel.call();
        } else {
            this.showError("Canceled.");
        }
    },

    /**
     * Creates random Ids used in loaders.
     */
    createId : function(){
        function randomNumber(a){
            return (Math.floor(Math.random() * a + 1));
        }
        return "loader" + randomNumber(100) + randomNumber(100) + randomNumber(100);
    },

    /**
     * Informs the page that will communicate.
     * @param destination Page path
     */
    setDestination : function(destination){
        this.varDestination = destination;
    },

    /**
     * Informs the mode of transmission information.
     * @param sendMode Can be used "GET" or "POST"
     */
    setSendMode : function(sendMode){
        this.varSendMode = sendMode;
    },

    /**
     * Tells how to return the information.
     * @param returnMode Can be used "XML" or "TXT"
     */
    setReturnMode : function(returnMode){
        this.varReturnMode = returnMode;
    },

    /**
     * Whether a communication will be asynchronous or synchronous.
     * @param asynchronous Skip "true" for asynchronous, false for synchronous
     */
    setAsynchronous : function(asynchronous){
        this.varAsynchronous = asynchronous;
    },

    /**
     * Parameters to send.
     * @param parameters Enter the parameters separated by "&" (ex: name=Rodrigo&city=Sorocaba)
     */
    setParameters : function(parameters){
        this.varParameters = parameters;
    },

    /**
     * Mount the URI automatically from a form.
     * @param form Form name
     */
    setParametersForm : function(form){
        this.varParametersForm = form;
    },

    /**
     * Informs whether or not to work with queue.
     * @param withLine Enter "true" to work with line and "false" to not work
     * @param showInLoader Enter "true" if you want the line appears on the loader and "false" to not display
     */
    setLine : function(withLine, showInLoader){
        this.varLine = withLine;
        this.varLineInLoader = showInLoader;
    },

    /**
     * Determine whether you want to work in safe mode.
     * If you work in safe mode, a new request will not "kill" the request in progress.
     * @param safeMode Enter "true" to enable and "false" to disable
     * @param alert Enter "true" to see a message warning that have a request in progress and "false" to not display anything
     */
    setSafeMode : function(safeMode, alert){
        this.varSafeMode = safeMode;
        this.varSafeModeAlert = alert;
    },

    /**
     * Function you want to run during the progress of the request.
     * @param theFunction Function you want to run
     */
    setLoadingFunction : function(theFunction){
        this.funLoading = theFunction;
    },

    /**
     * Function you want to run to the end of the request.
     * @param theFunction Function you want to run
     */
    setResponseFunction : function(theFunction){
        this.funResponse = theFunction;
    },

    /**
     * Function you want to run if a request is canceled.
     * @param theFunction Function you want to run
     */
    setCancelFunction : function(theFunction){
        this.funCancel = theFunction;
    },

    /**
     * Create a default loader.
     * @param y Vertical positioning based on the top
     * @param x Horizontal positioning based on the left
     * @param message Message to appear in the loader
     * @param image Image that will appear in the loader
     */
    setLoaderDefault : function(y, x, message, image){
        this.varIdLoader = this.createId();
        this.varIdLoaderLine = this.createId();
        var divLoader = "<div id=\"" +this.varIdLoader+ "\" style=\"position: absolute; top: " +y+ "px; left: " +x+ "px; z-index: 99999; visibility: hidden; padding: 5px; font-family: Arial, sans-serif; font-size: 11px; border: 1px solid #FFCC66; background-color: #FFEBC1\">";
        if (image){
            divLoader += "<img src=\"" +image+ "\" alt=\"\" />&nbsp;";
        }
        if (message){
            divLoader += message;
        }
        divLoader += "<span id=\"" +this.varIdLoaderLine+ "\" style=\"font-family: Arial, sans-serif; font-size: 10px\"></span></div>";
        document.write(divLoader);
    },

    /**
     * Creates a loader based on a CSS class.
     * @param classLoader Name of a CSS class
     */
    setLoaderClass : function(classLoader){
        this.varIdLoader = this.createId();
        this.varIdLoaderLine = this.createId();
        document.write("<div id=\"" +this.varIdLoader+ "\" class=\"" +classLoader+ "\"><span id=\"" +this.varIdLoaderLine+ "\" style=\"position: relative; top: 3px; left: 3px; font-family: Arial, sans-serif; font-size: 10px\"></span></div>");
        //setTimeout(this.hideLoader(), 1000);
    },

    /**
     * Returns the response (XML or TXT).
     */
    getResponse : function(){
        if (this.varReturnMode == "TXT"){
            return this.connection.responseText;
        } else {
            return this.connection.responseXML;
        }
    },

    /**
     * Describes a possible failure.
     */
    getFailureDescription : function(){
        //switch (this.connection.status){
        //case 0: return "";
        //case 400: return "400: Bad Request."; break;
        //case 401: return "401: Unauthorized."; break;
        //case 403: case 404: return "404: Not Found."; break;
        //case 405: return "405: Method Not Allowed."; break;
        //case 408: return "408: Request Timeout."; break;
        //case 414: return "414: Request-URI Too Long."; break;
        //case 500: return "500: Internal Server Error."; break;
        //case 503: return "503: Service Unavailable."; break;
        //default: return this.connection.status +": " + this.connection.statusText; break;
        //}
        return this.connection.status +": " + this.connection.statusText;
    },

    /**
     * Get all fields in a form and prepare to send.
     * @param form Form name
     */
    getParametersForm : function(form){

        if (!document.forms[form]){

            this.showError("Form not found.");

        } else {

            var parameters = new Array();
            var formElements = document.forms[form].elements;

            for(var r = 0; r < formElements.length; r++) {

                if(!formElements[r].name){
                    continue;
                }

                if(formElements[r].disabled){
                    continue;
                }

                var tipo = formElements[r].type.toLowerCase();

                if(tipo != "checkbox" && tipo != "radio"){
                    parameters[parameters.length] = formElements[r].name + "=" + formElements[r].value;
                } else if(formElements[r].checked){
                    parameters[parameters.length] = formElements[r].name + "=" + formElements[r].value;
                }

                this.varParameters = parameters.join("&");

            }

        }

    },

    /**
     * Returns the generated Id to a loader.
     */
    getIdLoader : function(){
        return this.varIdLoader;
    },

    /**
     * Function to get the request of destination.
     */
    getDestination : function(){
        return fixVarDestination; // Fix error when changing the characteristics of the application in a single connection
    },

    /**
     * Shows the error messages.
     * @param message Error message
     */
    showError : function(message){
        alert("AJAX\n\n" +message);
    },

    /**
     * Shows the loader.
     */
    showLoader : function(){
        document.getElementById(this.varIdLoader).style.visibility = "visible";
        document.getElementById(this.varIdLoader).style.zIndex = "99999";
    },

    /**
     * Hide loader.
     */
    hideLoader : function(){
        document.getElementById(this.varIdLoader).style.visibility = "hidden";
        document.getElementById(this.varIdLoader).style.zIndex = "-99999";
    }

};