"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RemotePort = void 0;
const STRING_1 = require("./constant/STRING");
const EventEmitter_1 = require("./EventEmitter");
const id_1 = require("./util/id");
class RemotePort {
    constructor(port) {
        this._call_id = new Set();
        this._watch_id = new Set();
        this._ref_id = new Set();
        this._ref = {};
        this._watch_emitter = new EventEmitter_1.EventEmitter_();
        this._call_emitter = new EventEmitter_1.EventEmitter_();
        this._valid = true;
        this._port = port;
        this._port.onmessage = (data) => {
            this.exec(data);
        };
        this._port.onerror = (event) => {
            const { message } = event;
            // console.log('err', message)
        };
    }
    exec(data) {
        const { type, data: _data } = data;
        const { id, data: __data } = _data;
        if (type === STRING_1.GET) {
            if (!this._call_id.has(id)) {
                throw new Error('unexpected worker call message id');
            }
            this._call_emitter.emit(id, __data);
        }
        else if (type === STRING_1.CALL) {
            if (!this._call_id.has(id)) {
                throw new Error('unexpected worker call message id');
            }
            this._call_emitter.emit(id, __data);
        }
        else if (type === STRING_1.WATCH) {
            if (!this._watch_id.has(id)) {
                //
            }
            this._watch_emitter.emit(id, __data);
        }
        else if (type === STRING_1.REF) {
            const ref_port = this._ref[id];
            ref_port.exec(__data);
        }
        else {
            throw new Error('unexpected worker message type');
        }
    }
    get(method, data, callback) {
        const id = (0, id_1.randomIdNotInSet)(this._call_id);
        this._call_id.add(id);
        const listener = (data) => {
            this._call_emitter.removeListener(id, listener);
            this._call_id.delete(id);
            callback(data);
        };
        this._call_emitter.addListener(id, listener);
        const _data = { type: STRING_1.GET, data: { id, method, data } };
        this._port.send(_data);
    }
    call(method, data, callback) {
        const id = (0, id_1.randomIdNotInSet)(this._call_id);
        this._call_id.add(id);
        const listener = (data) => {
            this._call_emitter.removeListener(id, listener);
            this._call_id.delete(id);
            callback(data);
        };
        this._call_emitter.addListener(id, listener);
        const _data = { type: STRING_1.CALL, data: { id, method, data } };
        this._port.send(_data);
    }
    watch(method, data, callback) {
        const id = (0, id_1.randomIdNotInSet)(this._watch_id);
        this._watch_id.add(id);
        const listener = (data) => {
            callback(data);
        };
        this._watch_emitter.addListener(id, listener);
        const _data = { type: STRING_1.WATCH, data: { id, method, data } };
        this._port.send(_data);
        return () => {
            this._watch_emitter.removeListener(id, listener);
            this._watch_id.delete(id);
            if (this._valid) {
                const _data = { type: STRING_1.UNWATCH, data: { id } };
                this._port.send(_data);
            }
            else {
                // console.log('Invalid Remote Port unlisten called')
            }
        };
    }
    ref(method, data) {
        const id = (0, id_1.randomIdNotInSet)(this._ref_id);
        const _data = { type: STRING_1.REF, data: { id, method, data } };
        this._port.send(_data);
        const port = {
            send: (data) => {
                const _data = { type: STRING_1.REF_EXEC, data: { id, data } };
                this._port.send(_data);
            },
            onmessage() { },
            onerror() { },
        };
        const remote_port = new RemotePort(port);
        this._ref[id] = remote_port;
        return remote_port;
    }
    close() {
        this._valid = false;
        for (const id in this._ref) {
            const ref = this._ref[id];
            ref.close();
        }
    }
    valid() {
        return this._valid;
    }
}
exports.RemotePort = RemotePort;
//# sourceMappingURL=RemotePort.js.map