"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.lazyFromSpec = void 0;
const Merge_1 = require("../Class/Merge");
const Unit_1 = require("../Class/Unit");
const f_1 = require("../system/core/object/ForEachKeyValue/f");
const f_2 = require("../system/f/object/Keys/f");
const fromSpec_1 = require("./fromSpec");
function lazyFromSpec(spec, specs, branch = {}) {
    const { inputs, outputs, id } = spec;
    if (!spec.id) {
        throw new Error();
    }
    class Lazy extends Unit_1.Unit {
        constructor(system) {
            super({
                i: (0, f_2.keys)(inputs),
                o: (0, f_2.keys)(outputs),
            }, branch, system, spec.id);
            this.__ = ['U', 'G'];
            this.stateful = false; // RETURN __stateful
            this.__element = false; // RETURN __element
            this._merge = {
                input: {},
                output: {},
            };
            this.getSpec = () => {
                this._ensure();
                return this.__graph.getSpec();
            };
            this.refUnits = () => {
                this._ensure();
                return this.__graph.refUnits();
            };
            this.refMergePin = (mergeId, type) => {
                this._ensure();
                return this.__graph.refMergePin(mergeId, type);
            };
            this.exposeOutputSets = (outputs) => {
                this._ensure();
                return this.__graph.exposeOutputSets(outputs);
            };
            this.exposeOutputSet = (input, id) => {
                this._ensure();
                return this.__graph.exposePinSet('output', id, input);
            };
            this.exposeOutput = (subPinId, pinSpec, id) => {
                this._ensure();
                return this.__graph.exposeOutput(subPinId, pinSpec, id);
            };
            this.coverOutputSet = (id) => {
                this._ensure();
                this.__graph.coverOutputSet(id);
            };
            this.coverOutput = (subPinId, id) => {
                this._ensure();
                return this.__graph.coverOutput(subPinId, id);
            };
            this.plugOutput = (subPinId, subPin, id) => {
                this._ensure();
                return this.__graph.plugOutput(subPinId, subPin, id);
            };
            this.unplugOutput = (subPinId, id) => {
                this._ensure();
                return this.__graph.unplugOutput(subPinId, id);
            };
            this.exposeInputSets = (inputs) => {
                this._ensure();
                return this.__graph.exposeInputSets(inputs);
            };
            this.exposeInputSet = (input, pinId) => {
                this._ensure();
                return this.__graph.exposeInputSet(input, pinId);
            };
            this.exposePinSet = (type, pinId, pinSpec) => {
                this._ensure();
                return this.__graph.exposePinSet(type, pinId, pinSpec);
            };
            this.exposePin = (type, pinId, subPinId, subPinSpec) => {
                this._ensure();
                return this.__graph.exposePin(type, pinId, subPinId, subPinSpec);
            };
            this.exposeInput = (subPinId, pinSpec, pinId) => {
                this._ensure();
                return this.__graph.exposeInput(subPinId, pinSpec, pinId);
            };
            this.coverInputSet = (id) => {
                this._ensure();
                return this.__graph.coverInputSet(id);
            };
            this.coverInput = (subPinId, id) => {
                this._ensure();
                return this.__graph.coverInput(subPinId, id);
            };
            this.coverPinSet = (type, id, emit = true) => {
                this._ensure();
                return this.__graph.coverPinSet(type, id, emit);
            };
            this.plugPin = (type, pinId, subPinId, subPinSpec) => {
                this._ensure();
                return this.plugPin(type, pinId, subPinId, subPinSpec);
            };
            this.plugInput = (subPinId, subPin, id) => {
                this._ensure();
                return this.plugInput(subPinId, subPin, id);
            };
            this.unplugInput = (subPinId, id) => {
                this._ensure();
                return this.unplugInput(subPinId, id);
            };
            this.coverPin = (type, id, subPinId) => {
                this._ensure();
                return this.__graph.coverPin(type, id, subPinId);
            };
            this.getSubPinSpec = (type, pinId, subPinId) => {
                this._ensure();
                return this.__graph.getSubPinSpec(type, pinId, subPinId);
            };
            this.unplugPin = (type, pinId, subPinId) => {
                this._ensure();
                return this.__graph.unplugPin(type, pinId, subPinId);
            };
            this.getExposedInputPin = (id) => {
                this._ensure();
                return this.__graph.getExposedInputPin(id);
            };
            this.getExposedOutputPin = (id) => {
                this._ensure();
                return this.__graph.getExposedOutputPin(id);
            };
            this.getGraphPinData = () => {
                this._ensure();
                return this.__graph.getGraphPinData();
            };
            this.getGraphErr = () => {
                this._ensure();
                return this.__graph.getGraphErr();
            };
            this.getUnitInputData = (unitId) => {
                this._ensure();
                return this.__graph.getUnitInputData(unitId);
            };
            this.addUnitSpecs = (units) => {
                this._ensure();
                return this.__graph.addUnitSpecs(units);
            };
            this.addUnitSpec = (unitId, unit) => {
                this._ensure();
                return this.__graph.addUnitSpec(unitId, unit);
            };
            this.addMerges = (merges) => {
                this._ensure();
                return this.__graph.addMerges(merges);
            };
            this.addMerge = (mergeSpec, mergeId) => {
                this._ensure();
                return this.__graph.addMerge(mergeSpec, mergeId);
            };
            this.addPinToMerge = (mergeId, unitId, type, pinId) => {
                this._ensure();
                return this.__graph.addPinToMerge(mergeId, unitId, type, pinId);
            };
            for (const name in this._input) {
                const i = this._input[name];
                i.addListener('data', (data) => {
                    this._ensure();
                });
            }
            this.addListener('play', () => {
                if (this.__graph) {
                    this.__graph.play();
                }
            });
            this.addListener('pause', () => {
                if (this.__graph) {
                    this.__graph.pause();
                }
            });
            this.addListener('take_err', () => {
                this.__graph.takeErr();
            });
            this.addListener('reset', () => {
                if (this.__graph) {
                    this.__graph.reset();
                }
            });
        }
        setUnitName(unitId, newUnitId, name) {
            this._ensure();
            return this.__graph.setUnitName(unitId, newUnitId, name);
        }
        injectGraph(graph) {
            this._ensure();
            return this.__graph.injectGraph(graph);
        }
        isElement() {
            this._ensure();
            return this.__graph.isElement();
        }
        getMergeSpec(mergeId) {
            this._ensure();
            return this.__graph.getMergeSpec(mergeId);
        }
        appendParentRoot(subComponentId, childId, slotName) {
            this._ensure();
            return this.__graph.appendParentRoot(subComponentId, childId, slotName);
        }
        appendParentRootChildren(subComponentId, children, slotMap) {
            this._ensure();
            return this.__graph.appendParentRootChildren(subComponentId, children, slotMap);
        }
        appendParentChild(component, slotName) {
            this._ensure();
            return this.__graph.appendParentChild(component, slotName);
        }
        removeParentChild(component) {
            this._ensure();
            return this.__graph.removeParentChild(component);
        }
        appendRoot(subComponentId) {
            this._ensure();
            return this.__graph.appendRoot(subComponentId);
        }
        removeRoot(subComponentId) {
            this._ensure();
            return this.__graph.removeRoot(subComponentId);
        }
        moveSubgraphInto(graphId, nodeIds, nextIdMap, nextPinMap, nextMergePinId, nextPlugSpec, nextSubComponentParent, nextSubComponentChildrenMap) {
            this._ensure();
            return this.__graph.moveSubgraphInto(graphId, nodeIds, nextIdMap, nextPinMap, nextMergePinId, nextPlugSpec, nextSubComponentParent, nextSubComponentChildrenMap);
        }
        registerRoot(component) {
            this._ensure();
            return this.__graph.registerRoot(component);
        }
        unregisterRoot(component) {
            this._ensure();
            return this.__graph.unregisterRoot(component);
        }
        registerParentRoot(component, slotName) {
            this._ensure();
            return this.__graph.registerParentRoot(component, slotName);
        }
        unregisterParentRoot(component) {
            this._ensure();
            return this.__graph.unregisterParentRoot(component);
        }
        _load() {
            // console.log('Lazy', '_load')
            const Class = (0, fromSpec_1.fromSpec)(spec, specs, branch);
            this.__graph = new Class(this.__system);
            this.__graph.addListener('err', (err) => {
                this.err(err);
            });
            this.__graph.addListener('take_err', () => {
                this.takeErr();
            });
            (0, f_1.default)(this.__graph.getOutputs(), (output, name) => {
                const merge = new Merge_1.default(this.__system);
                merge.play();
                this._merge.output[name] = merge;
                merge.setInput(name, output);
                merge.setOutput(name, this._output[name]);
            });
            (0, f_1.default)(this.__graph.getInputs(), (input, name) => {
                const merge = new Merge_1.default(this.__system);
                merge.play();
                this._merge.input[name] = merge;
                merge.setInput(name, this._input[name]);
                merge.setOutput(name, input);
            });
            this.__graph.play();
        }
        _ensure() {
            // console.log('Lazy', '_ensure')
            if (!this.__graph) {
                this._load();
            }
        }
        getBundleSpec() {
            this._ensure();
            return this.__graph.getBundleSpec();
        }
        getSpecs() {
            this._ensure();
            return this.__graph.getSpecs();
        }
        getUnitState(unitId) {
            this._ensure();
            return this.__graph.getUnitState(unitId);
        }
        getGraphState() {
            this._ensure();
            return this.__graph.getGraphState();
        }
        getGraphChildren() {
            this._ensure();
            return this.__graph.getGraphChildren();
        }
        pushChild(Bundle) {
            this._ensure();
            return this.__graph.pushChild(Bundle);
        }
        appendChild(Bundle) {
            this._ensure();
            return this.__graph.appendChild(Bundle);
        }
        insertChild(Bundle, at) {
            this._ensure();
            return this.__graph.insertChild(Bundle, at);
        }
        pullChild(at) {
            this._ensure();
            return this.__graph.pullChild(at);
        }
        removeChild(at) {
            this._ensure();
            return this.__graph.removeChild(at);
        }
        hasChild(at) {
            this._ensure();
            return this.__graph.hasChild(at);
        }
        refChild(at) {
            this._ensure();
            return this.__graph.refChild(at);
        }
        refChildren() {
            this._ensure();
            return this.__graph.refChildren();
        }
        refSlot(slotName) {
            this._ensure();
            return this.__graph.refSlot(slotName);
        }
        isExposedOutput(pin) {
            this._ensure();
            return this.__graph.isExposedOutput(pin);
        }
        setPinSetId(type, pinId, nextPinId) {
            this._ensure();
            return this.__graph.setPinSetId(type, pinId, nextPinId);
        }
        setPinSetFunctional(type, name, functional) {
            this._ensure();
            return this.__graph.setPinSetFunctional(type, name, functional);
        }
        isExposedInput(pin) {
            this._ensure();
            return this.__graph.isExposedInput(pin);
        }
        getExposedPinSpec(pinId, type) {
            this._ensure();
            return this.__graph.getExposedPinSpec(type, pinId);
        }
        isExposedInputPinId(pinId) {
            this._ensure();
            return this.__graph.isExposedInputPinId(pinId);
        }
        isExposedOutputPinId(pinId) {
            this._ensure();
            return this.__graph.isExposedOutputPinId(pinId);
        }
        getExposedInputSpec(pinId) {
            this._ensure();
            return this.__graph.getExposedInputSpec(pinId);
        }
        getExposedOutputSpec(pinId) {
            this._ensure();
            return this.__graph.getExposedOutputSpec(pinId);
        }
        hasUnit(id) {
            this._ensure();
            return this.__graph.hasUnit(id);
        }
        hasMerge(id) {
            this._ensure();
            return this.__graph.hasMerge(id);
        }
        getGraphUnitSpec(unitId) {
            this._ensure();
            return this.__graph.getGraphUnitSpec(unitId);
        }
        refUnit(id) {
            this._ensure();
            return this.__graph.refUnit(id);
        }
        getUnitByPath(path) {
            this._ensure();
            return this.__graph.getUnitByPath(path);
        }
        getUnitPin(id, type, pinId) {
            this._ensure();
            return this.__graph.getUnitPin(id, type, pinId);
        }
        getUnitPinData(id, type, pinId) {
            this._ensure();
            return this.__graph.getUnitPinData(id, type, pinId);
        }
        getUnitInput(id, pinId) {
            this._ensure();
            return this.__graph.getUnitInput(id, pinId);
        }
        getUnitOutput(id, pinId) {
            this._ensure();
            return this.__graph.getUnitOutput(id, pinId);
        }
        setUnitErr(unitId, err) {
            this._ensure();
            return this.__graph.setUnitErr(unitId, err);
        }
        takeUnitErr(unitId) {
            this._ensure();
            return this.__graph.takeUnitErr(unitId);
        }
        refMerges() {
            this._ensure();
            return this.__graph.refMerges();
        }
        refMerge(mergeId) {
            this._ensure();
            return this.__graph.refMerge(mergeId);
        }
        getMergeCount() {
            this._ensure();
            return this.__graph.getMergeCount();
        }
        getMergeUnitCount(mergeId) {
            this._ensure();
            return this.__graph.getMergeUnitCount(mergeId);
        }
        getMergePinCount(mergeId) {
            this._ensure();
            return this.__graph.getMergePinCount(mergeId);
        }
        moveUnit(id, unitId, inputId) {
            this._ensure();
            return this.__graph.moveUnit(id, unitId, inputId);
        }
        moveUnitInto(graphId, unitId, nextUnitId) {
            this._ensure();
            return this.__graph.moveUnitInto(graphId, unitId, nextUnitId, {
                input: new Set(),
                output: new Set(),
            }, new Set(), {
                input: {},
                output: {},
            }, null, []);
        }
        movePlugInto(graphId, type, pinId, subPinId, subPinSpec) {
            throw new Error('Method not implemented.');
        }
        moveLinkPinInto(graphId, unitId, type, pinId) {
            this._ensure();
            return this.__graph.moveLinkPinInto(graphId, unitId, type, pinId);
        }
        moveMergeInto(graphId, mergeId, nextInputMergeId, nextOutputMergeId) {
            this._ensure();
            return this.__graph.moveMergeInto(graphId, mergeId, nextInputMergeId, nextOutputMergeId);
        }
        removeUnit(unitId) {
            this._ensure();
            return this.__graph.removeUnit(unitId);
        }
        addUnitGhost(unitId, nextUnitId, nextUnitBundle, nextUnitPinMap) {
            this._ensure();
            return this.__graph.addUnitGhost(unitId, nextUnitId, nextUnitBundle, nextUnitPinMap);
        }
        removeUnitGhost(unitId, nextUnitId, nextUnitSpec) {
            this._ensure();
            return this.__graph.removeUnitGhost(unitId, nextUnitId, nextUnitSpec);
        }
        swapUnitGhost(unitId, nextUnitId, spec) {
            throw new Error('Method not implemented.');
        }
        explodeUnit(unitId, mapUnitId, mapMergeId) {
            this._ensure();
            return this.__graph.explodeUnit(unitId, mapUnitId, mapMergeId);
        }
        removeMerge(mergeId) {
            this._ensure();
            return this.__graph.removeMerge(mergeId);
        }
        removePinFromMerge(mergeId, unitId, type, pinId) {
            this._ensure();
            return this.__graph.removePinFromMerge(mergeId, unitId, type, pinId);
        }
        mergeMerges(mergeIds) {
            this._ensure();
            return this.__graph.mergeMerges(mergeIds);
        }
        isPinMergedTo(mergeId, unitId, type, pinId) {
            this._ensure();
            return this.__graph.isPinMergedTo(mergeId, unitId, type, pinId);
        }
        setUnitPinConstant(unitId, type, pinId, constant) {
            this._ensure();
            return this.__graph.setUnitPinConstant(unitId, type, pinId, constant);
        }
        setUnitInputConstant(unitId, pinId, constant) {
            this._ensure();
            return this.__graph.setUnitInputConstant(unitId, pinId, constant);
        }
        setUnitOutputConstant(unitId, pinId, constant) {
            this._ensure();
            return this.__graph.setUnitOutputConstant(unitId, pinId, constant);
        }
        setUnitInputIgnored(unitId, pinId, ignored) {
            this._ensure();
            return this.__graph.setUnitPinIgnored(unitId, 'input', pinId, ignored);
        }
        setUnitOutputIgnored(unitId, pinId, ignored) {
            this._ensure();
            return this.__graph.setUnitPinIgnored(unitId, 'output', pinId, ignored);
        }
        setUnitPinIgnored(unitId, type, pinId, ignored) {
            this._ensure();
            return this.__graph.setUnitPinIgnored(unitId, type, pinId, ignored);
        }
        setUnitPinData(unitId, type, pinId, data) {
            this._ensure();
            return this.__graph.setUnitPinData(unitId, type, pinId, data);
        }
        setUnitInputData(unitId, pinId, data) {
            this._ensure();
            return this.__graph.setUnitInputData(unitId, pinId, data);
        }
        setUnitOutputData(unitId, pinId, data) {
            this._ensure();
            return this.__graph.setUnitOutputData(unitId, pinId, data);
        }
        getGraphMergeInputData() {
            this._ensure();
            return this.__graph.getGraphMergeInputData();
        }
        setMetadata(path, data) {
            this._ensure();
            this.__graph.setMetadata(path, data);
        }
        setGraphState(state) {
            this._ensure();
            this.__graph.setGraphState(state);
        }
    }
    Lazy.__bundle = {
        unit: {
            id,
        },
        specs: {},
    };
    return Lazy;
}
exports.lazyFromSpec = lazyFromSpec;
//# sourceMappingURL=Lazy.js.map