"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AsyncG = exports.AsyncGRef = exports.AsyncGWatch = exports.AsyncGCall = exports.AsyncGGet = void 0;
exports.evalBulkEdit = evalBulkEdit;
exports.evalMoveSubgraph = evalMoveSubgraph;
exports.stringifyBulkEdit = stringifyBulkEdit;
exports.stringifyBulkEditActions = stringifyBulkEditActions;
exports.stringifyMoveSubgraph = stringifyMoveSubgraph;
const bundle_1 = require("../../../bundle");
const watchGraph_1 = require("../../../debug/graph/watchGraph");
const watchUnit_1 = require("../../../debug/watchUnit");
const G_1 = require("../../../spec/actions/G");
const evaluate_1 = require("../../../spec/evaluate");
const evaluateBundleSpec_1 = require("../../../spec/evaluate/evaluateBundleSpec");
const evaluateMemorySpec_1 = require("../../../spec/evaluate/evaluateMemorySpec");
const evaluateDataValue_1 = require("../../../spec/evaluateDataValue");
const resolveDataValue_1 = require("../../../spec/resolveDataValue");
const stringify_1 = require("../../../spec/stringify");
const stringifySpec_1 = require("../../../spec/stringifySpec");
const f_1 = __importDefault(require("../../../system/core/object/ForEachKeyValue/f"));
const clone_1 = require("../../../util/clone");
const weakMerge_1 = require("../../../weakMerge");
const stringifyPinData_1 = require("../../stringifyPinData");
const Async_1 = require("./Async");
function call(graph, method, fork, bubble, ...args) {
    const { global } = graph.__system;
    let result;
    if (fork) {
        result = graph[method].call(graph, ...args, fork, bubble);
    }
    else {
        const all = { ...global.graph[graph.id] };
        delete all[graph.__global_id];
        const spec = graph.getSpec();
        const spec_ = (0, clone_1.clone)(spec);
        result = graph[method].call(graph, ...args, fork, bubble);
        for (const globalId in all) {
            const sibling = all[globalId];
            sibling[method].call((0, weakMerge_1.weakReadMerge)(sibling, {
                _spec: (0, clone_1.clone)(spec_),
            }), ...args, fork, bubble);
            sibling.setSpec(spec);
        }
        graph.__system.setSpec(spec.id, spec);
    }
    return result;
}
const AsyncGGet = (graph) => {
    const obj = {
        $getBundle(opt, callback) {
            const bundle = graph.getBundleSpec(opt);
            const { spec } = bundle;
            (0, stringifySpec_1.stringifyGraphSpecData)(spec);
            callback(bundle);
        },
        $getUnitPinData({ unitId, type, pinId }, callback) {
            const state = graph.getUnitData(unitId, type, pinId);
            callback(state);
        },
        $getGraphData(data, callback) {
            const children = graph.getGraphChildren();
            const err = graph.getGraphErr();
            const units = graph.getUnits();
            const pin = {};
            (0, f_1.default)(units, (unit, unitId) => {
                const unitPinData = unit.getPinsData();
                const _unitPinData = (0, stringifyPinData_1.stringifyPinData)(unitPinData);
                pin[unitId] = _unitPinData;
            });
            const merge_ = graph.getGraphMergeInputData();
            const merge = {};
            for (const mergeId in merge_) {
                const data = merge_[mergeId];
                Performance;
                if (data === undefined) {
                    merge[mergeId] = undefined;
                }
                else {
                    merge[mergeId] = (0, stringify_1.stringify)(data);
                }
            }
            callback({ children, err, pin, merge });
        },
        $getGraphChildren({}, callback) {
            const children = graph.getGraphChildren();
            callback(children);
        },
        $getGraphErr({}, callback) {
            const state = graph.getGraphErr();
            callback(state);
        },
        $getGraphPinData({}, callback) {
            const pinData = {};
            const units = graph.getUnits();
            (0, f_1.default)(units, (unit, unitId) => {
                const unitPinData = unit.getPinsData();
                const _unitPinData = (0, stringifyPinData_1.stringifyPinData)(unitPinData, true);
                pinData[unitId] = _unitPinData;
            });
            callback(pinData);
        },
        $getGraphMergeInputData({}, callback) {
            const mergeData = graph.getGraphMergeInputData();
            const _mergeData = (0, stringifyPinData_1.stringifyDataObj)(mergeData);
            callback(_mergeData);
        },
        $getUnitInputData({ unitId }, callback) {
            const state = graph.getUnitInputData(unitId);
            callback(state);
        },
    };
    return obj;
};
exports.AsyncGGet = AsyncGGet;
const AsyncGCall = (graph) => {
    const obj = {
        $setUnitId({ unitId, newUnitId, name, specId, fork = true, bubble = true, }) {
            call(graph, 'setUnitId', fork, bubble, unitId, newUnitId, name, specId);
        },
        $setUnitPinData({ unitId, pinId, type, data, fork = true, bubble = true, }) {
            const { specs, classes } = graph.__system;
            data = (0, evaluate_1.evaluate)(data, specs, classes);
            call(graph, 'setUnitPinData', fork, bubble, unitId, type, pinId, data, undefined, undefined);
        },
        $removeUnitPinData({ unitId, type, pinId, fork = true, bubble = true, }) {
            call(graph, 'removeUnitPinData', fork, bubble, unitId, type, pinId, undefined);
        },
        $addUnit({ unitId, bundle, parentId, fork = true, bubble = true, }) {
            const { specs, classes } = graph.__system;
            const { unit: { memory = {} }, } = bundle;
            (0, evaluateMemorySpec_1.evaluateMemorySpec)(memory, specs, classes);
            call(graph, 'addUnitSpec', fork, bubble, unitId, bundle, parentId, undefined);
        },
        $removeUnit({ unitId, take, fork = true, bubble = true, }) {
            call(graph, 'removeUnit', fork, bubble, unitId, undefined, take, undefined);
        },
        $exposePinSet({ type, pinId, pinSpec, data, fork = true, bubble = true, }) {
            const data_ = data && (0, evaluate_1.evaluate)(data, graph.__system.specs, graph.__system.classes);
            call(graph, 'exposePinSet', fork, bubble, type, pinId, pinSpec, data_, undefined, undefined);
        },
        $coverPinSet({ type, pinId, fork = true, bubble = true, }) {
            call(graph, 'coverPinSet', fork, bubble, type, pinId, undefined, undefined);
        },
        $exposePin({ type, pinId, subPinId, subPinSpec, pinSpec, fork = true, bubble = true, }) {
            call(graph, 'exposePin', fork, bubble, type, pinId, subPinId, subPinSpec, pinSpec, undefined, undefined);
        },
        $coverPin({ type, pinId, subPinId, fork = true, bubble = true, }) {
            call(graph, 'coverPin', fork, bubble, type, pinId, subPinId);
        },
        $plugPin({ type, pinId, subPinId, subPinSpec, fork = true, bubble = true, }) {
            call(graph, 'plugPin', fork, bubble, type, pinId, subPinId, subPinSpec, undefined, undefined, undefined);
        },
        $unplugPin({ type, pinId, subPinId, take, fork = true, bubble = true, }) {
            call(graph, 'unplugPin', fork, bubble, type, pinId, subPinId, true, take);
        },
        $exposeUnitPinSet({ unitId, type, pinId, pinSpec, fork = true, bubble = true, }) {
            const unit = graph.getUnit(unitId);
            call(unit, 'exposePinSet', fork, bubble, type, pinId, pinSpec, undefined, undefined, undefined);
        },
        $coverUnitPinSet({ unitId, type, pinId, fork = true, bubble = true, }) {
            const unit = graph.getUnit(unitId);
            call(unit, 'coverPinSet', fork, bubble, type, pinId);
        },
        $setPinSetId({ type, pinId, newPinId, fork = true, bubble = true, }) {
            call(graph, 'setPinSetId', fork, bubble, type, pinId, newPinId, undefined);
        },
        $setPinSetFunctional({ type, pinId, functional, fork = true, bubble = true, }) {
            call(graph, 'setPinSetFunctional', fork, bubble, type, pinId, functional);
        },
        $setUnitPinConstant({ unitId, type, pinId, constant, fork = true, bubble = true, }) {
            call(graph, 'setUnitPinConstant', fork, bubble, unitId, type, pinId, constant, true);
        },
        $setUnitPinIgnored({ unitId, type, pinId, ignored, fork = true, bubble = true, }) {
            call(graph, 'setUnitPinIgnored', fork, bubble, unitId, type, pinId, ignored);
        },
        $setUnitPinSetId({ unitId, type, pinId, newPinId, fork = true, bubble = true, }) {
            call(graph, 'setUnitPinSetId', fork, bubble, unitId, type, pinId, newPinId);
        },
        $setPlugData({ type, pinId, subPinId, data, fork = true, bubble = true, }) {
            const { specs, classes } = graph.__system;
            const _data = (0, evaluate_1.evaluate)(data, specs, classes);
            call(graph, 'setPlugData', fork, bubble, type, pinId, subPinId, _data);
        },
        $addMerge({ mergeId, mergeSpec, fork = true, bubble = true, }) {
            call(graph, 'addMerge', fork, bubble, mergeSpec, mergeId, undefined, undefined);
        },
        $removeMerge({ mergeId, take, fork = true, bubble = true, }) {
            call(graph, 'removeMerge', fork, bubble, mergeId, undefined, take);
        },
        $addPinToMerge({ mergeId, unitId, type, pinId, fork = true, bubble = true, }) {
            call(graph, 'addPinToMerge', fork, bubble, mergeId, unitId, type, pinId, undefined, undefined);
        },
        $removePinFromMerge({ mergeId, unitId, type, pinId, take, fork = true, bubble = true, }) {
            call(graph, 'removePinFromMerge', fork, bubble, mergeId, unitId, type, pinId, true, take);
        },
        $setMetadata({ path_, value, fork = true, bubble = true, }) {
            call(graph, 'setMetadata', fork, bubble, path_, value);
        },
        $setUnitMetadata({ unitId, path_, value, fork = true, bubble = true, }) {
            call(graph, 'setUnitMetadata', fork, bubble, unitId, path_, value);
        },
        $setUnitPinMetadata({ unitId, type, pinId, path_, value, fork = true, bubble = true, }) {
            call(graph, 'setUnitPinMetadata', fork, bubble, unitId, type, pinId, path_, value);
        },
        $setPinMetadata({ type, pinId, path_, value, fork = true, bubble = true, }) {
            call(graph, 'setPinMetadata', fork, bubble, type, pinId, path_, value);
        },
        $reorderSubComponent({ parentId, childId, to, fork = true, bubble = true, }) {
            call(graph, 'reorderSubComponent', fork, bubble, parentId, childId, to);
        },
        $moveSubComponentRoot({ parentId, children, slotMap, index, fork = true, bubble = true, }) {
            call(graph, 'moveSubComponentRoot', fork, bubble, parentId, children, slotMap, index, undefined);
        },
        $moveSubgraphInto(data) {
            const { specs, classes } = graph.__system;
            evalMoveSubgraph(specs, classes, data);
            const { graphId, selection, moves, mapping, fork = true, bubble = true, } = data;
            call(graph, 'moveSubgraphInto', fork, bubble, selection, graphId, moves, mapping);
        },
        $moveSubgraphOutOf(data) {
            const { specs, classes } = graph.__system;
            evalMoveSubgraph(specs, classes, data);
            const { graphId, selection, moves, mapping, fork = true, bubble = true, } = data;
            call(graph, 'moveSubgraphOutOf', fork, bubble, selection, graphId, moves, mapping);
        },
        $bulkEdit(data) {
            const { specs, classes } = graph.__system;
            evalBulkEdit(specs, classes, data);
            const { actions, fork = true, bubble = true } = data;
            call(graph, 'bulkEdit', fork, bubble, actions, undefined);
        },
        $setMergeData({ mergeId, data }) {
            const system = graph.__system;
            const { specs, classes } = system;
            const _data = (0, evaluate_1.evaluate)(data, specs, classes);
            graph.setMergeData(mergeId, _data);
        },
        $removeMergeData({ mergeId }) {
            graph.removeMergeData(mergeId);
        },
        $takeUnitErr({ unitId }) {
            graph.takeUnitErr(unitId);
        },
        $setPinSetDefaultIgnored({ type, pinId, defaultIgnored, fork, bubble, }) {
            call(graph, 'setPinSetDefaultIgnored', fork, bubble, type, pinId, defaultIgnored);
        },
        $setFork: function ({ fork }) {
            call(graph, 'setFork', undefined, undefined, fork);
        },
    };
    return obj;
};
exports.AsyncGCall = AsyncGCall;
const AsyncGWatch = (graph) => {
    return {
        $watchGraph({ events }, callback) {
            return (0, watchGraph_1.watchGraph)(graph, callback, events);
        },
        $watchUnit({ unitId, events }, callback) {
            const unit = graph.getUnit(unitId);
            return (0, watchUnit_1.watchUnit)(unit, callback, events);
        },
        $watchGraphUnit({ unitId, events }, callback) {
            const graph = this.refUnit(unitId);
            return (0, watchGraph_1.watchGraph)(graph, callback, events);
        },
        $watchUnitPath({ path, events }, callback) {
            const unit = graph.getUnitByPath(path);
            return (0, watchUnit_1.watchUnit)(unit, callback, events);
        },
        $watchGraphUnitPath({ path, events }, callback) {
            const unit = graph.getUnitByPath(path);
            return (0, watchGraph_1.watchGraph)(unit, callback, events);
        },
    };
};
exports.AsyncGWatch = AsyncGWatch;
const AsyncGRef = (graph) => {
    return {
        $refUnit({ unitId, __ }) {
            const unit = graph.getUnit(unitId);
            const $unit = (0, Async_1.Async)(unit, __, graph.__system.async);
            return $unit;
        },
        $refSubComponent({ unitId, __, }) {
            const unit = graph.getUnit(unitId);
            const $unit = (0, Async_1.Async)(unit, __, graph.__system.async);
            return $unit;
        },
    };
};
exports.AsyncGRef = AsyncGRef;
const AsyncG = (graph) => {
    return {
        ...(0, exports.AsyncGGet)(graph),
        ...(0, exports.AsyncGWatch)(graph),
        ...(0, exports.AsyncGCall)(graph),
        ...(0, exports.AsyncGRef)(graph),
    };
};
exports.AsyncG = AsyncG;
function evalBulkEdit(specs, classes, data) {
    data.actions = data.actions.map((action) => {
        action = (0, clone_1.clone)(action);
        if (action.data.data) {
            const dataRef = (0, evaluateDataValue_1.evaluateDataValue)(action.data.data, specs, classes);
            action.data.data = (0, resolveDataValue_1.resolveDataRef)(dataRef, specs, classes);
        }
        if (action.type === G_1.ADD_UNIT || action.type === G_1.ADD_UNIT_SPEC) {
            let { unitId, bundle } = action.data;
            const { unit } = bundle;
            const specs_ = (0, weakMerge_1.weakMerge)(specs, bundle.specs ?? {});
            const { id } = unit;
            if (!specs[id] && !bundle.specs?.[id]) {
                bundle.specs = bundle.specs ?? {};
                const spec = {
                    name: `${unitId}`,
                    id,
                    inputs: {},
                    outputs: {},
                };
                const { input = {}, output = {} } = unit;
                for (const name in input) {
                    spec.inputs[name] = {
                        plug: {
                            '0': {},
                        },
                    };
                }
                for (const name in output) {
                    spec.outputs[name] = {
                        plug: {
                            '0': {},
                        },
                    };
                }
                bundle.specs[id] = spec;
            }
            bundle = (0, bundle_1.unitBundleSpec)({ id }, (0, weakMerge_1.weakMerge)(specs, bundle.specs ?? {}));
            (0, evaluateBundleSpec_1.evaluateGraphUnitSpec)(unit, specs_, classes);
            for (const specId in bundle.specs) {
                const spec = bundle.specs[specId];
                (0, evaluateBundleSpec_1.evaluateSpec)(spec, specs_, classes);
            }
        }
        else if (action.type === G_1.MOVE_SUBGRAPH_INTO ||
            action.type === G_1.MOVE_SUBGRAPH_OUT_OF) {
            evalMoveSubgraph(specs, classes, action.data);
        }
        return action;
    });
}
function evalMoveSubgraph(specs, classes, data) {
    data.moves = data.moves.map((move) => {
        if (move.action.type === G_1.SET_UNIT_PIN_DATA) {
            move.action.data.data = (0, evaluate_1.evaluate)(move.action.data.data, specs, classes);
        }
        return move;
    });
}
function stringifyBulkEdit(data) {
    data.actions = stringifyBulkEditActions(data.actions);
}
function stringifyBulkEditActions(actions) {
    return actions.map((action) => {
        action = (0, clone_1.clone)(action);
        if (action.data.data) {
            action.data.data = (0, stringify_1.stringify)(action.data.data);
        }
        if (action.type === G_1.ADD_UNIT_SPEC) {
            const { bundle } = action.data;
            const { unit, specs = {} } = bundle;
            (0, stringifySpec_1.stringifyGraphUnitSpecData)(unit);
            for (const specId in specs) {
                const spec = specs[specId];
                (0, stringifySpec_1.stringifyGraphSpecData)(spec);
            }
        }
        else if (action.type === G_1.MOVE_SUBGRAPH_INTO ||
            action.type === G_1.MOVE_SUBGRAPH_OUT_OF) {
            stringifyMoveSubgraph(action.data);
        }
        return action;
    });
}
function stringifyMoveSubgraph(data) {
    data.moves = data.moves.map((move) => {
        if (move.action.type === G_1.SET_UNIT_PIN_DATA) {
            move.action.data.data = (0, stringify_1.stringify)(move.action.data.data);
        }
        return move;
    });
}
//# sourceMappingURL=AsyncG.js.map