"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ObjNode = void 0;
const printTree_1 = require("tree-dump/lib/printTree");
const clock_1 = require("../../../json-crdt-patch/clock");
const ConNode_1 = require("../const/ConNode");
/**
 * Represents a `obj` JSON CRDT node, which is a Last-write-wins (LWW) object.
 * It is a map of string keys to LWW registers. The value of each register is
 * a reference to another JSON CRDT node.
 *
 * @category CRDT Node
 */
class ObjNode {
    constructor(
    /**
     * @ignore
     */
    doc, id) {
        this.doc = doc;
        this.id = id;
        /**
         * @ignore
         */
        this.keys = new Map();
        /**
         * @ignore
         */
        this._tick = 0;
        /**
         * @ignore
         */
        this._view = {};
        /**
         * @ignore
         */
        this.api = undefined;
    }
    /**
     * Retrieves a JSON CRDT node at the given key.
     *
     * @param key A key of the object.
     * @returns JSON CRDT node at the given key, if any.
     */
    get(key) {
        const id = this.keys.get(key);
        if (!id)
            return undefined;
        return this.doc.index.get(id);
    }
    /**
     * Rewrites object key.
     *
     * @param key Object key to set.
     * @param id ID of the contents of the key.
     * @returns Returns old entry ID, if any.
     * @ignore
     */
    put(key, id) {
        const currentId = this.keys.get(key);
        if (currentId && (0, clock_1.compare)(currentId, id) >= 0)
            return;
        this.keys.set(key, id);
        return currentId;
    }
    /**
     * Iterate over all key-value pairs in the object.
     *
     * @param callback Callback to call for each key-value pair.
     */
    nodes(callback) {
        const index = this.doc.index;
        this.keys.forEach((id, key) => callback(index.get(id), key));
    }
    forEach(callback) {
        const index = this.doc.index;
        this.keys.forEach((id, key) => {
            const value = index.get(id);
            if (!value || (value instanceof ConNode_1.ConNode && value.val === void 0))
                return;
            callback(key, value);
        });
    }
    // ----------------------------------------------------------------- JsonNode
    /**
     * @ignore
     */
    children(callback) {
        const index = this.doc.index;
        this.keys.forEach((id, key) => callback(index.get(id)));
    }
    /**
     * @ignore
     */
    child() {
        return undefined;
    }
    /**
     * @ignore
     */
    container() {
        return this;
    }
    /**
     * @ignore
     */
    view() {
        const doc = this.doc;
        const tick = doc.clock.time + doc.tick;
        const _view = this._view;
        if (this._tick === tick)
            return _view;
        const view = {};
        const index = doc.index;
        let useCache = true;
        this.keys.forEach((id, key) => {
            const valueNode = index.get(id);
            if (!valueNode) {
                useCache = false;
                return;
            }
            const value = valueNode.view();
            if (value !== undefined) {
                if (_view[key] !== value)
                    useCache = false;
                view[key] = value;
            }
            else if (_view[key] !== undefined)
                useCache = false;
        });
        return useCache ? _view : ((this._tick = tick), (this._view = view));
    }
    name() {
        return 'obj';
    }
    // ---------------------------------------------------------------- Printable
    toString(tab = '') {
        const header = this.name() + ' ' + (0, clock_1.printTs)(this.id);
        return (header +
            (0, printTree_1.printTree)(tab, [...this.keys.entries()]
                .filter(([, id]) => !!this.doc.index.get(id))
                .map(([key, id]) => (tab) => JSON.stringify(key) + (0, printTree_1.printTree)(tab + ' ', [(tab) => this.doc.index.get(id).toString(tab)]))));
    }
}
exports.ObjNode = ObjNode;
//# sourceMappingURL=ObjNode.js.map