"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Registry = void 0;
const Object_1 = require("./Object");
const spec_1 = require("./client/spec");
const id_1 = require("./util/id");
const object_1 = require("./util/object");
class Registry {
    constructor(specs) {
        this.specsCount = {};
        this.specs = specs;
        this.specs_ = new Object_1.Object_(specs);
    }
    newSpecId() {
        return (0, id_1.uuidNotIn)(this.specs);
    }
    hasSpec(id) {
        return !!this.specs[id];
    }
    emptySpec() {
        const id = (0, spec_1.newSpecId)(this.specs);
        const spec = (0, spec_1.emptySpec)({ id });
        this.newSpec(spec);
        return spec;
    }
    newSpec(spec, specId) {
        // console.log('newSpec', spec, specId)
        specId = specId !== null && specId !== void 0 ? specId : (0, spec_1.newSpecId)(this.specs);
        spec.id = specId;
        this.specs_.set(specId, spec);
        return spec;
    }
    getSpec(id) {
        return this.specs[id];
    }
    setSpec(specId, spec) {
        // console.log('Registry', 'setSpec', specId, spec)
        this.specs_.set(specId, spec);
    }
    injectSpecs(newSpecs) {
        // console.log('injectSpecs', newSpecs)
        const mapSpecId = {};
        const visited = new Set();
        const _set = (specId, spec) => {
            if (visited.has(specId)) {
                return;
            }
            if (mapSpecId[specId]) {
                return;
            }
            let nextSpecId = specId;
            let hasSpec = false;
            while (this.hasSpec(nextSpecId)) {
                nextSpecId = this.newSpecId();
                hasSpec = true;
            }
            visited.add(specId);
            const { units } = spec;
            for (const unitId in units) {
                const unit = units[unitId];
                if (this.hasSpec(unit.id)) {
                    //
                }
                else {
                    const spec = newSpecs[unit.id];
                    _set(unit.id, spec);
                }
            }
            if (hasSpec) {
                // TODO spec equality
                if (JSON.stringify(spec) === JSON.stringify(this.getSpec(specId))) {
                    //
                }
                else {
                    // TODO
                    mapSpecId[specId] = nextSpecId;
                    this.specs_.set(specId, spec);
                }
            }
            else {
                this.specs_.set(specId, spec);
            }
            // this.specs_.set(nextSpecId, spec) // TODO
        };
        for (const specId in newSpecs) {
            const spec = newSpecs[specId];
            _set(specId, spec);
        }
        return mapSpecId;
    }
    shouldFork(id) {
        var _a;
        return ((_a = this.specsCount[id]) !== null && _a !== void 0 ? _a : 0) > 1 || (0, spec_1.isSystemSpecId)(this.specs, id);
    }
    forkSpec(spec, specId) {
        // console.log('forkSpec', spec, specId)
        if (this.shouldFork(spec.id)) {
            const clonedSpec = (0, object_1.clone)(spec);
            delete clonedSpec.system;
            const { id: newSpecId } = this.newSpec(clonedSpec, specId);
            return [newSpecId, clonedSpec];
        }
        else {
            return [spec.id, spec];
        }
    }
    registerUnit(id) {
        // console.log('registerUnit', { id })
        if (this.specsCount[id] === undefined) {
            this.specsCount[id] = 0;
        }
        this.specsCount[id] += 1;
    }
    unregisterUnit(id) {
        // console.log('unregisterUnit', { id })
        if (!this.specsCount[id]) {
            throw new Error(`cannot unregister unit: no spec with id ${id}`);
        }
        this.specsCount[id] -= 1;
        if (this.specsCount[id] === 0) {
            delete this.specsCount[id];
            if (!(0, spec_1.isSystemSpecId)(this.specs, id)) {
                this.deleteSpec(id);
            }
        }
    }
    deleteSpec(id) {
        // console.log('deleteSpec', id)
        this.specs_.delete(id);
    }
}
exports.Registry = Registry;
//# sourceMappingURL=Registry.js.map