/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { type AnchorNode, type TreeNodeSchemaIdentifier, type ITreeSubscriptionCursor, type IForestSubscription } from "../../core/index.js";
import { disposeSymbol } from "../../util/index.js";
import { TreeStatus } from "../flex-tree/index.js";
import type { TreeIndex, TreeIndexNodes } from "./types.js";
/**
 * A function that gets the value to index a node on, must be pure and functional.
 * The given cursor should point to the node that will be indexed.
 *
 * @returns a value the index will use as the key for the given node
 *
 * @remarks
 * This function does not own the cursor in any way, it walks the cursor to find the key the node is indexed on
 * but returns the cursor to the state it was in before being passed to the function. It should also not be disposed by this function
 * and must be disposed elsewhere.
 */
export type KeyFinder<TKey> = (tree: ITreeSubscriptionCursor) => TKey;
/**
 * An index from some arbitrary keys to anchor nodes. Keys can be anything that is a {@link TreeValue}.
 * A key can map to multiple nodes but each collection of nodes only results in a single value.
 *
 * @remarks
 * Detached nodes are stored in the index but filtered out when any public facing apis are called. This means that
 * calling {@link keys} will not include any keys that are stored in the index but only map to detached nodes.
 */
export declare class AnchorTreeIndex<TKey, TValue> implements TreeIndex<TKey, TValue> {
    private readonly forest;
    private readonly indexer;
    private readonly getValue;
    private readonly checkTreeStatus;
    private readonly isShallowIndex;
    readonly [Symbol.toStringTag] = "AnchorTreeIndex";
    disposed: boolean;
    /**
     * Caches {@link KeyFinder}s for each schema definition. If a schema maps to null, it does not
     * need to be considered at all for this index. This allows us to skip subtrees that aren't relevant
     * as a performance optimization.
     */
    private readonly keyFinders;
    /**
     * The actual index from keys to anchor nodes.
     * @remarks
     * Should not store empty values (and thus values should be a valid {@link TreeIndexNodes}).
     */
    private readonly keyToNodes;
    /**
     * Maintained for efficient removal of anchor nodes from the index when updating their keys
     */
    private readonly nodeToKey;
    /**
     * Keeps track of anchors for disposal.
     */
    private readonly anchors;
    /**
     * The key finder that is registered on the forest to keep this index updated, maintained
     * here for deregistration on disposal
     */
    private readonly keyFinder;
    /**
     * @param forest - the forest that is being indexed
     * @param indexer - a function that retrieves the key finder based on a given schema or undefined if the schema does not have an associated key finder
     * @param getValue - a pure and functional function that returns the associated value of one or more anchor nodes, can be used to map and filter the indexed anchor nodes
     * so that the values returned from the index are more usable
     * @param checkTreeStatus - a function that gets the tree status from an anchor node, used for filtering out detached nodes
     * @param isShallowIndex - indicates if this index is shallow, meaning that it only allows nodes to be keyed off of fields directly under them rather than anywhere in their subtree.
     * As a performance optimization, re-indexing up the spine can be turned off for shallow indexes.
     */
    constructor(forest: IForestSubscription, indexer: (schemaId: TreeNodeSchemaIdentifier) => KeyFinder<TKey> | undefined, getValue: (anchorNodes: TreeIndexNodes<AnchorNode>) => TValue | undefined, checkTreeStatus: (node: AnchorNode) => TreeStatus | undefined, isShallowIndex?: boolean);
    /**
     * Creates an announced visitor that responds to edits to the forest and updates the index accordingly.
     */
    private acquireVisitor;
    /**
     * Returns the value associated with the given key if it has been indexed
     */
    get(key: TKey): TValue | undefined;
    /**
     * Returns true iff the key exists in the index
     */
    has(key: TKey): boolean;
    /**
     * Returns the number of values that are indexed
     */
    get size(): number;
    /**
     * Returns all keys in the index
     */
    keys(): IterableIterator<TKey>;
    /**
     * Returns an iterable of values in the index
     */
    values(): IterableIterator<TValue>;
    /**
     * Returns an iterable of key, value pairs for every entry in the index
     */
    entries(): IterableIterator<[TKey, TValue]>;
    [Symbol.iterator](): IterableIterator<[TKey, TValue]>;
    /**
     * Applies the provided callback to each entry in the index.
     */
    forEach(callbackfn: (value: TValue, key: TKey, map: AnchorTreeIndex<TKey, TValue>) => void, thisArg?: unknown): void;
    /**
     * Returns an iterable of key, value pairs for every entry in the index, including ones that are detached.
     * This function should only be used for testing purposes, it is not exposed as part of the public {@link TreeIndex} API.
     */
    allEntries(): IterableIterator<[TKey, TValue]>;
    dispose(): void;
    /**
     * Disposes this index and all the anchors it holds onto.
     */
    [disposeSymbol](): void;
    /**
     * Checks if the spine needs to be re-indexed and if so, re-indexes it starting from the given path.
     */
    private reIndexSpine;
    private checkNotDisposed;
    /**
     * Given a cursor in node mode, indexes it.
     */
    private indexNode;
    /**
     * Given a cursor in field mode, recursively indexes all nodes under the field.
     */
    private indexField;
    /**
     * Given a cursor in field mode, indexes all nodes under the field and then indexes all nodes up the spine.
     */
    private indexSpine;
    private removeAnchor;
    /**
     * Filters out any anchor nodes that are detached and returns the value for the remaining nodes.
     */
    private getFilteredValue;
}
/**
 * Checks that an array is of the type {@link TreeIndexNodes} and has at least one element.
 */
export declare function hasElement<T>(array: readonly T[]): array is TreeIndexNodes<T>;
//# sourceMappingURL=anchorTreeIndex.d.ts.map