"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.treeComplexityById = treeComplexityById;
exports.treeComplexity = treeComplexity;
exports.graphComplexityById = graphComplexityById;
exports.graphComplexity = graphComplexity;
exports.graphMergeComplexity = graphMergeComplexity;
exports.graphUnitComplexity = graphUnitComplexity;
exports.specComplexityById = specComplexityById;
exports.specComplexity = specComplexity;
const f_1 = require("../system/f/object/Keys/f");
const object_1 = require("../util/object");
const weakMerge_1 = require("../weakMerge");
const evaluateDataValue_1 = require("./evaluateDataValue");
const HIRC = 1; // Human Information Retrieval Cost
const GFC = 2; // Graph Fundamental Complexity
// tree complexity
function treeComplexityById(specs, classes, id, known = {}) {
    if (known[id]) {
        return HIRC;
    }
    known[id] = true;
    const spec = specs[id];
    return treeComplexity(specs, classes, spec, known);
}
function treeComplexity(specs, classes, spec, known = {}) {
    let c = 0;
    const { base } = spec;
    if (base) {
        const { metadata = {} } = spec;
        const { complexity = 1 } = metadata;
        return complexity;
    }
    else {
        c += GFC;
        const { units = {} } = spec;
        for (const unitId in units) {
            const unit = units[unitId];
            const { id, input = {} } = unit;
            for (const inputId in input) {
                const _input = input[inputId] ?? {};
                const { data } = _input;
                if (data !== undefined) {
                    const dataRef = (0, evaluateDataValue_1.evaluateDataValue)(data, specs, classes);
                    for (const path of dataRef.ref ?? []) {
                        const bundle = (0, object_1.deepGet)(dataRef.data, path);
                        c += treeComplexityById((0, weakMerge_1.weakMerge)(specs, bundle.specs ?? {}), classes, bundle.unit.id, known);
                    }
                }
            }
            c += treeComplexityById(specs, classes, id, known);
        }
    }
    return c;
}
// layer complexity
function graphComplexityById(specs, path) {
    const graph = specs[path];
    return graphComplexity(specs, graph);
}
function graphComplexity(specs, graph) {
    let c = specComplexity(graph);
    c += graphMergeComplexity(graph);
    c += graphUnitComplexity(specs, graph);
    return c;
}
function graphMergeComplexity(graph) {
    const { merges = {} } = graph;
    return (0, f_1.keys)(merges).length;
}
function graphUnitComplexity(specs, graph) {
    const known = {};
    const { units = {} } = graph;
    let c = 0;
    for (const unitId in units) {
        const { id } = units[unitId];
        // if you already know a unit, just grab from memory
        if (!known[id]) {
            const spec = specs[id];
            c += specComplexity(spec);
            known[id] = true;
        }
        else {
            c += HIRC;
        }
    }
    return c;
}
// interface complexity
function specComplexityById(specs, id) {
    const spec = specs[id];
    return specComplexity(spec);
}
function specComplexity(spec) {
    return HIRC + (0, f_1.keys)(spec.inputs || {}).length + (0, f_1.keys)(spec.outputs || {}).length;
}
//# sourceMappingURL=complexity.js.map