/**
*   Swingjax AJAX Class
*
*   Copyright(c)2009 SwingNote LLC. All Rights Reserved.
*
*   Terms: You may freely use this source code in both
*   commercial and non-commercial applications, provided
*   all copyright notices remain intact.
*
*   Author:     Markus Diersbock <markus@swingnote.com>
*   Class:      Swingjax
*   Revisions:  2009/11/13 Created
*               2011/03/17 Bug fixes
*
*   Use: http://www.swingnote.com/downloads/swingjax_example.htm           
*/

var Swingjax = function () {

    /*
        Private Properties
    */
    
    var _ver = "1.2.2";
    
    // connection object
    var _xhr = null;
    
    // data to package
    var _parameterData = "";
    
    // http||https
    var _sendProtocol = "http";
    
    // requested file location
    var _requestPath = "";       
    
    // requested file
    var _requestFile = "";       

    
    /*
        Private Methods
    */
    
    /**
    *   Method:         _encodeVars
    *   Description:    encodes values in string of name/value pairs
    *   Parameters:     vars_in     string to encode
    *   Returns:        list of name/value pairs with values encoded
    */

    function _encodeVars(vars_in) {     
        var rtn = "";
        var i = 0;

        if (vars_in.length) {
            var vars_ary = vars_in.split("&");

            for (i in vars_ary) {
                var tmp_ary = vars_ary[i].split("=");
                rtn += tmp_ary[0] + "=";
                if (tmp_ary[1] !== undefined) {
                  rtn += encodeURIComponent(tmp_ary[1]);
                }
            }
        }

        return rtn;
    }          

    /**
    *   Method:         _createXHR
    *   Description:    creates XMLRequestObject
    *   Parameters:     n/a
    *   Returns:        XMLRequestObject
    */

    function _createXHR() {
        try {
            _xhr = new XMLHttpRequest();
            return;
        } catch (e) {}
        
        try {
            _xhr = new ActiveXObject("Msxml2.XMLHTTP");
            return;
        } catch (e) {}
        
        try {
            _xhr = new ActiveXObject("Microsoft.XMLHTTP");
            return;
        } catch (e) {
            _xhr = null;
            this.isError = true;
            this.errorDetail += "xhr Creation: " + e.message + "|";
        }
    }     

    /*
        Interface to Class Properties and Methods Aggregate
    */
    
    var _interface = {

        /*
            Public Properties
        */
        
        version: _ver,

        // transaction method GET||POST
        sendMethod: "GET",

        // async true||false
        isAsync: true,

        // response received as text
        responseText: "",

        // response received as xml
        responseXML: "",

        // text of transaction status
        transactionStatus: "",

        // error true||false
        isError: false,

        // error details delimited by pipe
        errorDetail: "",

        
        /*
            Public Events for Binding
        */
        
        // fires when requests are in process
        onProcessing: function () {},   
        
        // fires when request is complete
        onCompletion: function () {},
        
        
        /*
            Public Methods
        */

        /**
        *   Method:         addParameter
        *   Description:    encodes value, concats name/value to
        *                   parameters
        *   Parameters:     name_in     name
        *                   value_in    value
        *   Returns:        n/a
        */
        
        addParameter: function Swingjax_addParameter(name_in, value_in) {
            _parameterData += "&";
            _parameterData += name_in + "=" + encodeURIComponent(value_in);
        }
        ,       

        /**
        *   Method:         addParametersRaw
        *   Description:    encodes values in string of name/value
        *                   pairs, appends to parameters
        *   Parameters:     vars_in     string of one or more name/value
        *                   pairs
        *   Returns:        n/a
        */

        addParametersRaw: function Swingjax_addParametersRaw(vars_in) {
            _parameterData += "&";
            _parameterData += _encodeVars(vars_in);
        }
        ,
        
        /**
        *   Method:         addURL
        *   Description:    creates qualified url, assigns protocol
        *                   value based on optional third argument 
        *   Parameters:     url_path    path (example: www.xyz.com/abc)
        *                   url_file    file
        *                   is_ssl      (optional; defaults to false)
        *                               true||false (will convert to
        *                               https||http
        *   Returns:        n/a
        */

        addURL: function Swingjax_addURL(url_path, url_file) {
            _requestPath = url_path;
            
            // if user didn't append slash for path, do it
            if (_requestPath.substr(_requestPath.length - 1) !== "/") {
                _requestPath += "/";
            }
            
            _requestFile = url_file;
            
            // if optional 3rd argument is passed
            if (arguments.length === 3) {
                // assign protocol value based on is_ssl
                _sendProtocol = (arguments[2] === false ? "http" : "https");
            }
            
            return true;
        }
        ,
        
        /**
        *   Method:         sendRequest
        *   Description:    transmits data via GET/POST requests
        *   Parameters:     n/a
        *   Returns:        n/a
        *   
        *   Notes:          "Host" header used for proxy servers
        */
        
        sendRequest: function Swingjax_sendRequest() { 
        
            // create connection object
            try {
                _createXHR();
            } catch (e) {
               this.isError = true;
               this.errorDetail += "Create XHR: " + e.message + "|";
            }    

            // process data to send
            if (_xhr !== null) {
            
                // swing_random prevents caching
                var build_uri = _sendProtocol
                                + "://" 
                                + _requestPath
                                + _requestFile
                                + "?" 
                                + "swing_random=" + (Math.random() * 99999);
                
                switch (this.sendMethod) {
                    case "POST":
                        try {
                            _xhr.open(this.sendMethod, build_uri, this.isAsync);
                            _xhr.setRequestHeader("Host", _requestPath.split("/")[0]);
                            _xhr.setRequestHeader("User-Agent", "Swingjax");
                            _xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
                            _xhr.setRequestHeader("Content-Length", _parameterData.length);
                        } catch (e) {
                            this.isError = true;
                            this.errorDetail += "Open Conn/Set Headers (POST): " + e.message + "|";
                        }
                        break;
                        
                    case "GET":
                        try {
                            _xhr.open(this.sendMethod, build_uri + _parameterData, this.isAsync);
                            _xhr.setRequestHeader("Host", _requestPath.split("/")[0]);
                            _xhr.setRequestHeader("User-Agent", "Swingjax");
                            _xhr.setRequestHeader("Pragma", "no-cache");
                            _xhr.setRequestHeader("Cache-Control", "no-cache");
                            _xhr.setRequestHeader("Content-Type", "text/html");
                            _parameterData = null; 
                        } catch (e) {
                            this.isError = true;
                            this.errorDetail += "Open Conn/Set Headers (GET): " + e.message + "|";
                        }
                        break;
                        
                    default:
                        this.isError = true;
                        this.errorDetail += "Method Unset: " + e.message + "|"; 
                }
                
                // sending request
                try {
                    _xhr.onreadystatechange = this.responseCallback;
                    _xhr.send(_parameterData);
                } catch (e) {
                    this.isError = true;
                    this.errorDetail += "Send Request: " + e.message + "|";
                }
            }
        }
        ,
        
        /**
        *   Method:         responseCallback
        *   Description:    Processes readyState status, fires
        *                   onProcessing()/onCompletion() for callback
        *                   binding to object creator 
        *   Parameters:     n/a
        *   Returns:        n/a
        */
        
        responseCallback: function Swingjax_responseCallback() {
 
            switch (_xhr.readyState){
                case 1:
                    // fall thru
                    
                case 2:
                    _interface.transactionStatus = "Sending Request to Server";
                    _interface.onProcessing();
                    break;
                    
                case 3:
                    _interface.transactionStatus = "Awaiting Data from Server";
                    _interface.onProcessing();
                    break;
                    
                case 4:
                    // Ok
                    if (_xhr.status === 200) {
                        _interface.responseText = _xhr.responseText;
                        _interface.responseXML = _xhr.responseXML;
                        _interface.transactionStatus = "Completed";
                        _interface.onCompletion();
                    } else if (_xhr.status === 304) {
                        // # TODO Add 304 Cache functionality
                    } else {
                        _interface.isError = true;
                        _interface.errorDetail += "Response Callback: Retrieving Data|";
                        _interface.transactionStatus = "Error Retrieving Remote Data";
                    }
                    break;
            }

        }

    };
    
    // return interface
    return  _interface;
};
