"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.getEditableTreeContext = exports.ProxyContext = void 0;
const core_utils_1 = require("@fluidframework/core-utils");
const core_1 = require("../../core");
const editableField_1 = require("./editableField");
/**
 * Implementation of `EditableTreeContext`.
 *
 * An editor is required to edit the EditableTrees.
 */
class ProxyContext {
    /**
     * @param forest - the Forest
     * @param editor - an editor that makes changes to the forest.
     * @param nodeKeys - an object which handles node key generation and conversion
     * @param nodeKeyFieldKey - an optional field key under which node keys are stored in this tree.
     * If present, clients may query the {@link LocalNodeKey} of a node directly via the {@link localNodeKeySymbol}.
     */
    constructor(forest, schema, editor, nodeKeys, nodeKeyFieldKey) {
        this.forest = forest;
        this.schema = schema;
        this.editor = editor;
        this.nodeKeys = nodeKeys;
        this.nodeKeyFieldKey = nodeKeyFieldKey;
        this.withCursors = new Set();
        this.withAnchors = new Set();
        this.eventUnregister = [
            this.forest.on("beforeChange", () => {
                this.prepareForEdit();
            }),
        ];
    }
    prepareForEdit() {
        for (const target of this.withCursors) {
            target.prepareForEdit();
        }
        (0, core_utils_1.assert)(this.withCursors.size === 0, 0x3c0 /* prepareForEdit should remove all cursors */);
    }
    free() {
        this.clear();
        for (const unregister of this.eventUnregister) {
            unregister();
        }
        this.eventUnregister.length = 0;
    }
    clear() {
        for (const target of this.withCursors) {
            target.free();
        }
        for (const target of this.withAnchors) {
            target.free();
        }
        (0, core_utils_1.assert)(this.withCursors.size === 0, 0x3c1 /* free should remove all cursors */);
        (0, core_utils_1.assert)(this.withAnchors.size === 0, 0x3c2 /* free should remove all anchors */);
    }
    get unwrappedRoot() {
        return this.getRoot(true);
    }
    setContent(value) {
        // Note that an implementation of `set root` might change in the future.
        // This setter might want to keep the `replaceNodes` semantics for the cases when the root is unwrapped,
        // and use `replaceField` only if the root is a sequence field i.e.
        // it's unwrapped to the field itself.
        // TODO: update implementation once the low-level editing API is available.
        const rootField = this.getRoot(false);
        rootField.setContent(value);
    }
    get root() {
        return this.getRoot(false);
    }
    getRoot(unwrap) {
        const rootSchema = this.schema.rootFieldSchema;
        const cursor = this.forest.allocateCursor();
        (0, core_1.moveToDetachedField)(this.forest, cursor);
        const proxifiedField = unwrap
            ? (0, editableField_1.unwrappedField)(this, rootSchema, cursor)
            : (0, editableField_1.makeField)(this, rootSchema, cursor);
        cursor.free();
        return proxifiedField;
    }
    on(eventName, listener) {
        return this.forest.on(eventName, listener);
    }
}
exports.ProxyContext = ProxyContext;
/**
 * A simple API for a Forest to interact with the tree.
 *
 * @param forest - the Forest
 * @param editor - an editor that makes changes to the forest.
 * @param nodeKeyManager - an object which handles node key generation and conversion
 * @param nodeKeyFieldKey - an optional field key under which node keys are stored in this tree.
 * If present, clients may query the {@link LocalNodeKey} of a node directly via the {@link localNodeKeySymbol}.
 * @returns {@link EditableTreeContext} which is used to manage the cursors and anchors within the EditableTrees:
 * This is necessary for supporting using this tree across edits to the forest, and not leaking memory.
 */
function getEditableTreeContext(forest, schema, editor, nodeKeyManager, nodeKeyFieldKey) {
    return new ProxyContext(forest, schema, editor, nodeKeyManager, nodeKeyFieldKey);
}
exports.getEditableTreeContext = getEditableTreeContext;
//# sourceMappingURL=editableTreeContext.js.map