"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 spec_1 = require("../client/spec");
const f_1 = require("../system/core/object/ForEachKeyValue/f");
const f_2 = require("../system/f/object/Keys/f");
function lazyFromSpec(spec, specs, branch = {}, fromSpec) {
    const { inputs, outputs, id } = spec;
    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.__element = false;
            this._merge = {
                input: {},
                output: {},
            };
            this.getSpec = () => {
                this._ensure();
                return this.__graph.getSpec();
            };
            this.getUnits = () => {
                this._ensure();
                return this.__graph.getUnits();
            };
            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.addUnits = (units) => {
                this._ensure();
                return this.__graph.addUnitSpecs(units);
            };
            this.addUnit = (unitId, unit) => {
                this._ensure();
                return this.__graph.addUnit(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();
                }
            });
        }
        stopPropagation(name) {
            this._ensure();
            return this.__graph.stopPropagation(name);
        }
        getSetup() {
            this._ensure();
            return this.__graph.getSetup();
        }
        setUnitPinSetId(unitId, type, pinId, newPinId, ...extra) {
            this._ensure();
            return this.__graph.setUnitPinSetId(unitId, type, pinId, newPinId, ...extra);
        }
        fork() {
            this._ensure();
            return this.__graph.fork();
        }
        startTransaction() {
            this._ensure();
            return this.__graph.startTransaction();
        }
        endTransaction() {
            this._ensure();
            return this.__graph.endTransaction();
        }
        getMergeData(mergeId) {
            this._ensure();
            return this.__graph.getPlugSpecs();
        }
        getPlugSpecs() {
            this._ensure();
            return this.__graph.getPlugSpecs();
        }
        hasMergePin(mergeId, unitId, type, pinId) {
            this._ensure();
            return this.__graph.hasMergePin(mergeId, unitId, type, pinId);
        }
        getMergesSpec() {
            this._ensure();
            return this.__graph.getMergesSpec();
        }
        getUnitPinData(unitId, type, pinId) {
            this._ensure();
            return this.__graph.getUnitPinData(unitId, type, pinId);
        }
        isUnitPinConstant(unitId, type, pinId) {
            this._ensure();
            return this.__graph.isUnitPinConstant(unitId, type, pinId);
        }
        isUnitPinRef(unitId, type, pinId) {
            this._ensure();
            return this.__graph.isUnitPinRef(unitId, type, pinId);
        }
        getExposedPinSpecs() {
            this._ensure();
            return this.__graph.getExposedPinSpecs();
        }
        getPinPlugCount(type, pinId) {
            this._ensure();
            return this.__graph.getPinPlugCount(type, pinId);
        }
        moveRoot(parentId, childId, to, slotName) {
            this._ensure();
            return this.__graph.moveRoot(parentId, childId, to, slotName);
        }
        hasPlug(type, pinId, subPinId) {
            this._ensure();
            return this.__graph.hasPlug(type, pinId, subPinId);
        }
        removePinOrMerge(mergeId, unitId, type, pinId, ...extra) {
            this._ensure();
            return this.__graph.removePinOrMerge(mergeId, unitId, type, pinId, ...extra);
        }
        removeMergeData(mergeId) {
            this._ensure();
            return this.__graph.removeMergeData(mergeId);
        }
        setUnitSize(unitId, width, height) {
            this._ensure();
            return this.__graph.setUnitSize(unitId, width, height);
        }
        setSubComponentSize(unitId, width, height) {
            this._ensure();
            return this.__graph.setSubComponentSize(unitId, width, height);
        }
        setComponentSize(unitId, width, height) {
            this._ensure();
            return this.__graph.setComponentSize(unitId, width, height);
        }
        moveSubgraphOutOf(...[graphId, graphBundle, nextSpecId, nodeIds, nextIdMap, nextPinIdMap, nextMergePinId, nextPlugSpec, nextSubComponentParentMap, nextSubComponentChildrenMap,]) {
            this._ensure();
            return this.__graph.moveSubgraphOutOf(graphId, graphBundle, nextSpecId, nodeIds, nextIdMap, nextPinIdMap, nextMergePinId, nextPlugSpec, nextSubComponentParentMap, nextSubComponentChildrenMap);
        }
        removeUnitPinData(unitId, type, pinId) {
            this._ensure();
            return this.__graph.removeUnitPinData(unitId, type, pinId);
        }
        addUnitSpecs(units) {
            this._ensure();
            return this.__graph.addUnitSpecs(units);
        }
        addUnitSpec(unitId, unit, emit) {
            this._ensure();
            return this.__graph.addUnitSpec(unitId, unit);
        }
        bulkEdit(actions) {
            this._ensure();
            return this.__graph.bulkEdit(actions);
        }
        setUnitId(unitId, newUnitId, name, specId) {
            this._ensure();
            return this.__graph.setUnitId(unitId, newUnitId, name, specId);
        }
        isElement() {
            return (0, spec_1.isComponentSpec)(spec);
        }
        getMergeSpec(mergeId) {
            this._ensure();
            return this.__graph.getMergeSpec(mergeId);
        }
        reorderRoot(component, to) {
            this._ensure();
            return this.__graph.reorderRoot(component, to);
        }
        reorderParentRoot(component, to) {
            this._ensure();
            return this.__graph.reorderParentRoot(component, to);
        }
        reorderSubComponent(parentId, childId, to) {
            this._ensure();
            return this.__graph.reorderSubComponent(parentId, childId, to);
        }
        moveSubComponentRoot(subComponentId, children, slotMap) {
            this._ensure();
            return this.__graph.moveSubComponentRoot(subComponentId, children, slotMap);
        }
        appendParentChild(component, slotName) {
            this._ensure();
            return this.__graph.appendParentChild(component, slotName);
        }
        removeParentChild(component) {
            this._ensure();
            return this.__graph.removeParentChild(component);
        }
        removeRoot(subComponentId) {
            this._ensure();
            return this.__graph.removeRoot(subComponentId);
        }
        detach() {
            this._ensure();
            return this.__graph.detach();
        }
        moveSubgraphInto(...[graphId, graphBundle, nextSpecId, nodeIds, nextIdMap, nextPinIdMap, nextMergePinId, nextPlugSpec, nextSubComponentParentMap, nextSubComponentChildrenMap,]) {
            this._ensure();
            return this.__graph.moveSubgraphInto(graphId, graphBundle, nextSpecId, nodeIds, nextIdMap, nextPinIdMap, nextMergePinId, nextPlugSpec, nextSubComponentParentMap, 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', spec.name)
            const Class = fromSpec(spec, specs, this.__system.classes, 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();
        }
        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);
        }
        animate(keyframes, opt) {
            this._ensure();
            return this.__graph.animate(keyframes, opt);
        }
        cancelAnimation(id) {
            this._ensure();
            return this.__graph.cancelAnimation(id);
        }
        getAnimations() {
            this._ensure();
            return this.__graph.getAnimations();
        }
        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);
        }
        getUnit(id) {
            this._ensure();
            return this.__graph.getUnit(id);
        }
        getUnitByPath(path) {
            this._ensure();
            return this.__graph.getUnitByPath(path);
        }
        getUnitPin(id, type, pinId) {
            this._ensure();
            return this.__graph.getUnitPin(id, type, pinId);
        }
        getUnitData(id, type, pinId) {
            this._ensure();
            return this.__graph.getUnitData(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);
        }
        getMerges() {
            this._ensure();
            return this.__graph.getMerges();
        }
        getMerge(mergeId) {
            this._ensure();
            return this.__graph.getMerge(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);
        }
        removeUnit(unitId, ...extra) {
            this._ensure();
            return this.__graph.removeUnit(unitId, ...extra);
        }
        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) {
            this._ensure();
            this.__graph.swapUnitGhost(unitId, nextUnitId, spec);
        }
        explodeUnit(unitId, mapUnitId, mapMergeId, mapPlugId) {
            this._ensure();
            return this.__graph.explodeUnit(unitId, mapUnitId, mapMergeId, mapPlugId);
        }
        removeMerge(mergeId) {
            this._ensure();
            return this.__graph.removeMerge(mergeId);
        }
        removePinFromMerge(mergeId, unitId, type, pinId) {
            this._ensure();
            return this.__graph.removePinFromMerge(mergeId, unitId, type, pinId);
        }
        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