"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const Peer_1 = require("../../../../../api/peer/Peer");
const _1 = require("../../../../../Class/$");
const Holder_1 = require("../../../../../Class/Holder");
const MediaStream_1 = require("../../../../../wrap/MediaStream");
const _ids_1 = require("../../../../_ids");
class PeerReceiver extends Holder_1.Holder {
    constructor(system) {
        super({
            fi: ['opt'],
            fo: [],
            i: ['offer'],
            o: ['stream', 'channel', 'answer'],
        }, {
            input: {},
            output: {
                channel: {
                    ref: true,
                },
                stream: {
                    ref: true,
                },
            },
        }, system, _ids_1.ID_PEER_RECEIVER, 'close');
        this._peer = null;
        this._unlisten = undefined;
        this._connected = false;
        this._flag_err_invalid_offer = false;
        this._output_answer = async (offer) => {
            try {
                await this._peer.acceptOffer(offer);
            }
            catch (err) {
                this._flag_err_invalid_offer = true;
                this.err('invalid offer');
                return;
            }
            const answer = await this._peer.answer();
            this._output.answer.push(answer);
        };
        this._setup_peer = () => {
            const connect_listener = () => {
                // console.log('Receiver', 'Peer', 'connect')
                this._connected = true;
                const peer = this._peer;
                const channel = new (class Channel extends _1.$ {
                    constructor() {
                        super(...arguments);
                        this.__ = ['CH'];
                    }
                    async send(data) {
                        peer.send(data);
                        return;
                    }
                })(this.__system);
                this._output.channel.push(channel);
            };
            const error_listener = (err) => {
                // console.log('Receiver', 'Peer', 'error', err)
                this.err(err.message);
            };
            const close_listener = () => {
                // console.log('Receiver', 'Peer', 'close')
                this.d();
            };
            const message_listener = (message) => {
                // console.log('Receiver', 'Peer', 'message', message)
                if (this._output.channel.active()) {
                    // @ts-ignore
                    this._output.channel.peak().emit('message', message);
                }
            };
            const start_listener = (stream) => {
                // console.log('Receiver', 'Peer', 'start', stream)
                const _stream = (0, MediaStream_1.wrapMediaStream)(stream, this.__system);
                this._output.stream.push(_stream);
            };
            const stop_listener = () => {
                // console.log('Receiver', 'Peer', 'stop')
                this._output.stream.pull();
            };
            this._peer.addListener('connect', connect_listener);
            this._peer.addListener('error', error_listener);
            this._peer.addListener('close', close_listener);
            this._peer.addListener('message', message_listener);
            this._peer.addListener('start', start_listener);
            this._peer.addListener('stop', stop_listener);
            return () => {
                this._peer.removeListener('connect', connect_listener);
                this._peer.removeListener('error', error_listener);
                this._peer.removeListener('close', close_listener);
                this._peer.removeListener('message', message_listener);
                this._peer.removeListener('start', start_listener);
                this._peer.removeListener('stop', stop_listener);
            };
        };
        this.addListener('take_err', () => {
            if (this._flag_err_invalid_offer) {
                this._flag_err_invalid_offer = false;
                this._backward('offer');
            }
            else {
                // TODO
            }
        });
    }
    async f({ opt }, done, fail) {
        try {
            this._peer = new Peer_1.Peer(this.__system, false, opt);
        }
        catch (err) {
            fail(err.message.toLowerCase());
            return;
        }
        this._setup_peer();
        if (this._input.offer.active()) {
            await this._output_answer(this._input.offer.peak());
        }
    }
    d() {
        if (this._unlisten) {
            this._unlisten();
            this._unlisten = undefined;
        }
        if (this._peer) {
            this._peer.close();
            this._peer = null;
        }
        this._connected = false;
    }
    async onDataInputDrop(name, data) {
        if (name === 'opt') {
            this._forward_all_empty();
        }
    }
    async onIterDataInputData(name, data) {
        super.onIterDataInputData(name, data);
        if (name === 'offer') {
            if (this._input.opt.active()) {
                await this._output_answer(data);
            }
        }
    }
    onIterDataInputDrop(name) {
        super.onIterDataInputDrop(name);
        if (name === 'offer') {
            if (this._flag_err_invalid_offer) {
                this._flag_err_invalid_offer = false;
                this.takeErr();
                return;
            }
            this._forward_empty('channel');
            this._forward_empty('stream');
            this._forward_empty('answer');
        }
    }
    onDataOutputDrop(name) {
        if (name === 'answer') {
            this._input.offer.pull();
        }
    }
}
exports.default = PeerReceiver;
//# sourceMappingURL=index.js.map