"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.unitBundleSpec = unitBundleSpec;
exports.unitBundleSpecById = unitBundleSpecById;
exports.bundleSpec = bundleSpec;
const spec_1 = require("./client/spec");
const evaluateDataValue_1 = require("./spec/evaluateDataValue");
const object_1 = require("./util/object");
const weakMerge_1 = require("./weakMerge");
function unitBundleSpec(unit, specs) {
    const { id } = unit;
    const custom = {};
    _bundleUnit(unit, specs, custom, new Set());
    return {
        unit: {
            id,
            ...unit,
        },
        specs: custom,
    };
}
function unitBundleSpecById(id, specs) {
    const spec = (0, spec_1.getSpec)(specs, id);
    const { base } = spec;
    if (base) {
        return {
            unit: {
                id,
            },
        };
    }
    else {
        const custom = {
            [id]: spec,
        };
        _bundle(spec, specs, custom, new Set());
        return {
            unit: {
                id,
            },
            specs: custom,
        };
    }
}
function bundleSpec(spec, specs) {
    const custom = {};
    const branch = new Set([]);
    _bundle(spec, specs, custom, branch);
    return { spec, specs: custom };
}
function _bundle(spec, specs, custom, branch) {
    if (!spec.id) {
        throw new Error('spec id is required');
    }
    if (spec.system) {
        return;
    }
    if (branch.has(spec.id)) {
        return;
    }
    branch.add(spec.id);
    _bundleUnits(spec, specs, custom, branch);
}
function _bundleUnit(unit, specs, custom, branch) {
    var _a, _b, _c;
    const { id, input = {} } = unit;
    for (const inputId in input) {
        const _input = (_a = input[inputId]) !== null && _a !== void 0 ? _a : {};
        const { data } = _input;
        if (data !== undefined) {
            const dataRef = (0, evaluateDataValue_1.evaluateDataValue)(data, specs, {});
            for (const path of (_b = dataRef.ref) !== null && _b !== void 0 ? _b : []) {
                const bundle = (0, object_1.deepGet)(dataRef.data, path);
                for (const specId in bundle.specs) {
                    const spec = bundle.specs[specId];
                    custom[specId] = spec;
                    _bundle(spec, (0, weakMerge_1.weakMerge)(specs, (_c = bundle.specs) !== null && _c !== void 0 ? _c : {}), custom, branch);
                }
                _bundleUnit(bundle.unit, specs, custom, branch);
                if (bundle.specs) {
                    delete bundle.specs;
                }
            }
        }
    }
    const _spec = (0, spec_1.getSpec)((0, weakMerge_1.weakMerge)(specs, custom), id);
    if (!custom[id] && !(0, spec_1.isSystemSpecId)(specs, id)) {
        custom[id] = _spec;
    }
    _bundle(_spec, specs, custom, new Set(branch));
}
function _bundleUnits(spec, specs, custom, branch) {
    const { units = {} } = spec;
    for (const unit_id in units) {
        const unit = units[unit_id];
        _bundleUnit(unit, specs, custom, branch);
    }
}
//# sourceMappingURL=bundle.js.map