JSLIB.namespace("JSLIB.connection");

JSLIB.connection = {
    debug:false,
    pendingResponseCount:0,
    
    // fetch content using XMLHttpRequest
    // method: GET or POST
    // url: url of remote script
    // callback: object with
    //     {
    //        successFunc,   // called when request completed successfully
    //        failureFunc,   // called when request failed
    //        context        // value passed to callback function
    //     }
    // where successFunc and failureFunc are callback function with one argument 'response'.
    // response is an object contains the following fields:
    //        responseText,  // response text
    //        responseXML,   // response XML object
    //        status,        // response status code
    //        statusText,    // response status text
    //        headers,       // object of response headers
    //        context        // context passed when calling the get method
    // return a handle useful for abort request
    get:function (method, url, callback, postdata) {
        if (method != "GET" &&
            method != "POST") {
            this._debug("sendRequest(): unknown method '" + method + "'");
            return false;
        }
        
        if (typeof callback != "object" ||
            typeof callback.successFunc == "undefined" ||
            typeof callback.failureFunc == "undefined" ||
            typeof callback.context == "undefined") {
            this._debug("sendRequest(): invalid callback object");
            return false;
        }
    
        var req = this._createRequest();
        if (!req) {
            this._debug("sendRequest(): unable to create request object");
            return false;
        }
        
        var handle = {
            req: req,
            url: url,
            method: method,
            callback: callback
        };
        
        req.open(method, url, true);
        req.onreadystatechange = function() {
            JSLIB.connection._onResponseStateChange(handle);
        }
        
        if (method == "GET") {
            req.send(null);
        }
        else {
            var body = "";
            if (JSLIB.util.isObject(postdata)) {
                var key;
                for (key in postdata) {
                    var value = postdata[key];
                    if (body.length > 0) {
                        body += "&";
                    }
                    body += encodeURI(key) + "=" + encodeURI(value);
                }
            }
            req.setRequestHeader('Content-Type',  'application/x-www-form-urlencoded; charset=UTF-8');
            req.send(body);
        }
        this.pendingResponseCount ++;
        return handle;
    },

    // abort request. handle is the value returned by get()
    abort:function(handle) {
        if (handle && handle.req && handle.req.abort) {
            handle.req.abort();
            handle.req = null;
        }
    },

    // private method. it is called when XMLHttpRequest readyState changed
    _onResponseStateChange:function(handle) {
        var req = handle.req;
        // nothing to process until everything loaded
        if (req.readyState < 4) {
            return;
        }
        
        // prepare the response structure for callback
        var response = {
            responseText:req.responseText,
            responseXML:req.responseXML,
            status:req.status,
            statusText:req.statusText,
            headers:this._createHeaderMap(req.getAllResponseHeaders()),
            context:handle.callback.context,
            
            getText:function(){return this.responseText;},
            getXML:function(){return this.responseXML;},
            getJSON:function(){
                    var tmpFunc = new Function("return " + this.responseText);
                    return tmpFunc();
                }
        };
        
        // calling the callback function now
        if (req.status == 200) {
            if (handle.callback.successFunc) {
                handle.callback.successFunc(response);
            }
        }
        else {
            if (handle.callback.failureFunc) {
                handle.callback.failureFunc(response);
            }
        }
        this.pendingResponseCount --;
        handle = null;
    },

    _createHeaderMap:function(headersText) {
        extractedHeaders = headersText.split("\n");
        delete extractedHeaders[extractedHeaders.length]; // Del blank line at end
        headerMap = new Array();
        for (i=0; i<extractedHeaders.length-2; i++) {
          head = extractedHeaders[i];
          fieldNameEnding = head.indexOf(":");
          field = head.substring(0, fieldNameEnding);
          value = head.substring(fieldNameEnding + 2, head.length);
          value = value.replace(/\s$/, "");
          headerMap[field] = value;
        }
        return headerMap;
    },

    _createRequest:function() {
        var req = null;
        var e;
        
        // IE7, Firefox, Safari, Opera
        try {
            req = new XMLHttpRequest();
        }
        catch (e) {};
        
        // IE < 7
        if (!req) {
            try {
                req = new ActiveXObject("Msxml2.XMLHTTP");
            }
            catch (e) {};
        }
        
        if (!req) {
            try {
                req = new ActiveXObject("Microsoft.XMLHTTP");
            }
            catch (e) {};
        }
        
        return req;
    },
    
    _debug:function(msg) {
        if (this.debug) {
            alert(msg);
        }
    }
};
 