"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.lazyFromSpec = lazyFromSpec;
const Merge_1 = __importDefault(require("../Class/Merge"));
const Unit_1 = require("../Class/Unit");
const f_1 = __importDefault(require("../system/core/object/ForEachKeyValue/f"));
const f_2 = require("../system/f/object/Keys/f");
const util_1 = require("./util");
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.lazy = true;
            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.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.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.addUnit = (unitId, unit, ...extra) => {
                this._ensure();
                return this.__graph.addUnit(unitId, unit, ...extra);
            };
            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();
                }
            });
        }
        setFork(fork) {
            this._ensure();
            this.__graph.setFork(fork);
        }
        setName(name, ...extra) {
            this._ensure();
            this.__graph.setName(name, ...extra);
        }
        stopPropagation(name) {
            this._ensure();
            return this.__graph.stopPropagation(name);
        }
        attachText(type, text) {
            this._ensure();
            return this.__graph.attachText(type, text);
        }
        attachDropTarget() {
            this._ensure();
            return this.__graph.attachDropTarget();
        }
        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();
        }
        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);
        }
        setMergeData(mergeId, data, ...extra) {
            this._ensure();
            return this.__graph.setMergeData(mergeId, data);
        }
        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, specId, selection, map, moves]) {
            this._ensure();
            return this.__graph.moveSubgraphOutOf(graphId, specId, selection, map, moves);
        }
        removeUnitPinData(unitId, type, pinId) {
            this._ensure();
            return this.__graph.removeUnitPinData(unitId, type, pinId);
        }
        addUnitSpec(unitId, unit, parentId, emit = true) {
            this._ensure();
            return this.__graph.addUnitSpec(unitId, unit, parentId, emit);
        }
        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, util_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, emit) {
            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, index) {
            this._ensure();
            return this.__graph.moveSubComponentRoot(subComponentId, children, slotMap, index);
        }
        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);
        }
        moveSubgraphInto(...[graphId, specId, selection, map, moves]) {
            this._ensure();
            return this.__graph.moveSubgraphInto(graphId, specId, selection, map, moves);
        }
        registerRoot(component, subComponentId, emit) {
            this._ensure();
            return this.__graph.registerRoot(component, subComponentId, emit);
        }
        unregisterRoot(component, subComponentId, emit) {
            this._ensure();
            return this.__graph.unregisterRoot(component, subComponentId, emit);
        }
        registerParentRoot(component, subComponentId, slotName, at, emit) {
            this._ensure();
            return this.__graph.registerParentRoot(component, subComponentId, slotName, at, emit);
        }
        unregisterParentRoot(component, subComponentId, emit) {
            this._ensure();
            return this.__graph.unregisterParentRoot(component, subComponentId, emit);
        }
        detach(host, opt) {
            this._ensure();
            return this.__graph.detach(host, opt);
        }
        _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();
        }
        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);
        }
        appendChildren(Classes) {
            this._ensure();
            return this.__graph.appendChildren(Classes);
        }
        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);
        }
        refRoot(at) {
            this._ensure();
            return this.__graph.refRoot(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);
        }
        setSlot(slotName, subComponentId) {
            this._ensure();
            return this.__graph.setSlot(slotName, subComponentId);
        }
        getSlot(slotName) {
            this._ensure();
            return this.__graph.getSlot(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();
        }
        setPinSetId(type, pinId, newPinId) {
            this._ensure();
            return this.__graph.setPinSetId(type, pinId, newPinId);
        }
        setPinSetFunctional(type, name, functional) {
            this._ensure();
            return this.__graph.setPinSetFunctional(type, name, functional);
        }
        setPinSetDefaultIgnored(type, name, ignored) {
            this._ensure();
            return this.__graph.setPinSetDefaultIgnored(type, name, ignored);
        }
        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);
        }
        removeUnit(unitId, ...extra) {
            this._ensure();
            return this.__graph.removeUnit(unitId, ...extra);
        }
        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);
        }
        setPlugData(type, pinId, subPinId, data) {
            this._ensure();
            return this.__graph.setPlugData(type, pinId, subPinId, 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);
        }
        setUnitMetadata(unitId, path, data) {
            this._ensure();
            this.__graph.setUnitMetadata(unitId, path, data);
        }
        setUnitPinMetadata(unitId, type, pinId, path, data) {
            this._ensure();
            this.__graph.setUnitPinMetadata(unitId, type, pinId, path, data);
        }
        setPinMetadata(type, pinId, path, data) {
            this._ensure();
            this.__graph.setPinMetadata(type, pinId, path, data);
        }
    }
    Lazy.__bundle = {
        unit: {
            id,
        },
        specs: {},
    };
    return Lazy;
}
//# sourceMappingURL=Lazy.js.map