/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import type { ErasedType } from "@fluidframework/core-interfaces";
import { type TreeNodeSchema, type WithType, typeNameSymbol } from "./schemaTypes.js";
import { type FlexTreeNode, type MapTreeNode } from "../feature-libraries/index.js";
/**
 * Type alias to document which values are un-hydrated.
 *
 * Un-hydrated values are nodes produced from schema's create functions that haven't been inserted into a tree yet.
 *
 * Since un-hydrated nodes become hydrated when inserted, strong typing can't be used to distinguish them.
 * This no-op wrapper is used instead.
 * @public
 */
export type Unhydrated<T> = T;
/**
 * A collection of events that can be emitted by a {@link TreeNode}.
 *
 * @privateRemarks
 * TODO: add a way to subscribe to a specific field (for nodeChanged and treeChanged).
 * Probably have object node and map node specific APIs for this.
 *
 * TODO: ensure that subscription API for fields aligns with API for subscribing to the root.
 *
 * TODO: add more wider area (avoid needing tons of nodeChanged registration) events for use-cases other than treeChanged.
 * Some ideas:
 *
 * - treeChanged, but with some subtrees/fields/paths excluded
 * - helper to batch several nodeChanged calls to a treeChanged scope
 * - parent change (ex: registration on the parent field for a specific index: maybe allow it for a range. Ex: node event takes optional field and optional index range?)
 * - new content inserted into subtree. Either provide event for this and/or enough info to treeChanged to find and search the new sub-trees.
 * Add separate (non event related) API to efficiently scan tree for given set of types (using low level cursor and schema based filtering)
 * to allow efficiently searching for new content (and initial content) of a given type.
 *
 * @sealed @public
 */
export interface TreeChangeEvents {
    /**
     * Emitted by a node after a batch of changes has been applied to the tree, if a change affected the node, where a
     * change is:
     *
     * - For an object node, when the value of one of its properties changes (i.e., the property's value is set
     * to something else, including `undefined`).
     *
     * - For an array node, when an element is added, removed, or moved.
     *
     * - For a map node, when an entry is added, updated, or removed.
     *
     * @remarks
     * This event is not emitted when:
     *
     * - Properties of a child node change. Notably, updates to an array node or a map node (like adding or removing
     * elements/entries) will emit this event on the array/map node itself, but not on the node that contains the
     * array/map node as one of its properties.
     *
     * - The node is moved to a different location in the tree or removed from the tree.
     * In this case the event is emitted on the _parent_ node, not the node itself.
     *
     * For remote edits, this event is not guaranteed to occur in the same order or quantity that it did in
     * the client that made the original edit.
     *
     * When it is emitted, the tree is guaranteed to be in-schema.
     *
     * @privateRemarks
     * This event occurs whenever the apparent contents of the node instance change, regardless of what caused the change.
     * For example, it will fire when the local client reassigns a child, when part of a remote edit is applied to the
     * node, or when the node has to be updated due to resolution of a merge conflict
     * (for example a previously applied local change might be undone, then reapplied differently or not at all).
     */
    nodeChanged(): void;
    /**
     * Emitted by a node after a batch of changes has been applied to the tree, when something changed anywhere in the
     * subtree rooted at it.
     *
     * @remarks
     * This event is not emitted when the node itself is moved to a different location in the tree or removed from the tree.
     * In that case it is emitted on the _parent_ node, not the node itself.
     *
     * The node itself is part of the subtree, so this event will be emitted even if the only changes are to the properties
     * of the node itself.
     *
     * For remote edits, this event is not guaranteed to occur in the same order or quantity that it did in
     * the client that made the original edit.
     *
     * When it is emitted, the tree is guaranteed to be in-schema.
     */
    treeChanged(): void;
}
/**
 * A non-{@link NodeKind.Leaf|leaf} SharedTree node. Includes objects, arrays, and maps.
 *
 * @remarks
 * Base type which all nodes implement.
 *
 * This can be used as a type to indicate/document values which should be tree nodes.
 * Runtime use of this class object (for example when used with `instanceof` or extending it), is not currently supported.
 *
 * Instances of tree nodes must be created by opening an existing document, inserting values into the document,
 * or by using the constructors and create functions of {@link TreeNodeSchema} produced by {@link SchemaFactory}.
 * @privateRemarks
 * This is a class not an interface to enable stricter type checking (see {@link TreeNode.#brand})
 * and some runtime enforcement of schema class policy (see the the validation in the constructor).
 * This class is however only `type` exported not value exported, preventing the class object from being used,
 * similar to how interfaces work.
 *
 * Not all node implementations include this in their prototype chain (some hide it with a proxy),
 * and thus cause the default/built in `instanceof` to return false despite our type checking and all other APIs treating them as TreeNodes.
 * This class provides a custom `Symbol.hasInstance` to fix `instanceof` for this class and all classes extending it.
 * For now the type-only export prevents use of `instanceof` on this class (but allows it in subclasses like schema classes).
 * @sealed @public
 */
export declare abstract class TreeNode implements WithType {
    #private;
    /**
     * Adds a type symbol for stronger typing.
     * @privateRemarks
     * Subclasses provide more specific strings for this to get strong typing of otherwise type compatible nodes.
     */
    abstract get [typeNameSymbol](): string;
    /**
     * Provides `instanceof` support for testing if a value is a `TreeNode`.
     * @remarks
     * For more options, like including leaf values or narrowing to collections of schema, use `is` or `schema` from {@link TreeNodeApi}.
     * @privateRemarks
     * Due to type-only export, this functionality is not available outside the package.
     */
    static [Symbol.hasInstance](value: unknown): value is TreeNode;
    /**
     * Provides `instanceof` support for all schema classes with public constructors.
     * @remarks
     * For more options, like including leaf values or narrowing to collections of schema, use `is` or `schema` from {@link TreeNodeApi}.
     * @privateRemarks
     * Despite type-only export, this functionality is available outside the package since it is inherited by subclasses.
     */
    static [Symbol.hasInstance]<TSchema extends abstract new (...args: any[]) => TreeNode>(this: TSchema, value: unknown): value is InstanceType<TSchema>;
    protected constructor();
}
/**
 * Check if the prototype derived's prototype chain contains `base`.
 * @param derived - prototype to check
 * @param base - prototype to search for
 * @returns true iff `base` is in the prototype chain starting at `derived`.
 */
export declare function inPrototypeChain(derived: object | null, base: object): boolean;
/**
 * Class which all {@link TreeNode}s must extend.
 * Since this is not exported, it allows robust detection of attempts to create TreeNodes which do not go through SchemaFactory which is the only place which exposes classes that extend this.
 *
 * This has static members which schema classes can override to provide schema specific functionality.
 * These static members are only intended to be used / overridden by code within this package, and are used by the various node kinds.
 * Access to these static members has to be done via `this.constructor.staticMember` to support the overrides, and thus can only be used in the constructor, after the base constructor has been invoked.
 */
export declare abstract class TreeNodeValid<TInput> extends TreeNode {
    /**
     * Schema classes can override this to control what happens at the end of the constructor.
     * The return value from this is returned from the constructor, allowing substituting a proxy if desired.
     *
     * This is not simply done in the derived constructor to enable:
     * - this class to access the value which is being returned before it's returned from the constructor.
     * - the derived class to be provided the input `FlexTreeNode` without relying on a field on the node to hold it.
     */
    protected static prepareInstance<T>(this: typeof TreeNodeValid<T>, instance: TreeNodeValid<T>, input: FlexTreeNode): TreeNodeValid<T>;
    /**
     * Schema classes must override to provide an implementation of RawTreeNode construction.
     */
    protected static buildRawNode<T>(this: typeof TreeNodeValid<T>, instance: TreeNodeValid<T>, input: T): MapTreeNode;
    /**
     * Schema classes can override to provide a callback that is called once when the first node is constructed.
     * This is a good place to perform extra validation and cache schema derived data needed for the implementation of the node.
     */
    protected static oneTimeSetup<T>(this: typeof TreeNodeValid<T>): void;
    /**
     * The most derived constructor (the one invoked with the `new` operator, not a parent class constructor invoked with as `super`) used to construct an instance of this type.
     * @remarks
     * Captured when an instance is constructed.
     *
     * Used to ensure that some derived class (which must override this member, defaulting it to `undefined`) is only instantiated with a single "most derived" class (the constructor actually invoked the the user with `new`).
     *
     * Typically this is override in the class that statically implements {@link TreeNodeSchema} to enforce that all nodes using that schema use the same class and not different subclasses of it.
     *
     * Also used to detect if oneTimeSetup has run.
     *
     * @privateRemarks
     * This defaults to "default", which is used to trigger an error if not overridden in the derived class.
     *
     * The value of this on TreeNodeValid must only be overridden by base classes and never modified.
     * Ways to enforce this immutability prevent it from being overridden,
     * so code modifying constructorCached should be extra careful to avoid accidentally modifying the base/inherited value.
     */
    protected static constructorCached: MostDerivedData | "default" | undefined;
    /**
     * Indicate that `this` is the most derived version of a schema, and thus the only one allowed to be used (other than by being subclassed a single time).
     */
    static markMostDerived(this: typeof TreeNodeValid & TreeNodeSchema): MostDerivedData;
    constructor(input: TInput | InternalTreeNode);
}
/**
 * Data cached about the most derived type in a schema's class hierarchy.
 * @remarks
 * The most derived type is the only one allowed to be referenced by other schema or constructed as a node.
 * It has to be discovered lazily (when a node is constructed or when a {@link TreeViewConfiguration} is made),
 * since JavaScript provides no way to find derived classes, or inject static class initialization time logic into base classes.
 * Additionally since schema can reference other schema through lazy references which might be forward or recursive references,
 * this can not be evaluated for one schema when referenced by another schema.
 *
 * See {@link TreeNodeValid.constructorCached} and {@link TreeNodeValid.markMostDerived}.
 */
export interface MostDerivedData {
    readonly constructor: typeof TreeNodeValid & TreeNodeSchema;
    oneTimeInitialized: boolean;
}
/**
 * A node type internal to `@fluidframework/tree`.
 * @remarks
 * This type is used in the construction of {@link TreeNode} as an implementation detail, but leaks into the public API due to how schema are implemented.
 * @privateRemarks
 * A {@link FlexTreeNode}. Includes {@link RawTreeNode}s.
 * @sealed @public
 */
export interface InternalTreeNode extends ErasedType<"@fluidframework/tree.InternalTreeNode"> {
}
export declare function toFlexTreeNode(node: InternalTreeNode): FlexTreeNode;
//# sourceMappingURL=types.d.ts.map