"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.destroy = exports.boot = void 0;
const EventEmitter_1 = require("../EventEmitter");
const NOOP_1 = require("../NOOP");
const Object_1 = require("../Object");
const Registry_1 = require("../Registry");
const styleToCSS_1 = require("../client/id/styleToCSS");
const attachStyle_1 = require("../client/render/attachStyle");
const fromBundle_1 = require("../spec/fromBundle");
const stringifySpec_1 = require("../spec/stringifySpec");
const id_1 = require("../util/id");
function boot(parent = null, api, opt) {
    const { path = '', specs = {}, classes = {}, components = {}, flags = {}, } = opt;
    const keyboard = {
        pressed: [],
        repeat: false,
    };
    const gamepads = [];
    const pointers = {};
    const customEvent = new Set();
    const context = [];
    const input = {
        keyboard,
        gamepads,
        pointers,
    };
    const cache = {
        iframe: [],
        dragAndDrop: {},
        pointerCapture: {},
        spriteSheetMap: {},
    };
    const feature = {};
    const registry = new Registry_1.Registry(specs);
    const { specs_ } = registry;
    const { specsCount, newSpecId, hasSpec, emptySpec, newSpec, getSpec, setSpec, forkSpec, injectSpecs, deleteSpec, registerUnit, unregisterUnit, shouldFork, } = registry;
    const emitter = parent ? parent.emitter : new EventEmitter_1.EventEmitter_();
    const componentLocalToRemote = {};
    const componentLocal = {};
    const componentRemoteToLocal = {};
    const system = {
        path,
        parent,
        emitter,
        animated: true,
        root: null,
        theme: 'dark',
        customEvent,
        input,
        context,
        specs_,
        specs,
        classes,
        components,
        graphs: [],
        specsCount,
        cache,
        feature,
        foreground: {
            svg: undefined,
            canvas: undefined,
            app: undefined,
        },
        showLongPress: undefined,
        captureGesture: undefined,
        global: parent
            ? parent.global
            : {
                ref: {},
                component: componentLocal,
                data: new Object_1.Object_({}),
                scope: {},
            },
        api,
        flags: Object.assign({ defaultInputModeNone: false, tick: 'sync' }, flags),
        tick: flags.tick === 'sync'
            ? (callback) => {
                callback();
            }
            : (callback) => system.api.animation.requestAnimationFrame(callback),
        boot: (opt) => boot(system, api, opt),
        stringifyBundleData: (bundle) => {
            return (0, stringifySpec_1.stringifyBundleSpecData)(bundle);
        },
        fromBundle: (bundle) => {
            return (0, fromBundle_1.fromBundle)(bundle, specs, {});
        },
        newGraph: (Bundle) => {
            const graph = new Bundle(system);
            return graph;
        },
        getSpec: getSpec.bind(registry),
        hasSpec: hasSpec.bind(registry),
        newSpecId: newSpecId.bind(registry),
        emptySpec: emptySpec.bind(registry),
        forkSpec: forkSpec.bind(registry),
        newSpec: newSpec.bind(registry),
        setSpec: setSpec.bind(registry),
        injectSpecs: injectSpecs.bind(registry),
        deleteSpec: deleteSpec.bind(registry),
        registerUnit: registerUnit.bind(registry),
        unregisterUnit: unregisterUnit.bind(registry),
        shouldFork: shouldFork.bind(registry),
        injectPrivateCSSClass: function (globalId, className, style) {
            if (system.root) {
                if (!system.global.component[globalId]) {
                    throw new Error('component not found');
                }
                const css = `${(0, styleToCSS_1.styleToCSS)(style)}`;
                (0, attachStyle_1.appendRootStyle)(system, css);
                return () => {
                    (0, attachStyle_1.removeRootStyle)(system, css);
                };
            }
            else {
                return NOOP_1.NOOP;
            }
        },
        getLocalComponents: function (remoteGlobalId) {
            const localIds = componentRemoteToLocal[remoteGlobalId];
            return localIds ? [...localIds].map((id) => componentLocal[id]) : [];
        },
        registerLocalComponent: function (component, remoteGlobalId) {
            var _a;
            const localId = (0, id_1.randomIdNotIn)(componentLocalToRemote);
            componentLocal[localId] = component;
            componentLocalToRemote[localId] = remoteGlobalId;
            componentRemoteToLocal[remoteGlobalId] =
                (_a = componentRemoteToLocal[remoteGlobalId]) !== null && _a !== void 0 ? _a : new Set();
            componentRemoteToLocal[remoteGlobalId].add(localId);
            emitter.emit(remoteGlobalId, component);
            return localId;
        },
        unregisterLocalComponent: function (localId) {
            const remoteGlobalId = componentLocalToRemote[localId];
            if (!remoteGlobalId) {
                throw new Error('local component not found');
            }
            const localIds = componentRemoteToLocal[remoteGlobalId];
            localIds.delete(localId);
            if (localIds.size === 0) {
                delete componentRemoteToLocal[remoteGlobalId];
            }
            delete componentLocalToRemote[localId];
        },
    };
    return system;
}
exports.boot = boot;
function destroy(system) {
    const { graphs } = system;
    for (const graph of graphs) {
        graph.destroy();
    }
    // TODO
}
exports.destroy = destroy;
//# sourceMappingURL=index.js.map