"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) => {
            this._functional._done(data);
        };
        const self = this;
        const functional = new (class _Functional extends Functional_1.Functional {
            constructor(system) {
                super({
                    i: fi,
                    o: fo,
                }, {}, system, `_${id}`);
            }
            f(i, done, fail) {
                self.f(i, done, fail);
            }
            d() {
                self.d();
            }
            b() {
                self.b();
            }
        })(this.__system);
        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);
        if (!this.paused()) {
            functional.play();
            functional.play();
        }
        this._functional = functional;
        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.addListener('pause', () => {
            functional.pause();
            primitive.pause();
        });
        this.addListener('play', () => {
            functional.play();
            primitive.play();
        });
        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);
        });
    }
    f(i, done, fail) { }
    d() { }
    b() { }
    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();
    }
    _backward_f() {
        for (const fi of this._f_i) {
            if (!this._ref_input[fi]) {
                this._backward(fi);
            }
        }
    }
    _forward_empty_f() {
        for (const fo of this._f_o) {
            this._forward_empty(fo);
        }
    }
    snapshotSelf() {
        return {
            ...super.snapshotSelf(),
            _primitive: this._primitive.snapshotSelf(),
            _functional: this._functional.snapshotSelf(),
        };
    }
    restoreSelf(state) {
        const { _primitive, _functional, ...rest } = state;
        super.restoreSelf(rest);
        _primitive && this._primitive.restoreSelf(_primitive);
        _functional && this._functional.restoreSelf(_functional);
    }
}
exports.Semifunctional = Semifunctional;
//# sourceMappingURL=index.js.map