
/**
* JSR Class
* Perform http request and get the response
* Use together with CBDJSR, and CBDJSRService
*
* // common
* @var mixed    onload      String or function to be called on load
* @var object   results     Conatins the returned jsrActionsResult - assoc array with key = the action name and value = the action(method) result
*
* // the call parameters
* @var string   file        JSR class / file
* @var mixed    actions     Single or array of JSR actions (the required server actions)
* @var array    params      jsrParams to be passed to the action method
*
* // aditional vars
* @var string   responseText  The full server response as plain text
* @var string   responseObj   The full server response as js text
*
* // options
* @var array    options     JSR Class options
*                           (url, method, param, actionsParam, paramsParam, resultsKey)
*                           The most important is probably the url.
*                           They ususally don't need aditional configuration.
*
*
*
* SYNOPSYS:
* <code>
*    var oJsr = new Jsr();
*    oJsr.onload = jsrLoadHandler;
*    actions = 'someDump';
*    params = {'param1': 'value 1', 'param2': 'value 2'};
*    oJsr.call(file, actions, params);
*    function jsrLoadHandler(oThis) {
*        if (! oThis.results) {
*            alert("Server Error!\n" + oThis.responseText);
*        } else {
*            var res = oThis.results.getDump;
*            alert("OK! response:\n" + ((typeof(res.toSource) == 'function')? res.toSource() : oThis.responseText));
*            alert("res date: " + res.date);
*        }
*    }
*
* // Together with php JSR framework this will:
* // call the "someDump" action in from file jsr/test.php and
* // return object results (results.someDump contain the action method result)
* </code>
*
*/
function Jsr(options)
{
    // import options || defaults
    this.options = {};
    this.options.url = this.options.url || BDP.site + '/jsr.php';
    this.options.method = this.options.method || 'POST';
    this.options.classParam = this.options.param || 'jsrClass',
    this.options.actionsParam = this.options.actionsParam || 'jsrActions',
    this.options.paramsParam = this.options.paramsParam || 'jsrParams',
    this.options.resultsKey = this.options.resultsKey || 'jsrActionsResult',

    // some atrs
    this.file;
    this.actions;
	this.params;

    this.onload;
	this.responseText;
	this.responseObj;

	this.results;
	this.msg;

	this.onresults;

	this.onerror;
	this.errorMsg;
	this.errorDesc;

	// http obj
	this._domHttp = null;
    this._xmlHttp = getXmlHttp();
    if (!this._xmlHttp) {
        // try dynamic load
        if (typeof(DomHttp) == 'undefined') {
            var src = "domhttp.js";
            var tScripts = document.getElementsByTagName('script');
            for (var i=0; i<tScripts.length; i++) {
                if (tScripts[i].src) {
                    var pos = tScripts[i].src.indexOf('jsr.js');
                    if (pos > -1) {
                        src = tScripts[i].src.substr(0, pos) + src;
                        break;
                    }
                }
            }
            var script = document.createElement('script');
            script.id = 'domhttp';
            script.type = 'text/javascript';
            script.src = src;
            document.getElementsByTagName('head')[0].appendChild(script);
        }

    }

    // ready state
	this.isReady = true;
}
Jsr.prototype.call = function (file, actions, params) {
    // occupied
    this.isReady = false;

    // import params
    this.file = file;
    this.actions = actions;
    this.params = params;

    // clear old
    this.responseText = undefined;
    this.responseObj = undefined;
    this.results = undefined;
	this.msg = undefined;
    this.errorMsg = undefined;
    this.errorDesc = undefined;

    // prapare data
    var data = {};
    data[this.options.classParam] = this.file;
    data[this.options.actionsParam] = this.actions;
    data[this.options.paramsParam] = this.params;

    // params
    data = toPhpQueryString(data);
    var url = this.options.url;
    if (this.options.method == 'GET') {
        url += "?" + data;
        data = null; 
    } 
    
    // make request (use xmlHttp, domHttp on fail) and call onload
    var oThis = this;
    if (this._xmlHttp) {
        this._xmlHttp.open(this.options.method, url, true);
        this._xmlHttp.onreadystatechange = function () {
            if (oThis._xmlHttp.readyState == 4) {
                oThis.responseText = oThis._xmlHttp.responseText;
                try {
        		  eval("var res = " + oThis.responseText.replace(/\n/g, ""));
                } catch (e) {
                    var res = false;
                    var desc = "Eval error: " + e.message;
                }
                if (typeof(res) == "object") {
                    oThis.responseObj = res;
                    oThis.results = res[oThis.options.resultsKey];
                    oThis.fireAction('onresults');
                } else {
                    oThis.error("The server didn't return a valid object", desc);
                }
                oThis.fireAction('onload');
                oThis.isReady = true;
            }
        }
        try {
            this._xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
            this._xmlHttp.send(data);
        } catch (e) {
            this.error("Couldn't send the request", e.message);
        }
    } else if (typeof(DomHttp) != 'undefined') {
        if (! this._domHttp) {
            this._domHttp = new DomHttp(this.options.url);
        }
        this._domHttp.onload = function () {
            oThis.responseText = oThis._domHttp.response_src;
            oThis.responseObj = oThis._domHttp.response_obj;
            oThis.results = oThis.responseObj[oThis.options.resultsKey];
            if (oThis.results) {
                 oThis.fireAction('onresults');
            } else {
                 oThis.error("Ivalid domhttp server response");
            }
            oThis.fireAction('onload');
            oThis.isReady = true;
        }
        this._domHttp.request(data);
    } else  {
        this.error('HTTP transporter not available.');
    }
}
Jsr.prototype.error = function (msg, desc) {
    this.errorMsg = msg;
    this.errorDesc = desc;
    this.fireAction('onerror');
}
Jsr.prototype.fireAction = function (action) {
	if	(typeof this[action] == "string")		this[action] = new Function(this[action]);
	if 	(typeof this[action] == "function")		this[action](this);
}

function getXmlHttp () {
    var xmlhttp;
    /*@cc_on @*/
    /*@if (@_jscript_version >= 5)
      try {
      xmlhttp=new ActiveXObject("Msxml2.XMLHTTP");
     } catch (e) {
      try {
        xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
      } catch (E) {
       xmlhttp=false;
      }
     }
    @else
     xmlhttp=false
     @end @*/
    if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
    	try {
    		xmlhttp = new XMLHttpRequest();
    	} catch (e) {
    		xmlhttp=false;
    	}
    }
    if (!xmlhttp && window.createRequest) {
    	try {
    		xmlhttp = window.createRequest();
    	} catch (e) {
    		xmlhttp = false;
    	}
    }
    return xmlhttp;
}

if (!window.toPhpQueryString) {
/**
* Convert js object to query string for PHP
* Handles all data structures recursivly.
*
* @param obj js obj ({key: value})
* @return string
*/
function toPhpQueryString (obj) {
	var pairs = [];
	var data = toPhpQueryStringPairs (obj);
	for (var key in data) {
		pairs[pairs.length] = key + "=" + (typeof(data[key]) == "undefined"? "" : encodeURIComponent(data[key]));  //escape(data[key]);
	}
	return pairs.join("&");
}

function toPhpQueryStringPairs (data) {
	if(!data) return {};

	var qs_pairs = {}; //new Array();
	for (var path in data) {
		var value = data[path];
		if (typeof(value) == 'object') {
		    for (var subpath in value) {
				qs_pairs[ path+"[" +subpath+ "]" ] = value[subpath];
			}
		} else {
		    qs_pairs[path] = value;
		}
	}

	for (var key in qs_pairs) {
		if (typeof(qs_pairs[key]) == 'object') {
			qs_pairs = toPhpQueryStringPairs(qs_pairs);
		}
	}

	return qs_pairs;
}
}