"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.JSONRPCClient = exports.JSON_RPC_CLIENT_TYPE_ACTIVE_X = exports.JSON_RPC_CLIENT_TYPE_NPAPI = exports.JSON_RPC_CLIENT_TYPE_WEB_EXTENSION = exports.JSON_RPC_CLIENT_TYPE_SIGN_AGENT = exports.JSON_RPC_ERRORS_STRINGS = exports.JSON_RPC_ERROR_INVALID_ENCODING = exports.JSON_RPC_ERROR_UNSUPPORTED_ENCODING = exports.JSON_RPC_ERROR_PARSE = exports.JSON_RPC_ERROR_INTERNAL_RPC_ERROR = exports.JSON_RPC_ERROR_INVALID_METHOD_PARAMS = exports.JSON_RPC_ERROR_REQUESTED_METHOD_NOT_FOUND = exports.JSON_RPC_ERROR_INVALID_REQUEST = exports.JSON_RPC_ERROR_INVALID_SESSION = exports.JSON_RPC_ERROR_APPLICATION_ERROR = exports.JSON_RPC_ERROR_SYSTEM_ERROR = exports.JSON_RPC_ERROR_TRANSPORT_ERROR = exports.JSON_RPC_ERROR_UNKNOWN = exports.JSON_RPC_ERROR_NONE = exports.JSON_RPC_HTTP_HEADER_CONTENT_TYPE = exports.JSON_RPC_FIELD_VALUE_VERSION = exports.JSON_RPC_FIELD_NAME_SESSION_ID = exports.JSON_RPC_FIELD_NAME_ERROR_MSG = exports.JSON_RPC_FIELD_NAME_ERROR_CODE = exports.JSON_RPC_FIELD_NAME_ERROR = exports.JSON_RPC_FIELD_NAME_RESULT = exports.JSON_RPC_FIELD_NAME_PARAMS = exports.JSON_RPC_FIELD_NAME_METHOD = exports.JSON_RPC_FIELD_NAME_ID = exports.JSON_RPC_FIELD_NAME_VERSION = void 0;
const base64coder_1 = require("./base64coder");
const eutypes_1 = require("./eutypes");
const stringcoder_1 = require("./stringcoder");
exports.JSON_RPC_FIELD_NAME_VERSION = 'jsonrpc';
exports.JSON_RPC_FIELD_NAME_ID = 'id';
exports.JSON_RPC_FIELD_NAME_METHOD = 'method';
exports.JSON_RPC_FIELD_NAME_PARAMS = 'params';
exports.JSON_RPC_FIELD_NAME_RESULT = 'result';
exports.JSON_RPC_FIELD_NAME_ERROR = 'error';
exports.JSON_RPC_FIELD_NAME_ERROR_CODE = 'code';
exports.JSON_RPC_FIELD_NAME_ERROR_MSG = 'message';
exports.JSON_RPC_FIELD_NAME_SESSION_ID = 'session_id';
exports.JSON_RPC_FIELD_VALUE_VERSION = '2.0';
exports.JSON_RPC_HTTP_HEADER_CONTENT_TYPE = 'application/json-rpc';
//--------------------------------------------------------------------------------
exports.JSON_RPC_ERROR_NONE = 0;
exports.JSON_RPC_ERROR_UNKNOWN = -1;
exports.JSON_RPC_ERROR_TRANSPORT_ERROR = -32300;
exports.JSON_RPC_ERROR_SYSTEM_ERROR = -32400;
exports.JSON_RPC_ERROR_APPLICATION_ERROR = -32500;
exports.JSON_RPC_ERROR_INVALID_SESSION = -32510;
exports.JSON_RPC_ERROR_INVALID_REQUEST = -32600;
exports.JSON_RPC_ERROR_REQUESTED_METHOD_NOT_FOUND = -32601;
exports.JSON_RPC_ERROR_INVALID_METHOD_PARAMS = -32602;
exports.JSON_RPC_ERROR_INTERNAL_RPC_ERROR = -32603;
exports.JSON_RPC_ERROR_PARSE = -32700;
exports.JSON_RPC_ERROR_UNSUPPORTED_ENCODING = -32701;
exports.JSON_RPC_ERROR_INVALID_ENCODING = -32702;
exports.JSON_RPC_ERRORS_STRINGS = [];
exports.JSON_RPC_ERRORS_STRINGS[exports.JSON_RPC_ERROR_NONE] = 'Executed successfully';
exports.JSON_RPC_ERRORS_STRINGS[exports.JSON_RPC_ERROR_UNKNOWN] = 'Unknown error';
exports.JSON_RPC_ERRORS_STRINGS[exports.JSON_RPC_ERROR_TRANSPORT_ERROR] = 'Transport error';
exports.JSON_RPC_ERRORS_STRINGS[exports.JSON_RPC_ERROR_SYSTEM_ERROR] = 'System error';
exports.JSON_RPC_ERRORS_STRINGS[exports.JSON_RPC_ERROR_APPLICATION_ERROR] = 'Application error';
exports.JSON_RPC_ERRORS_STRINGS[exports.JSON_RPC_ERROR_INVALID_SESSION] = 'Application error. Invalid session';
exports.JSON_RPC_ERRORS_STRINGS[exports.JSON_RPC_ERROR_INVALID_REQUEST] = 'Server error. Invalid rpc. Not conforming to spec';
exports.JSON_RPC_ERRORS_STRINGS[exports.JSON_RPC_ERROR_REQUESTED_METHOD_NOT_FOUND] = 'Server error. Requested method not found';
exports.JSON_RPC_ERRORS_STRINGS[exports.JSON_RPC_ERROR_INVALID_METHOD_PARAMS] = 'Server error. Invalid method parameters';
exports.JSON_RPC_ERRORS_STRINGS[exports.JSON_RPC_ERROR_INTERNAL_RPC_ERROR] = 'Server error. Internal rpc error';
exports.JSON_RPC_ERRORS_STRINGS[exports.JSON_RPC_ERROR_PARSE] = 'Parse error. Not well formed';
exports.JSON_RPC_ERRORS_STRINGS[exports.JSON_RPC_ERROR_UNSUPPORTED_ENCODING] = 'Parse error. Unsupported encoding';
exports.JSON_RPC_ERRORS_STRINGS[exports.JSON_RPC_ERROR_INVALID_ENCODING] = 'Parse error. Invalid character for encoding';
//================================================================================
exports.JSON_RPC_CLIENT_TYPE_SIGN_AGENT = 1;
exports.JSON_RPC_CLIENT_TYPE_WEB_EXTENSION = 2;
exports.JSON_RPC_CLIENT_TYPE_NPAPI = 3;
exports.JSON_RPC_CLIENT_TYPE_ACTIVE_X = 4;
//================================================================================
const JSONRPCClient = function (type, address, port, useHttps) {
    this.Vendor = 'JSC IIT';
    this.ClassVersion = '1.0.2';
    this.ClassName = 'JSONRPCClient';
    this.m_type = type;
    this.m_log = false;
    this._logFunction('Initialize', arguments, ['type', 'address', 'port', 'useHttps']);
    switch (type) {
        case exports.JSON_RPC_CLIENT_TYPE_WEB_EXTENSION:
            this.m_uri = address;
            this.m_callbacks = [];
            this._registerOnExtensionRecieveEventHandler();
            break;
        case exports.JSON_RPC_CLIENT_TYPE_NPAPI:
        case exports.JSON_RPC_CLIENT_TYPE_ACTIVE_X:
            this.m_uri = address;
            this.m_callbacks = [];
            break;
        case exports.JSON_RPC_CLIENT_TYPE_SIGN_AGENT:
        default:
            this.m_uri = '';
            if (useHttps && address.indexOf('https://'))
                this.m_uri += 'https://';
            else if (address.indexOf('http://') != 0)
                this.m_uri += 'http://';
            this.m_uri += address + ':' + port;
            break;
    }
    this.m_requests = 0;
    this.m_session_id = this._loadSessionId();
};
exports.JSONRPCClient = JSONRPCClient;
//--------------------------------------------------------------------------------
exports.JSONRPCClient.prototype._logFunction = function (funcName, args, argsNames) {
    if (!this.m_log)
        return;
    var str = '(';
    for (var i = 0; i < args.length; i++) {
        str += argsNames[i] + ': ' + args[i].toString();
        if (i != (args.length - 1))
            str += ', ';
    }
    str += ')';
    this._log(funcName, str);
};
//--------------------------------------------------------------------------------
exports.JSONRPCClient.prototype._log = function (funcName, data) {
    if (!this.m_log)
        return;
    console.log(funcName + ': ' + data);
};
//--------------------------------------------------------------------------------
exports.JSONRPCClient.prototype._loadSessionId = function () {
    try {
        var session = sessionStorage.getItem(this.ClassName +
            exports.JSON_RPC_FIELD_NAME_SESSION_ID);
        if ((typeof session == 'undefined') ||
            (session == null) || (session == '')) {
            return null;
        }
        return session;
    }
    catch (e) {
        return null;
    }
};
//--------------------------------------------------------------------------------
exports.JSONRPCClient.prototype._saveSessionId = function (sessionId) {
    try {
        sessionStorage.setItem(this.ClassName +
            exports.JSON_RPC_FIELD_NAME_SESSION_ID, sessionId);
    }
    catch (e) {
    }
};
//--------------------------------------------------------------------------------
exports.JSONRPCClient.prototype.createXMLHttpRequest = function () {
    let XMLHttpRequest;
    if (typeof XMLHttpRequest == 'undefined') {
        XMLHttpRequest = function () {
            try {
                // @ts-ignore
                return new ActiveXObject('Msxml2.XMLHTTP.6.0');
            }
            catch (e) {
            }
            try {
                // @ts-ignore
                return new ActiveXObject('Msxml2.XMLHTTP.3.0');
            }
            catch (e) {
            }
            try {
                // @ts-ignore
                return new ActiveXObject('Msxml2.XMLHTTP');
            }
            catch (e) {
            }
            try {
                // @ts-ignore
                return new ActiveXObject('Microsoft.XMLHTTP');
            }
            catch (e) {
            }
            throw exports.JSON_RPC_ERRORS_STRINGS[exports.JSON_RPC_ERROR_TRANSPORT_ERROR];
        };
    }
    // @ts-ignore
    return new XMLHttpRequest();
};
//--------------------------------------------------------------------------------
exports.JSONRPCClient.prototype.makeRequest = function (method, params, id) {
    var request = null;
    try {
        request = {};
        request[exports.JSON_RPC_FIELD_NAME_VERSION] = exports.JSON_RPC_FIELD_VALUE_VERSION;
        request[exports.JSON_RPC_FIELD_NAME_ID] = id;
        request[exports.JSON_RPC_FIELD_NAME_METHOD] = method;
        request[exports.JSON_RPC_FIELD_NAME_PARAMS] = params;
        request[exports.JSON_RPC_FIELD_NAME_SESSION_ID] = this.m_session_id;
        request = JSON.stringify(request);
    }
    catch (e) {
    }
    return request;
};
//--------------------------------------------------------------------------------
exports.JSONRPCClient.prototype.verifyResponse = function (request_id, response) {
    try {
        if (response[exports.JSON_RPC_FIELD_NAME_VERSION] !=
            exports.JSON_RPC_FIELD_VALUE_VERSION) {
            return false;
        }
        var error = response[exports.JSON_RPC_FIELD_NAME_ERROR];
        if (typeof error == 'undefined') {
            if ((response[exports.JSON_RPC_FIELD_NAME_ID] != request_id) ||
                (typeof response[exports.JSON_RPC_FIELD_NAME_RESULT] == 'undefined')) {
                return false;
            }
        }
        else {
            if (typeof error[exports.JSON_RPC_FIELD_NAME_ERROR_CODE] == 'undefined' ||
                typeof error[exports.JSON_RPC_FIELD_NAME_ERROR_MSG] == 'undefined') {
                return false;
            }
        }
        if (typeof response[exports.JSON_RPC_FIELD_NAME_SESSION_ID] != 'undefined') {
            if (this.m_session_id != null &&
                response[exports.JSON_RPC_FIELD_NAME_SESSION_ID] != null) {
                if (this.m_session_id != response[exports.JSON_RPC_FIELD_NAME_SESSION_ID])
                    return false;
            }
            else {
                this.m_session_id = response[exports.JSON_RPC_FIELD_NAME_SESSION_ID];
                this._saveSessionId(this.m_session_id);
            }
        }
        return true;
    }
    catch (e) {
        return false;
    }
};
//--------------------------------------------------------------------------------
exports.JSONRPCClient.prototype.handleResponse = function (request_id, response) {
    try {
        var response = JSON.parse(response);
        if (!this.verifyResponse(request_id, response))
            return null;
        return response;
    }
    catch (e) {
        return null;
    }
};
//--------------------------------------------------------------------------------
exports.JSONRPCClient.prototype._sendHttp = function (request, request_id, callback) {
    var xhr;
    var response;
    var pThis = this;
    try {
        xhr = this.createXMLHttpRequest();
        xhr.open('POST', this.m_uri, callback != null);
        xhr.setRequestHeader('Content-Type', exports.JSON_RPC_HTTP_HEADER_CONTENT_TYPE);
        if (callback != null) {
            xhr.onload = function () {
                if (xhr.status != 200) {
                    callback(null);
                    return;
                }
                response = pThis.handleResponse(request_id, xhr.response);
                if (response == null) {
                    callback(null);
                    return;
                }
                callback(response[exports.JSON_RPC_FIELD_NAME_RESULT]);
                return;
            };
            xhr.onerror = function () {
                callback(null);
            };
        }
        xhr.send(request);
        if (callback != null)
            return;
        if (xhr.status != 200)
            return null;
        response = this.handleResponse(request_id, xhr.response);
        if (response == null)
            return null;
        return response[exports.JSON_RPC_FIELD_NAME_RESULT];
    }
    catch (e) {
        if (callback != null)
            callback(null);
        else
            return null;
    }
};
//--------------------------------------------------------------------------------
exports.JSONRPCClient.prototype._registerOnExtensionRecieveEventHandler = function () {
    var pThis = this;
    window.addEventListener('message', function (event) {
        if (event.data.sender != pThis.m_uri)
            return;
        try {
            var callback_id = event.data.callback_id;
            var callbackObj = pThis.m_callbacks[callback_id - 1];
            delete pThis.m_callbacks[callback_id - 1];
            pThis._logFunction('_registerOnExtensionRecieveEventHandler', [callbackObj.request_id, event.data.data], ['request_id', 'data']);
            var response = pThis.handleResponse(callbackObj.request_id, event.data.data);
            if (response == null) {
                callbackObj.callback(null);
                return;
            }
            callbackObj.callback(response[exports.JSON_RPC_FIELD_NAME_RESULT]);
        }
        catch (e) {
        }
    }, false);
};
//--------------------------------------------------------------------------------
exports.JSONRPCClient.prototype._sendExtension = function (request, request_id, callback) {
    var response;
    var pThis = this;
    pThis._logFunction('_sendExtension', [arguments[0], arguments[1]], ['request', 'request_id']);
    if (!callback)
        throw 'Synchronous calls for web extensions not supported';
    if (document.getElementsByClassName(pThis.m_uri).length != 1) {
        callback(null);
        return;
    }
    try {
        var callbackObj = {
            'request_id': request_id,
            'callback': callback
        };
        var callback_id = pThis.m_callbacks.push(callbackObj);
        var rpcRequest = {
            sender: pThis.ClassName,
            request: request,
            callback_id: callback_id
        };
        window.postMessage(rpcRequest, '*');
    }
    catch (e) {
        callback(null);
    }
};
//--------------------------------------------------------------------------------
exports.JSONRPCClient.prototype._getPluginObject = function () {
    try {
        var objects = document.getElementsByTagName('object');
        for (var i = 0; i < objects.length; i++) {
            var classid = objects[i].classid;
            if (!classid &&
                objects[i].attributes &&
                objects[i].attributes['classid']) {
                classid = objects[i].attributes['classid'].value;
            }
            if (classid === this.m_uri)
                return objects[i];
        }
        return null;
    }
    catch (e) {
        return null;
    }
};
//--------------------------------------------------------------------------------
exports.JSONRPCClient.prototype._sendPlugin = function (request, request_id, callback) {
    var response;
    var pThis = this;
    pThis._logFunction('_sendPlugin', [arguments[0], arguments[1]], ['request', 'request_id']);
    var pluginObject = pThis._getPluginObject();
    if (pluginObject == null) {
        if (callback != null)
            callback(null);
        return null;
    }
    var _pluginMakeExchange = function (request) {
        try {
            var PLUGIN_MESSAGE_HEADER_SIZE = 5;
            var PLUGIN_MESSAGE_HEADER_PART = '"part';
            var PLUGIN_MESSAGE_HEADER_LAST = '"last';
            var PLUGIN_MESSAGE_HEADER_NEXT = '"next"';
            var base64Coder = new base64coder_1.EndUserBase64Coder();
            var buffer = new eutypes_1.EndUserUint8Array(0);
            while (true) {
                var response = pluginObject.ProcessData(request);
                var header = response.slice(0, PLUGIN_MESSAGE_HEADER_SIZE);
                var body = response.slice(PLUGIN_MESSAGE_HEADER_SIZE, response.length - 1);
                if (body != null || body != '') {
                    var part = base64Coder.decode(body);
                    var _tmpBuffer = new eutypes_1.EndUserUint8Array(buffer.length + part.length);
                    _tmpBuffer.set(buffer);
                    _tmpBuffer.set(part, buffer.length);
                    buffer = _tmpBuffer;
                }
                switch (header) {
                    case PLUGIN_MESSAGE_HEADER_PART:
                        request = PLUGIN_MESSAGE_HEADER_NEXT;
                        continue;
                    case PLUGIN_MESSAGE_HEADER_LAST:
                        return stringcoder_1.EndUserStringCoder.ArrayToString(stringcoder_1.EU_SIGN_CP_ENCODING_UTF_8, buffer);
                    default:
                        return null;
                }
            }
        }
        catch (e) {
            return null;
        }
    };
    try {
        if (callback != null) {
            setTimeout(function () {
                response = _pluginMakeExchange(request);
                pThis._logFunction('_sendPlugin', [request_id, response], ['request_id', 'response']);
                response = pThis.handleResponse(request_id, response);
                if (response == null) {
                    callback(null);
                    return;
                }
                callback(response[exports.JSON_RPC_FIELD_NAME_RESULT]);
            }, 1);
            return;
        }
        response = _pluginMakeExchange(request);
        response = pThis.handleResponse(request_id, response);
        if (response == null)
            return null;
        return response[exports.JSON_RPC_FIELD_NAME_RESULT];
    }
    catch (e) {
        callback(null);
    }
};
//--------------------------------------------------------------------------------
exports.JSONRPCClient.prototype.send = function (request, request_id, callback) {
    var response;
    var pThis = this;
    switch (pThis.m_type) {
        case exports.JSON_RPC_CLIENT_TYPE_SIGN_AGENT:
            return pThis._sendHttp(request, request_id, callback);
        case exports.JSON_RPC_CLIENT_TYPE_WEB_EXTENSION:
            return pThis._sendExtension(request, request_id, callback);
        case exports.JSON_RPC_CLIENT_TYPE_NPAPI:
        case exports.JSON_RPC_CLIENT_TYPE_ACTIVE_X:
            return pThis._sendPlugin(request, request_id, callback);
    }
};
//--------------------------------------------------------------------------------
exports.JSONRPCClient.prototype.execute = function (method, params, callback) {
    var request_id;
    var request;
    request_id = this.m_requests;
    this.m_requests++;
    request = this.makeRequest(method, params, request_id);
    if (request == null) {
        if (callback != null) {
            callback(null);
            return;
        }
        return null;
    }
    if (callback != null) {
        this.send(request, request_id, callback);
        return;
    }
    return this.send(request, request_id, callback);
};
//================================================================================
