/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
    if (kind === "m") throw new TypeError("Private method is not writable");
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
    return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
    return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _LazyEntity_lazyCursor;
import { assert } from "@fluidframework/core-utils";
import { ITreeSubscriptionCursorState, } from "../../core";
import { fail, disposeSymbol } from "../../util";
import { boxedIterator, flexTreeMarker, } from "./flexTreeTypes";
/**
 * Declare an enumerable own property on `T` under the key `key` using the implementation of one on `from`.
 */
export function makePropertyEnumerableOwn(target, key, from) {
    assert(Object.getOwnPropertyDescriptor(target, key) === undefined, 0x776 /* preexisting property */);
    const descriptor = Object.getOwnPropertyDescriptor(from, key) ?? fail("missing property");
    Object.defineProperty(target, key, { ...descriptor, enumerable: true });
}
/**
 * Modify a property on `T` under the key `key` to be not-enumerable
 */
export function makePropertyNotEnumerable(target, key) {
    makePrivatePropertyNotEnumerable(target, key);
}
/**
 * Like {@link makePropertyNotEnumerable}, but less type safe so it works on private properties.
 */
export function makePrivatePropertyNotEnumerable(target, key) {
    assert(Object.getOwnPropertyDescriptor(target, key)?.enumerable === true, 0x777 /* missing property or not enumerable */);
    Object.defineProperty(target, key, { enumerable: false });
}
export const prepareForEditSymbol = Symbol("prepareForEdit");
export const isFreedSymbol = Symbol("isFreed");
export const tryMoveCursorToAnchorSymbol = Symbol("tryMoveCursorToAnchor");
export const forgetAnchorSymbol = Symbol("forgetAnchor");
export const cursorSymbol = Symbol("cursor");
export const anchorSymbol = Symbol("anchor");
/**
 * This is a base class for lazy (cursor based) UntypedEntity implementations, which uniformly handles cursors and anchors.
 */
export class LazyEntity {
    constructor(context, schema, cursor, anchor) {
        this.context = context;
        this.schema = schema;
        _LazyEntity_lazyCursor.set(this, void 0);
        this[anchorSymbol] = anchor;
        __classPrivateFieldSet(this, _LazyEntity_lazyCursor, cursor.fork(), "f");
        context.withCursors.add(this);
        this.context.withAnchors.add(this);
        // Setup JS Object API:
        makePropertyNotEnumerable(this, "context");
        makePropertyNotEnumerable(this, "schema");
        makePropertyNotEnumerable(this, anchorSymbol);
    }
    [(_LazyEntity_lazyCursor = new WeakMap(), disposeSymbol)]() {
        __classPrivateFieldGet(this, _LazyEntity_lazyCursor, "f").free();
        this.context.withCursors.delete(this);
        this[forgetAnchorSymbol](this[anchorSymbol]);
        this.context.withAnchors.delete(this);
    }
    [prepareForEditSymbol]() {
        __classPrivateFieldGet(this, _LazyEntity_lazyCursor, "f").clear();
        this.context.withCursors.delete(this);
    }
    [isFreedSymbol]() {
        return __classPrivateFieldGet(this, _LazyEntity_lazyCursor, "f").state === ITreeSubscriptionCursorState.Freed;
    }
    get [cursorSymbol]() {
        if (__classPrivateFieldGet(this, _LazyEntity_lazyCursor, "f").state !== ITreeSubscriptionCursorState.Current) {
            assert(__classPrivateFieldGet(this, _LazyEntity_lazyCursor, "f").state === ITreeSubscriptionCursorState.Cleared, 0x778 /* Unset cursor should be in cleared state */);
            assert(this[anchorSymbol] !== undefined, 0x779 /* EditableTree should have an anchor if it does not have a cursor */);
            const result = this[tryMoveCursorToAnchorSymbol](this[anchorSymbol], __classPrivateFieldGet(this, _LazyEntity_lazyCursor, "f"));
            assert(result === 1 /* TreeNavigationResult.Ok */, 0x77a /* It is invalid to access an EditableTree node which no longer exists */);
            this.context.withCursors.add(this);
        }
        return __classPrivateFieldGet(this, _LazyEntity_lazyCursor, "f");
    }
}
/**
 * Prevent Entities from inheriting members from Object.prototype including:
 * '__defineGetter__', '__defineSetter__', '__lookupGetter__', '__lookupSetter__', '__proto__',
 * 'hasOwnProperty', 'isPrototypeOf', 'valueOf', 'propertyIsEnumerable', 'toLocaleString' and 'toString'.
 *
 * This opens up more options for field names on struct nodes.
 */
Object.setPrototypeOf(LazyEntity.prototype, null);
//# sourceMappingURL=lazyEntity.js.map