
RPC = {}

RPC.GetXHR = function() {
    if (window.XMLHttpRequest) {
        try { return new XMLHttpRequest(); } catch(e) { }
    } else if (window.ActiveXObject) {
        try { return new ActiveXObject("MSXML3.XMLHTTP"); } catch (e) { }
        try { return new ActiveXObject("MSXML2.XMLHTTP.3.0"); } catch (e) { }
        try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { }
        try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { }
        try { return new ActiveXObject("Msxml2.XMLHTTP.4.0"); } catch (e) { }
    }

    throw {};
}

RPC.EncodeRequest = function(obj) {
    switch (typeof(obj)) {
        case 'string':
            return '"' + encodeURIComponent(obj) + '"';
        case 'object':
            if (obj != null) {
                switch (obj.constructor) {
                    case Array:
                        var a = new Array();
                        var n = obj.length;
                        for (var i = 0; i < n; i++) {
                            a.push(RPC.EncodeRequest(obj[i]));
                        }

                        return '[' + a.join(',') + ']';
                    default:
                        var a = new Array();
                        for (var key in obj) {
                            a.push('"' + key + '":' + RPC.EncodeRequest(obj[key]));
                        }

                        return '(' + a.join(',') + ')';
                }
            }

            return 'null';
        case 'number':
            return Math.abs(Math.round(obj)).toString();
        case 'boolean':
            switch (obj) {
                case true:
                    return 'true';
                case false:
                    return 'false';
                default:
                    return 'null';
            }

            break;
        default:
            break;
    }

    throw {};
}

RPC.DecodeResponse = function(str) {
    var index = 0;
    var length = str.length;

    var DecodeArray = function() {
        var ret = new Array();

        while (index < length) {
            switch (str.charAt(index)) {
                case ']':
                    index++;
                    return ret;
                case ',':
                    index++;
                    break;
                default:
                    ret.push(DecodeStr());
                    break;
            }
        }

        return ret; // ERROR ???
    }

    var DecodeObject = function() {
        var ret = new Object();

        while (index < length) {
            switch (str.charAt(index)) {
                case ')':
                    index++;
                    return ret;
                case ',':
                    index++;
                    break;
                default:
                    var s = DecodeStr();
                    if (typeof(s) == 'string') {
                        if (str.charAt(index) == ':') {
                            index++;
                            ret[s] = DecodeStr();
                        } else {
                            throw {}
                        }
                    }

                    break;
            }
        }

        // ERROR ???
    }

    var DecodeStr = function() {
        var chr = str.charAt(index++);

        switch (chr) {
            case '[':
                return DecodeArray();
            case '(':
                return DecodeObject();
            case '"':
                var i = index;
                while (index < length) {
                    var p = str.charAt(index);
                    if (p == '"') {
                        index++;
                        return decodeURIComponent(str.substring(i, index - 1));
                    }

                    index++;
                }

                break;
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                var i = index;
                while (index < length) {
                    var p = str.charAt(index);
                    if (p < '0' || p > '9') {
                        var n = str.substring(i - 1, index);
                        return parseInt(n);
                    }

                    index++;
                }

                break;
            default:
                if ((chr <= 'z' && chr >= 'a') ||
                    (chr <= 'Z' && chr >= 'A') ||
                     chr == '_') {
                    var p = chr;
                    while (index < length) {
                        chr = str.charAt(index);
                        if ((chr <= 'z' && chr >= 'a') ||
                            (chr <= 'Z' && chr >= 'A') ||
                             chr == '_') {
                            p += chr;
                            index++;
                            continue;
                        }

                        break;
                    }

                    switch (p) {
                        case 'false':
                            return false;
                        case 'true':
                            return true;
                        case 'null':
                            return null;
                        default:
                            return p.toString();
                    }
                }

                /* E4 (Unknown Character)
				 */
				throw {}
                break;
        }

        throw {}
    }

    var decoded = DecodeStr();
    if (index < (length - 1)) {
        throw {}
    }

    return decoded;
}

RPC.Invoke = function(proc, data, pEvent) {
    /* objektas XMLHttpRequest */
    var pHttpProxy = null;
    /* stringas `Rq=()` */
    var pPostData = null;

    try {
        pPostData = 'Rq=' + RPC.EncodeRequest(data);

        /* XMLHttpRequest */
        pHttpProxy = RPC.GetXHR();
        pHttpProxy.open('POST', '/?' + proc, true);
        pHttpProxy.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        pHttpProxy.setRequestHeader('Connection', 'close');
        pHttpProxy.setRequestHeader('Content-Length', pPostData.length);

        pHttpProxy.onreadystatechange = function() {
            if (pHttpProxy.readyState == 4) {
                switch (pHttpProxy.status) {
                    case 200:
                    case 304:
                        try {
                            var pDecoded = RPC.DecodeResponse(pHttpProxy.responseText);
							//alert(pHttpProxy.responseText);
							pEvent(pDecoded.Status, pDecoded.Code, pDecoded.Response);
                        } catch (e) {
                            //alert('Objektas nedekoduotas arba callbackai nerasti ' + e);
                        }

                        break;
                    default:
                        break;
                }
            }
        }

        pHttpProxy.send(pPostData);
    } catch (o) {
        //alert('Neapdorota RPC isimtis');
    }
}

RPC.Post = function(proc, data) {
	var aDiv = document.createElement('DIV');
	var aPort = document.createElement('FORM');
	var aInput = document.createElement('INPUT');

    var post = RPC.EncodeRequest(data);
    //alert(post);

	aPort.method = 'post';
	aPort.action = '/?' + proc;
	aDiv.style.display = 'none';
	aInput.type = 'hidden';
	aInput.name = 'Rq';
	aInput.value = post;

	aPort.appendChild(aInput);
	aDiv.appendChild(aPort);
	document.body.appendChild(aDiv);
	aPort.submit();
}
