"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Semifunctional = void 0;
const Primitive_1 = require("../../Primitive");
const Functional_1 = require("../Functional");
class Semifunctional extends Primitive_1.Primitive {
    constructor({ fi = [], fo = [], i = [], o = [] }, opt = {}, system, id) {
        super({ i: [...fi, ...i], o: [...fo, ...o] }, opt, system, id);
        this._done = (data, err = null) => {
            this._functional._done(data, err);
        };
        const self = this;
        const functional = new (class _Functional extends Functional_1.Functional {
            constructor(system) {
                super({
                    i: fi,
                    o: fo,
                }, {}, system, `_${id}`);
            }
            f(i, done) {
                self.f(i, done);
            }
            d() {
                self.d();
            }
            i() {
                self.i();
            }
        })(this.__system);
        this._functional = functional;
        functional.play();
        const primitive = new (class _Primitive extends Primitive_1.Primitive {
            constructor(system) {
                super({
                    i,
                    o,
                }, {}, system, `_${id}`);
            }
            onDataInputData(name, data) {
                self.onIterDataInputData(name, data);
            }
            onRefInputData(name, data) {
                self.onIterRefInputData(name, data);
            }
            onDataInputDrop(name) {
                self.onIterDataInputDrop(name);
            }
            onRefInputDrop(name) {
                self.onIterRefInputDrop(name);
            }
            onDataOutputDrop(name) {
                self.onIterDataOutputDrop(name);
            }
            onRefOutputDrop(name) {
                self.onIterRefOutputDrop(name);
            }
            onDataInputInvalid(name) {
                self.onIterDataInputInvalid(name);
            }
            onRefInputInvalid(name) {
                self.onIterRefInputInvalid(name);
            }
        })(this.__system);
        primitive.play();
        this._primitive = primitive;
        for (const name of fi) {
            functional.setInput(name, this.getInput(name), this.getInputOpt(name));
        }
        for (const name of fo) {
            functional.setOutput(name, this.getOutput(name), this.getOutputOpt(name));
        }
        for (const name of i) {
            primitive.setInput(name, this.getInput(name), this.getInputOpt(name));
        }
        for (const name of o) {
            primitive.setOutput(name, this.getOutput(name), this.getOutputOpt(name));
        }
        // assuming primitive side will not throw error
        functional.addListener('err', (err) => {
            this.err(err);
        });
        functional.addListener('take_err', () => {
            this.takeErr();
        });
        this.addListener('take_err', () => {
            functional.takeErr();
        });
        this.addListener('take_caught_err', () => {
            functional.takeCaughtErr();
        });
        this._f_i = new Set(fi);
        this._f_o = new Set(fo);
        this.addListener('set_input', (name, pin, opt, propagate) => {
            this._f_i.add(name);
            functional.addInput(name, pin, opt);
        });
        this.addListener('set_output', (name, pin, opt, propagate) => {
            this._f_o.add(name);
            functional.addOutput(name, pin, opt);
        });
        // TODO
        // this.addListener('remove_input', this._onInputRemoved)
        // this.addListener('remove_output', this._onOutputRemoved)
        // this.addListener('rename_input', this._onInputRenamed)
        // this.addListener('rename_output', this._onOutputRenamed)
    }
    f(i, done) { }
    d() {
        this.fd();
    }
    fd() { }
    i() {
        this.fi();
    }
    fi() { }
    onIterDataInputData(name, data) { }
    onIterRefInputData(name, data) { }
    onIterDataInputDrop(name) { }
    onIterRefInputDrop(name) { }
    onIterDataOutputDrop(name) { }
    onIterRefOutputDrop(name) { }
    onIterDataInputInvalid(name) { }
    onIterRefInputInvalid(name) { }
    destroy() {
        this._functional.destroy();
        this._primitive.destroy();
        super.destroy();
    }
}
exports.Semifunctional = Semifunctional;
//# sourceMappingURL=index.js.map