"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.graphFromSpec = exports.classFromSpec = exports.applyDefaultIgnored = exports.fromSpec = exports.extractGraphSpecs = void 0;
const Graph_1 = require("../Class/Graph");
const weakMerge_1 = require("../weakMerge");
const bundleClass_1 = require("./bundleClass");
const idFromUnitValue_1 = require("./idFromUnitValue");
const parser_1 = require("./parser");
function extractGraphSpecs(spec, specs, graphs = {}, classes = {}) {
    var _a;
    graphs[spec.id] = spec;
    const { units } = spec;
    for (const unit_id in units) {
        const unit = units[unit_id];
        const { id, input } = unit;
        for (const inputId in input) {
            const _input = (_a = input[inputId]) !== null && _a !== void 0 ? _a : {};
            const { data } = _input;
            if (data) {
                const tree = (0, parser_1.getTree)(data);
                if (tree.type === parser_1.TreeNodeType.Unit) {
                    const { value } = tree;
                    const bundle = (0, idFromUnitValue_1.evaluateBundleStr)(value, specs, classes);
                    for (const specId in bundle.specs) {
                        const spec = bundle.specs[specId];
                        graphs[specId] = spec;
                    }
                    for (const specId in bundle.specs) {
                        const spec = bundle.specs[specId];
                        extractGraphSpecs(spec, (0, weakMerge_1.weakMerge)(specs, graphs), graphs);
                    }
                }
            }
        }
        const unit_spec = specs[id];
        if (!unit_spec) {
            return;
        }
        const { system } = unit_spec;
        if (!system) {
            if (!graphs[id]) {
                graphs[id] = unit_spec;
                extractGraphSpecs(graphs[id], specs, graphs);
            }
        }
    }
    return graphs;
}
exports.extractGraphSpecs = extractGraphSpecs;
function fromSpec(spec, specs_, classes = {}, branch = {}) {
    const Class = classFromSpec(spec, specs_, classes, branch);
    const { id } = spec;
    if (!id) {
        throw new Error('spec id is required');
    }
    const specs = extractGraphSpecs(spec, specs_, {});
    const unit = { id };
    const Bundle = (0, bundleClass_1.bundleClass)(Class, { unit, specs });
    return Bundle;
}
exports.fromSpec = fromSpec;
function applyDefaultIgnored(spec, specs) {
    const { name, units } = spec;
    for (const unitId in units) {
        const unitSpec = units[unitId];
        unitSpec.input = unitSpec.input || {};
        unitSpec.output = unitSpec.output || {};
        const { id, input, output } = unitSpec;
        const spec = specs[id];
        const { inputs, outputs } = spec;
        function setIgnored(unitPinSpec, pinSpec) {
            const { ignored } = unitPinSpec;
            if (ignored === undefined) {
                const { defaultIgnored } = pinSpec;
                if (defaultIgnored === true) {
                    unitPinSpec.ignored = true;
                }
            }
        }
        for (const inputId in inputs) {
            const inputPinSpec = inputs[inputId];
            input[inputId] = input[inputId] || {};
            const unitInputPinSpec = input[inputId];
            setIgnored(unitInputPinSpec, inputPinSpec);
        }
        for (const outputId in outputs) {
            const outputPinSpec = outputs[outputId];
            output[outputId] = output[outputId] || {};
            const unitOutputPinSpec = output[outputId];
            setIgnored(unitOutputPinSpec, outputPinSpec);
        }
    }
}
exports.applyDefaultIgnored = applyDefaultIgnored;
function classFromSpec(spec, specs, classes, branch = {}) {
    applyDefaultIgnored(spec, specs);
    const { id, name } = spec;
    if (classes[id]) {
        return classes[id];
    }
    class Class extends Graph_1.Graph {
        constructor(system) {
            const spec = system.getSpec(id);
            super(spec, branch, system, id);
        }
    }
    Object.defineProperty(Class, 'name', {
        value: name,
    });
    if (!branch[id]) {
        // classes[id] = Class
    }
    return Class;
}
exports.classFromSpec = classFromSpec;
function graphFromSpec(system, spec, specs, branch = {}) {
    applyDefaultIgnored(spec, specs);
    return new Graph_1.Graph(spec, branch, system, spec.id);
}
exports.graphFromSpec = graphFromSpec;
//# sourceMappingURL=fromSpec.js.map