/* phprpc_client.js - JavaScript PHPRPC Client
 *
 * Copyright Ma Bingyao <andot@ujn.edu.cn>
 * Version: 1.1
 * LastModified: 2006-01-29
 * This library is free.  You can redistribute it and/or modify it.
 * http://www.coolcode.cn/?p=106
 */

/*
 * Interfaces:
 * phprpc_client.create('rpc');
 * rpc.use_service('http://domain.com/phprpc/server.php');
 * rpc.method_callback = function(result, args, output) {
 *     if (result instanceof phprpc_error) {
 *         alert(result.errstr);
 *     }
 *     else {
 *         alert(result);  // or do any other things.
 *     }
 * }
 * ....
 * if (rpc.ready) rpc.method();
 */

function phprpc_error(errno, errstr) {
    this.errno = errno;
    this.errstr = errstr;
}

function phprpc_client() {
    this.__php = new PHP_Serializer();
    this.__url = '';
    this.ready = false;
    this.use_service = function (url) {
        if (typeof(this.__name) == "undefined") {
            return false;
        }
        this.__url = url;
        var id = this.__create_id();
        var callback = base64encode(utf16to8(this.__name + ".__get_functions('" + id + "');"));
        this.__append_script(id, 'phprpc_callback=' + callback + '&phprpc_encode=false');
        return true;
    }
    this.__get_functions = function (id) {
        var functions = this.__php.unserialize(phprpc_functions);
        var func;
        for (var i = 0; i < functions.length; i++) {
            func = this.__name + "." + functions[i] + " = function () {\r\n";
            func += "    this.__call('"  + functions[i] + "', this.__args_to_array(arguments));\r\n";
            func += "}";
            eval(func);
        }
        this.ready = true;
        if (typeof(this.onready) == "function") {
            this.onready();
        }
        this.__remove_script(id);
    }
    this.__call = function (func, args) {
        args = base64encode(this.__php.serialize(args));
        var id = this.__create_id();
        var request = 'phprpc_func=' + func + '&phprpc_args=' + args + '&phprpc_encode=false';
        var callback = this.__name + "." + func + "_callback";
        if (typeof(eval(callback)) == "function") {
            request += '&phprpc_callback=' + base64encode(utf16to8(this.__name + ".__callback('" + id + "', " + callback + ");"));
        }
        this.__append_script(id, request);
    }
    this.__callback = function (id, callback) {
        if (phprpc_errno == 0) {
            phprpc_result = this.__php.unserialize(phprpc_result);
            phprpc_args = this.__php.unserialize(phprpc_args);
        }
        else {
            phprpc_result = new phprpc_error(phprpc_errno, phprpc_errstr);
            phprpc_args = null;
        }
        callback(phprpc_result, phprpc_args, phprpc_output);
        this.__remove_script(id);
    }
    this.__create_id = function () {
        return (new Date()).getTime().toString(36) + Math.floor(Math.random() * 100000000).toString(36);
    }
    this.__append_script = function (id, request) {
        var script = document.createElement("script");
        script.id = "script_" + id;
        script.src = this.__url + "?" + request.replace(/\+/g, '%2B');
        script.defer = true;
        script.type = "text/javascript";
        var head = document.getElementsByTagName("head").item(0);
        head.appendChild(script);
    }
    this.__remove_script = function (id) {
        var script = document.getElementById("script_" + id);
        var head = document.getElementsByTagName("head").item(0);
        head.removeChild(script);
    }
    this.__args_to_array = function (args) {
        argArray = new Array();
        for (i = 0; i < args.length; i++) {
            argArray[i] = args[i];
        }
        return argArray;
    }
}

phprpc_client.create = function (name) {
    eval(name + ' = new phprpc_client();');
    eval(name + '.__name = "' + name + '";');
}