"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.extractSubSpec = void 0;
const deepSet_1 = require("../deepSet");
const emptyIO_1 = require("./emptyIO");
function extractSubSpec(specs, spec, selection, newUnitId, newSpecId) {
    let parentSpec = {};
    let newSpec = {};
    const { units = [], links, merges = [] } = selection;
    const subUnitSet = new Set(units);
    const subMergeSet = new Set(merges);
    const subUnitInputToMerges = {};
    const subUnitOutputToMerges = {};
    for (const mergeId of merges) {
        const merge = spec.merges[mergeId];
        for (const unitId in merge) {
            subUnitInputToMerges[unitId] = subUnitInputToMerges[unitId] || {};
            subUnitOutputToMerges[unitId] = subUnitOutputToMerges[unitId] || {};
            const mergeUnit = merge[unitId];
            const { input = {}, output = {} } = mergeUnit;
            for (const inputId in input) {
                subUnitInputToMerges[unitId][inputId] = mergeId;
            }
            for (const outputId in output) {
                subUnitOutputToMerges[unitId][outputId] = mergeId;
            }
        }
    }
    const subUnitInputSets = {};
    const subUnitOutputSets = {};
    for (const unitId in links.input) {
        const unitInput = links.input[unitId];
        subUnitInputSets[unitId] = new Set(unitInput);
    }
    for (const unitId in links.output) {
        const unitOutput = links.output[unitId];
        subUnitOutputSets[unitId] = new Set(unitOutput);
    }
    const mergeTotalCounts = {};
    const mergeTotalSelectedCounts = {};
    const unitInputToMerges = {};
    const unitOutputToMerges = {};
    for (const mergeId in spec.merges) {
        mergeTotalCounts[mergeId] = 0;
        mergeTotalSelectedCounts[mergeId] = 0;
        const merge = spec.merges[mergeId];
        for (const unitId in merge) {
            unitInputToMerges[unitId] = unitInputToMerges[unitId] || {};
            unitOutputToMerges[unitId] = unitOutputToMerges[unitId] || {};
            const mergeUnit = merge[unitId];
            const { input = {}, output = {} } = mergeUnit;
            for (const inputId in input) {
                mergeTotalCounts[mergeId]++;
                if (subUnitSet.has(unitId)) {
                    mergeTotalSelectedCounts[mergeId]++;
                }
                unitInputToMerges[unitId][inputId] = mergeId;
            }
            for (const outputId in output) {
                mergeTotalCounts[mergeId]++;
                if (subUnitSet.has(unitId)) {
                    mergeTotalSelectedCounts[mergeId]++;
                }
                unitOutputToMerges[unitId][outputId] = mergeId;
            }
        }
    }
    for (const unitId in spec.units) {
        const unit = spec.units[unitId];
        if (subUnitSet.has(unitId)) {
            newSpec = (0, deepSet_1.default)(newSpec, ['units', unitId], unit);
        }
        else {
            parentSpec = (0, deepSet_1.default)(parentSpec, ['units', unitId], unit);
        }
    }
    const newSpecSubPinId = {
        input: {},
        output: {},
    };
    function suffixId(init, obj) {
        let id = init;
        let i = 0;
        while (obj[id]) {
            id = init + i;
            i++;
        }
        return id;
    }
    const unitMergePinRename = {};
    for (const unitId in spec.units) {
        const unit = spec.units[unitId];
        const { id } = unit;
        const unitSpec = specs[id];
        const subUnitInputSet = subUnitInputSets[unitId] || new Set();
        const subUnitOutputSet = subUnitOutputSets[unitId] || new Set();
        const unitInputToMerge = unitInputToMerges[unitId] || {};
        const unitOutputToMerge = unitOutputToMerges[unitId] || {};
        const subUnitInputToMerge = subUnitInputToMerges[unitId] || {};
        const subUnitOutputToMerge = subUnitOutputToMerges[unitId] || {};
        const { inputs = {}, outputs = {} } = unitSpec;
        unitMergePinRename[unitId] = (0, emptyIO_1.emptyIO)({}, {});
        function addNewSpecPin(type, unitId, pinId) {
            var _a;
            const _pinId = suffixId(pinId, newSpec[`${type}s`] || {});
            const newSpecTypeSubPinId = newSpecSubPinId[type];
            const subPinId = ((_a = newSpecTypeSubPinId[_pinId]) !== null && _a !== void 0 ? _a : -1) + 1;
            newSpecTypeSubPinId[_pinId] = subPinId;
            newSpec = (0, deepSet_1.default)(newSpec, [`${type}s`, _pinId], {
                plug: { [subPinId]: { unitId, pinId } },
            });
            unitMergePinRename[unitId][type][pinId] = _pinId;
            return _pinId;
        }
        function addNewSpecInput(unitId, pinId) {
            return addNewSpecPin('input', unitId, pinId);
        }
        function addNewSpecOutput(unitId, pinId) {
            return addNewSpecPin('output', unitId, pinId);
        }
        for (const inputId in inputs) {
            unitMergePinRename[unitId]['input'][inputId] = inputId;
            const inputMergeId = unitInputToMerge[inputId];
            if (inputMergeId) {
                if (subUnitSet.has(unitId)) {
                    if (subMergeSet.has(inputMergeId)) {
                        const mergeTotalCount = mergeTotalCounts[inputMergeId];
                        const mergeTotalSelectedCount = mergeTotalSelectedCounts[inputMergeId];
                        if (mergeTotalCount === mergeTotalSelectedCount) {
                            //
                        }
                        else if (mergeTotalSelectedCount === 1) {
                            addNewSpecInput(unitId, inputId);
                        }
                    }
                    else {
                        addNewSpecInput(unitId, inputId);
                    }
                }
                // if (subMergeSet.has(inputMergeId)) {
                //   if (subUnitSet.has(unitId)) {
                //     addNewSpecOutput(unitId, inputId)
                //   }
                // } else {
                //   if (subUnitSet.has(unitId)) {
                //     addNewSpecInput(unitId, inputId)
                //   }
                // }
            }
            else {
                if (subUnitInputSet.has(inputId)) {
                    //
                }
                else {
                    if (subUnitSet.has(unitId)) {
                        addNewSpecInput(unitId, inputId);
                    }
                }
            }
        }
        for (const outputId in outputs) {
            unitMergePinRename[unitId]['output'][outputId] = outputId;
            const outputMergeId = unitOutputToMerge[outputId];
            if (outputMergeId) {
                if (subUnitSet.has(unitId)) {
                    if (subMergeSet.has(outputMergeId)) {
                        const mergeTotalCount = mergeTotalCounts[outputMergeId];
                        const mergeTotalSelectedCount = mergeTotalSelectedCounts[outputMergeId];
                        if (mergeTotalCount === mergeTotalSelectedCount) {
                            //
                        }
                        else if (mergeTotalSelectedCount === 1) {
                            addNewSpecOutput(unitId, outputId);
                        }
                    }
                    else {
                        addNewSpecOutput(unitId, outputId);
                    }
                }
                // if (subMergeSet.has(outputMergeId)) {
                //   if (subUnitSet.has(unitId)) {
                //     addNewSpecOutput(unitId, outputId)
                //   }
                // } else {
                //   if (subUnitSet.has(unitId)) {
                //     addNewSpecOutput(unitId, outputId)
                //   }
                // }
            }
            else {
                if (subUnitOutputSet.has(outputId)) {
                    //
                }
                else {
                    if (subUnitSet.has(unitId)) {
                        addNewSpecOutput(unitId, outputId);
                    }
                }
            }
        }
    }
    for (const mergeId in spec.merges) {
        const merge = spec.merges[mergeId];
        if (subMergeSet.has(mergeId)) {
            const mergeTotalCount = mergeTotalCounts[mergeId];
            const mergeTotalSelectedCount = mergeTotalSelectedCounts[mergeId];
            const newMerge = {};
            const parentMerge = {};
            for (const unitId in merge) {
                if (subUnitSet.has(unitId)) {
                    newMerge[unitId] = merge[unitId];
                }
                else {
                    parentMerge[unitId] = merge[unitId];
                }
            }
            if (mergeTotalSelectedCount > 1) {
                newSpec = (0, deepSet_1.default)(newSpec, ['merges', mergeId], newMerge);
                if (mergeTotalSelectedCount < mergeTotalCount) {
                    parentSpec = (0, deepSet_1.default)(newSpec, ['merges', mergeId], parentMerge);
                }
            }
            if (mergeTotalSelectedCount === mergeTotalCount) {
                newSpec = (0, deepSet_1.default)(newSpec, ['merges', mergeId], newMerge);
            }
        }
        else {
            const _merge = {};
            for (const unitId in merge) {
                const mergeUnit = merge[unitId];
                const _unitId = subUnitSet.has(unitId) ? newUnitId : unitId;
                const { input = {}, output = {} } = mergeUnit;
                _merge[_unitId] = {};
                for (const inputId in input) {
                    const _inputId = unitMergePinRename[unitId]['input'][inputId];
                    _merge[_unitId]['input'] = _merge[_unitId]['input'] || {};
                    _merge[_unitId]['input'][_inputId] = true;
                }
                for (const outputId in output) {
                    const _outputId = unitMergePinRename[unitId]['output'][outputId];
                    _merge[_unitId]['output'] = _merge[_unitId]['output'] || {};
                    _merge[_unitId]['output'][_outputId] = true;
                }
            }
            parentSpec = (0, deepSet_1.default)(parentSpec, ['merges', mergeId], _merge);
        }
    }
    parentSpec.units = parentSpec.units || {};
    parentSpec.units[newUnitId] = {
        id: newSpecId,
    };
    return [parentSpec, newSpec];
}
exports.extractSubSpec = extractSubSpec;
//# sourceMappingURL=extract.js.map