"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AsyncG = exports.AsyncGRef = exports.AsyncGWatch = exports.AsyncGCall = exports.parseMemoryData = exports.stringifyMemoryData = exports.stringifyBundleData = void 0;
const Graph_1 = require("../../../Class/Graph");
const spec_1 = require("../../../client/spec");
const watchGraph_1 = require("../../../debug/graph/watchGraph");
const watchUnit_1 = require("../../../debug/watchUnit");
const proxyWrap_1 = require("../../../proxyWrap");
const evaluate_1 = require("../../../spec/evaluate");
const fromId_1 = require("../../../spec/fromId");
const stringify_1 = require("../../../spec/stringify");
const stringifySpec_1 = require("../../../spec/stringifySpec");
const f_1 = require("../../../system/core/object/ForEachKeyValue/f");
const object_1 = require("../../../util/object");
const stringifyPinData_1 = require("../../stringifyPinData");
const Async_1 = require("./Async");
const stringifyBundleData = (bundle) => {
    const { unit } = bundle;
    const { id, memory } = unit;
    (0, exports.stringifyMemoryData)(memory);
    return bundle;
};
exports.stringifyBundleData = stringifyBundleData;
const stringifyMemoryData = (memory) => {
    if (memory) {
        for (const inputId in memory.input) {
            if (memory.input[inputId]._register !== undefined) {
                memory.input[inputId]._register = (0, stringify_1.stringify)(memory.input[inputId]._register);
            }
        }
        for (const outputId in memory.output) {
            if (memory.output[outputId]._register !== undefined) {
                memory.output[outputId]._register = (0, stringify_1.stringify)(memory.output[outputId]._register);
            }
        }
    }
};
exports.stringifyMemoryData = stringifyMemoryData;
const parseMemoryData = (system, memory) => {
    if (memory) {
        for (const inputId in memory.input) {
            if (memory.input[inputId]._register !== undefined) {
                memory.input[inputId]._register = (0, evaluate_1.evaluate)(memory.input[inputId]._register, system.specs, system.classes);
            }
        }
        for (const outputId in memory.output) {
            if (memory.output[outputId]._register !== undefined) {
                memory.output[outputId]._register = (0, evaluate_1.evaluate)(memory.output[outputId]._register, system.specs, system.classes);
            }
        }
    }
};
exports.parseMemoryData = parseMemoryData;
const AsyncGCall = (graph) => {
    return {
        $setUnitName({ unitId, newUnitId, name, }) {
            graph.setUnitName(unitId, newUnitId, name);
        },
        $setUnitPinData({ unitId, pinId, type, data, }) {
            const system = graph.__system;
            const { specs, classes } = system;
            const _specs = graph.getSpecs();
            data = (0, evaluate_1.evaluate)(data, Object.assign(Object.assign({}, specs), _specs), classes);
            graph.setUnitPinData(unitId, type, pinId, data);
        },
        $removeUnitPinData({ unitId, type, pinId, }) {
            const unit = graph.refUnit(unitId);
            unit.getPin(type, pinId).take();
        },
        $addUnit({ id, unit }) {
            graph.addUnitSpec(id, unit);
        },
        $cloneUnit({ unitId, newUnitId, }) {
            graph.cloneUnit(unitId, newUnitId);
        },
        $moveUnit({ id, unitId, inputId, }) {
            graph.moveUnit(id, unitId, inputId);
        },
        $addUnits({ specs, units, classes, }) {
            const unitNodes = (0, object_1.mapObjVK)(units, (u) => (Object.assign(Object.assign({}, u), { Class: (0, fromId_1.fromId)(u.id, specs, classes) })));
            graph.addUnitSpecs(unitNodes);
        },
        $removeUnit({ id }) {
            graph.removeUnit(id);
        },
        $exposePinSet({ type, id, pin, }) {
            graph.exposePinSet(type, id, pin);
        },
        $coverPinSet({ type, id }) {
            graph.coverPinSet(type, id, true);
        },
        $exposePin({ type, id, subPinId, subPin, }) {
            graph.exposePin(type, id, subPinId, subPin);
        },
        $coverPin({ type, id, subPinId, }) {
            graph.coverPin(type, id, subPinId);
        },
        $plugPin({ type, id, subPinId, subPin, }) {
            graph.plugPin(type, id, subPinId, subPin);
        },
        $unplugPin({ type, id, subPinId, }) {
            graph.unplugPin(type, id, subPinId);
        },
        $exposeUnitPinSet({ unitId, type, id, pin, }) {
            const unit = graph.refUnit(unitId);
            unit.exposePinSet(type, id, pin);
        },
        $coverUnitPinSet({ unitId, type, id, }) {
            const unit = graph.refUnit(unitId);
            unit.coverPinSet(type, id);
        },
        $setPinSetId({ type, pinId, nextPinId, }) {
            graph.setPinSetId(type, pinId, nextPinId);
        },
        $setPinSetFunctional({ type, pinId, functional, }) {
            graph.setPinSetFunctional(type, pinId, functional);
        },
        $setUnitPinConstant({ unitId, type, pinId, constant, }) {
            graph.setUnitPinConstant(unitId, type, pinId, constant);
        },
        $setUnitPinIgnored({ unitId, type, pinId, ignored, }) {
            graph.setUnitPinIgnored(unitId, type, pinId, ignored);
        },
        $addMerge({ id, merge }) {
            graph.addMerge((0, object_1.clone)(merge), id);
        },
        $removeMerge({ id }) {
            graph.removeMerge(id);
        },
        $addMerges({ merges }) {
            graph.addMerges(merges);
        },
        $setMergeData({ id, data }) {
            const system = graph.refSystem();
            const { specs, classes } = system;
            const _specs = graph.getSpecs();
            const _data = (0, evaluate_1.evaluate)(data, Object.assign(Object.assign({}, specs), _specs), classes);
            const mergePin = graph.refMergePin(id, 'input');
            mergePin.push(_data);
        },
        $removeMergeData({ id }) {
            const mergePin = graph.refMergePin(id, 'input');
            mergePin.take();
        },
        $addPinToMerge({ mergeId, unitId, type, pinId, }) {
            graph.addPinToMerge(mergeId, unitId, type, pinId);
        },
        $removePinFromMerge({ mergeId, unitId, type, pinId, }) {
            graph.removePinFromMerge(mergeId, unitId, type, pinId);
        },
        $mergeMerges({ mergeIds }) {
            graph.mergeMerges(mergeIds);
        },
        $takeUnitErr({ unitId }) {
            graph.takeUnitErr(unitId);
        },
        $getSpec({}, callback) {
            const spec = graph.getSpec();
            callback(spec);
        },
        $getBundle({}, callback) {
            const bundle = graph.getBundleSpec();
            const { spec } = bundle;
            (0, stringifySpec_1._stringifyGraphSpecData)(spec);
            callback(bundle);
        },
        $getUnitPinData({ unitId, type, pinId }, callback) {
            const state = graph.getUnitPinData(unitId, type, pinId);
            callback(state);
        },
        $getUnitState({ unitId }, callback) {
            return __awaiter(this, void 0, void 0, function* () {
                const state = yield graph.getUnitState(unitId);
                callback(state);
            });
        },
        $getGraphData(callback) {
            return __awaiter(this, void 0, void 0, function* () {
                const state = yield graph.getGraphState();
                const children = graph.getGraphChildren();
                const err = graph.getGraphErr();
                const pinData = {};
                const units = graph.refUnits();
                (0, f_1.default)(units, (unit, unitId) => {
                    const unitPinData = unit.getPinData();
                    const _unitPinData = (0, stringifyPinData_1.stringifyPinData)(unitPinData);
                    pinData[unitId] = _unitPinData;
                });
                const _mergeData = graph.getGraphMergeInputData();
                const mergeData = {};
                for (const mergeId in _mergeData) {
                    const data = _mergeData[mergeId];
                    if (data === undefined) {
                        mergeData[mergeId] = undefined;
                    }
                    else {
                        mergeData[mergeId] = (0, stringify_1.stringify)(data);
                    }
                }
                callback({ state, children, err, pinData, mergeData });
            });
        },
        $snapshot(data, callback) {
            return __awaiter(this, void 0, void 0, function* () {
                const memory = graph.snapshot();
                callback(memory);
            });
        },
        $snapshotUnit({ unitId }, callback) {
            const unit = graph.refUnit(unitId);
            const memory = unit.snapshot();
            callback(memory);
        },
        $removeUnitGhost({ unitId, nextUnitId, nextUnitSpec, }, callback) {
            const ghost = graph.removeUnitGhost(unitId, nextUnitId, nextUnitSpec);
            (0, exports.stringifyBundleData)(ghost.bundle);
            callback(ghost);
        },
        $addUnitGhost({ unitId, nextUnitId, nextUnitBundle, nextUnitPinMap, }) {
            (0, exports.parseMemoryData)(graph.__system, nextUnitBundle.unit.memory);
            graph.addUnitGhost(unitId, nextUnitId, nextUnitBundle, nextUnitPinMap);
        },
        $getGraphState({}, callback) {
            return __awaiter(this, void 0, void 0, function* () {
                const state = yield graph.getGraphState();
                callback(state);
            });
        },
        $getGraphChildren({}, callback) {
            const children = graph.getGraphChildren();
            callback(children);
        },
        $getGraphErr({}, callback) {
            const state = graph.getGraphErr();
            callback(state);
        },
        $getGraphPinData({}, callback) {
            // const state = graph.getGraphPinData()
            const pinData = {};
            const units = graph.refUnits();
            (0, f_1.default)(units, (unit, unitId) => {
                const unitPinData = unit.getPinData();
                const _unitPinData = (0, stringifyPinData_1.stringifyPinData)(unitPinData);
                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);
        },
        $setMetadata({ path, data }) {
            graph.setMetadata(path, data);
        },
        $moveSubComponentChild({ subComponentId, childId, slotName, }) {
            graph.moveSubComponent(subComponentId, childId, slotName);
        },
        $moveSubComponentChildren({ subComponentId, children, slotMap, }) {
            graph.appendParentRootChildren(subComponentId, children, slotMap);
        },
        $appendSubComponent({ subComponentId }) {
            graph.appendRoot(subComponentId);
        },
        $moveSubgraphInto({ graphId, nodeIds, nextIdMap, nextPinIdMap, nextMergePinId, nextPlugSpec, nextSubComponentParentMap, nextSubComponentChildrenMap, }) {
            graph.moveSubgraphInto(graphId, nodeIds, nextIdMap, nextPinIdMap, nextMergePinId, nextPlugSpec, nextSubComponentParentMap, nextSubComponentChildrenMap);
        },
        $moveUnitInto({ graphId, unitId, nextUnitId, ignoredPin, ignoredMerge, nextPinMap, nextUnitSubComponentParent, nextSubComponentChildren, }) {
            graph.moveUnitInto(graphId, unitId, nextUnitId, ignoredPin, ignoredMerge, nextPinMap, nextUnitSubComponentParent, nextSubComponentChildren);
        },
        $moveLinkPinInto({ graphId, unitId, type, pinId, }) {
            graph.moveLinkPinInto(graphId, unitId, type, pinId);
        },
        $moveMergePinInto({ graphId, mergeId, nextInputMergeId, nextOutputMergeId, }) {
            graph.moveMergeInto(graphId, mergeId, nextInputMergeId, nextOutputMergeId);
        },
        $movePlugInto({ graphId, type, pinId, subPinId, subPinSpec, }) {
            graph.movePlugInto(graphId, type, pinId, subPinId, subPinSpec);
        },
        $explodeUnit({ unitId, mapUnitId, mapMergeId, }) {
            graph.explodeUnit(unitId, mapUnitId, mapMergeId, true);
        },
    };
};
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.refUnit(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 {
        $compose({ id, unitId, _, }) {
            const system = graph.refSystem();
            const spec = graph.getSpec();
            if (system.hasSpec(id)) {
                throw new Error('Spec with id ' + id + ' already exists');
            }
            const render = spec.component && !(0, object_1.isEmptyObject)(spec.component.subComponents || {});
            if (render) {
                graph.setElement();
            }
            else {
                graph.setNotElement();
            }
            const parentSpec = (0, spec_1.emptySpec)({ id });
            system.setSpec(id, parentSpec);
            const parent = new Graph_1.Graph(parentSpec, {}, system);
            parent.addUnit(unitId, graph, false);
            parent.play();
            const $parent = (0, Async_1.Async)(parent, _);
            return (0, proxyWrap_1.proxyWrap)($parent, _);
        },
        $refUnit({ unitId, _ }) {
            const unit = graph.refUnit(unitId);
            const $unit = (0, Async_1.Async)(unit, _);
            return (0, proxyWrap_1.proxyWrap)($unit, _);
        },
        $refSubComponent({ unitId, _, }) {
            console;
            const unit = graph.refUnit(unitId);
            const $unit = (0, Async_1.Async)(unit, _);
            return (0, proxyWrap_1.proxyWrap)($unit, _);
        },
    };
};
exports.AsyncGRef = AsyncGRef;
const AsyncG = (graph) => {
    return Object.assign(Object.assign(Object.assign({}, (0, exports.AsyncGWatch)(graph)), (0, exports.AsyncGCall)(graph)), (0, exports.AsyncGRef)(graph));
};
exports.AsyncG = AsyncG;
//# sourceMappingURL=AsyncG.js.map