"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const Peer_1 = require("../../../../../api/peer/Peer");
const AsyncWorker_1 = require("../../../../../AsyncWorker");
const STRING_1 = require("../../../../../constant/STRING");
const Primitive_1 = require("../../../../../Primitive");
const RemotePort_1 = require("../../../../../RemotePort");
const evaluate_1 = require("../../../../../spec/evaluate");
const stringify_1 = require("../../../../../spec/stringify");
const wrap_1 = require("../../../../../wrap");
const _ids_1 = require("../../../../_ids");
class PeerGraph extends Primitive_1.Primitive {
    constructor(system) {
        super({
            i: ['opt', 'offer', 'close'],
            o: ['graph', 'answer'],
        }, {
            output: {
                graph: {
                    ref: true,
                },
            },
        }, system, _ids_1.ID_PEER_GRAPH);
        this.__ = ['U'];
        this._peer_connected = false;
        this._offer_sent = false;
        this._accept_offer = (offer) => __awaiter(this, void 0, void 0, function* () {
            yield this._peer.acceptOffer(offer);
            const answer = yield this._peer.answer();
            this._output.answer.push(answer);
            this._offer_sent = true;
        });
        this.__forward_empty = () => {
            this._forward_all_empty();
            this._backward('offer');
            this._backward('close');
            this._backward('opt');
            this._forwarding_empty = true;
            if (this.hasErr()) {
                this.takeErr();
            }
            this._disconnect();
            this._forwarding_empty = false;
        };
        this._disconnect = () => {
            // console.log('PeerGraph', '_close')
            this._backwarding = true;
            this._output.graph.pull();
            if (this._remote_port) {
                this._remote_port.close();
                this._remote_port = undefined;
            }
            if (this._peer) {
                // this._peer.close()
                this._peer = null;
            }
            this._backwarding = false;
        };
        this.addListener('destroy', () => {
            this.__forward_empty();
        });
        this.addListener('take_err', () => {
            //
        });
        this.addListener('take_caught_err', () => {
            //
        });
    }
    onDataInputData(name, data) {
        return __awaiter(this, void 0, void 0, function* () {
            // console.log('PeerGraph', 'onDataInputData', name, data)
            if (name === 'opt') {
                this._peer = new Peer_1.Peer(this.__system, false, data);
                const port = {
                    send: (data) => {
                        // console.log('PeerGraph', 'postMessage', data)
                        const message = (0, stringify_1.stringify)(data);
                        this._peer.send(message);
                    },
                    onmessage(data) { },
                    onerror() {
                        // console.log('onerror')
                    },
                    terminate() {
                        // console.log('terminate')
                    },
                };
                this._peer.addListener('message', (message) => {
                    // console.log('PeerGraph', 'message', message)
                    const specs = this.__system.specs;
                    const classes = this.__system.classes;
                    const data = (0, evaluate_1.evaluate)(message, specs, classes);
                    const { type, data: _data } = data;
                    switch (type) {
                        case STRING_1.EXEC:
                            {
                                port.onmessage({ data: _data });
                            }
                            break;
                        case STRING_1.INIT:
                            {
                                const remote_port = new RemotePort_1.RemotePort(port);
                                this._remote_port = remote_port;
                                const $graph = (0, AsyncWorker_1.AsyncWorkerGraph)(remote_port);
                                const graph = (0, wrap_1.$wrap)(this.__system, $graph, [
                                    'U',
                                    'C',
                                    'G',
                                ]);
                                this._output.graph.push(graph);
                            }
                            break;
                        case STRING_1.TERMINATE:
                            {
                                this._disconnect();
                            }
                            break;
                    }
                });
                this._peer.addListener('connect', () => {
                    // console.log('PeerGraph', 'peer', 'connect')
                    this._peer_connected = true;
                });
                this._peer.addListener('close', () => {
                    // console.log('PeerGraph', 'peer', 'close')
                    this._peer_connected = false;
                });
                const offer = this._input.offer.peak();
                if (offer !== undefined) {
                    this._accept_offer(offer);
                }
            }
            else if (name === 'offer') {
                if (this._peer) {
                    const offer = data;
                    this._accept_offer(offer);
                }
            }
            else if (name === 'close') {
                this.__forward_empty();
            }
        });
    }
    onDataInputDrop(name) {
        if (name === 'opt') {
            if (!this._backwarding) {
                this.__forward_empty();
            }
        }
    }
}
exports.default = PeerGraph;
//# sourceMappingURL=index.js.map