/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { type DeltaMark } from "../../core/index.js";
import { type TreeStatus } from "../../feature-libraries/index.js";
import { type TreeNodeSchema, type TreeNode, type TreeLeafValue, type ImplicitAllowedTypes, type TreeNodeFromImplicitAllowedTypes } from "../core/index.js";
import type { TreeChangeEvents } from "./treeChangeEvents.js";
/**
 * A `"retain"` op in an {@link ArrayNodeDeltaOp} sequence.
 * Represents elements that were neither inserted into nor removed from the array.
 * @sealed @alpha
 */
export interface ArrayNodeRetainOp {
    readonly type: "retain";
    readonly count: number;
}
/**
 * A `"retain"` op in an {@link ArrayNodeTreeChangedDeltaOp} sequence, used in
 * {@link NodeChangedDataTreeDelta} payloads delivered to
 * {@link TreeChangeEventsAlpha.treeChanged} on array nodes.
 *
 * Extends {@link ArrayNodeRetainOp} with a {@link ArrayNodeTreeChangedRetainOp.subtreeChanged}
 * flag that indicates whether any descendant of the retained element changed.
 * @sealed @alpha
 */
export interface ArrayNodeTreeChangedRetainOp extends ArrayNodeRetainOp {
    /**
     * Whether any descendant of this retained element changed.
     * `true` if the element's subtree changed; `false` if nothing changed within it.
     * @remarks
     * Subscribe to `nodeChanged` or `treeChanged` on the element node itself for details.
     */
    readonly subtreeChanged: boolean;
}
/**
 * A single operation in an array-node delta delivered by {@link TreeChangeEventsAlpha.treeChanged}.
 * Extends {@link ArrayNodeDeltaOp}: retain ops carry a {@link ArrayNodeTreeChangedRetainOp.subtreeChanged}
 * flag indicating whether any descendant of the retained element changed.
 * @alpha
 */
export type ArrayNodeTreeChangedDeltaOp = ArrayNodeTreeChangedRetainOp | ArrayNodeInsertOp | ArrayNodeRemoveOp;
/**
 * An `"insert"` op in an {@link ArrayNodeDeltaOp} sequence.
 * Represents elements added to the array.
 * Read the new element values from the current tree at the positions described by this op.
 * @sealed @alpha
 */
export interface ArrayNodeInsertOp {
    readonly type: "insert";
    readonly count: number;
}
/**
 * A `"remove"` op in an {@link ArrayNodeDeltaOp} sequence.
 * Represents elements removed from the array.
 * @sealed @alpha
 */
export interface ArrayNodeRemoveOp {
    readonly type: "remove";
    readonly count: number;
}
/**
 * A single operation in an array node change delta. Used to efficiently sync an external
 * representation of an array (e.g. a text editor or virtual list) with tree changes without
 * needing to snapshot the old state or diff the entire array. Each op describes a contiguous run
 * of positions in the array before the change. For inserts, read the new element values from the
 * current tree at those positions.
 *
 * @remarks
 * There is no dedicated `"move"` op. Moves are represented as `"remove"` + `"insert"`.
 * When an element is moved within the same array it appears
 * as a `"remove"` at the source position followed by an `"insert"` at the destination position.
 * When an element is moved across two different arrays, the source array's delta contains a
 * `"remove"` and the destination array's delta contains an `"insert"` — they cannot be
 * correlated without additional bookkeeping on the caller's side.
 *
 * @sealed @alpha
 */
export type ArrayNodeDeltaOp = ArrayNodeRetainOp | ArrayNodeInsertOp | ArrayNodeRemoveOp;
/**
 * Provides various functions for analyzing {@link TreeNode}s.
 *
 * @remarks
 * With the exception of {@link TreeNodeApi.status}, these functions should not be called with nodes that have
 * been {@link TreeStatus.Deleted | deleted}.
 * To verify whether or not a node already has been deleted, use the {@link TreeNodeApi.status} function.
 *
 * This type should only be used via the public {@link (Tree:variable)} export.
 *
 * @privateRemarks
 * Due to limitations of API-Extractor link resolution, this type can't be moved into internalTypes but should be considered just an implementation detail of the `Tree` export.
 *
 * Inlining the typing of this interface onto the `Tree` object provides slightly different .d.ts generation,
 * which avoids typescript expanding the type of TreeNodeSchema and thus encountering
 * https://github.com/microsoft/rushstack/issues/1958.
 * @sealed @public
 */
export interface TreeNodeApi {
    /**
     * The schema information for this node.
     */
    schema(node: TreeNode | TreeLeafValue): TreeNodeSchema;
    /**
     * Narrow the type of the given value if it satisfies the given schema.
     * @example
     * ```ts
     * if (node.is(myNode, Point)) {
     *     const y = myNode.y; // `myNode` is now known to satisfy the `Point` schema and therefore has a `y` coordinate.
     * }
     * ```
     */
    is<TSchema extends ImplicitAllowedTypes>(value: unknown, schema: TSchema): value is TreeNodeFromImplicitAllowedTypes<TSchema>;
    /**
     * Return the node under which this node resides in the tree (or undefined if this is a root node of the tree).
     *
     * @throws A {@link @fluidframework/telemetry-utils#UsageError} if the node has been {@link TreeStatus.Deleted | deleted}.
     *
     * @see {@link (TreeAlpha:interface).child}
     * @see {@link (TreeAlpha:interface).children}
     */
    parent(node: TreeNode): TreeNode | undefined;
    /**
     * The key of the given node under its parent.
     *
     * @remarks
     * If `node` is an element in a {@link (TreeArrayNode:interface)}, this returns the index of `node` in the array node (a `number`).
     * Otherwise, this returns the key of the field that it is under (a `string`).
     *
     * @throws A {@link @fluidframework/telemetry-utils#UsageError} if the node has been {@link TreeStatus.Deleted | deleted}.
     */
    key(node: TreeNode): string | number;
    /**
     * Register an event listener on the given node.
     * @param node - The node whose events should be subscribed to.
     * @param eventName - Which event to subscribe to.
     * @param listener - The callback to trigger for the event. The tree can be read during the callback, but it is invalid to modify the tree during this callback.
     * @returns A callback function which will deregister the event.
     * This callback should be called only once.
     * @remarks
     * The returned unsubscribe function should be called any time the need for the `listener` callback ends before the node is {@link TreeStatus.Deleted | deleted} (Not just {@link TreeStatus.Removed | removed}).
     * Doing so removes the overhead of tracking and triggering the event, and also avoids leaking any memory retained by the callback.
     */
    on<K extends keyof TreeChangeEvents>(node: TreeNode, eventName: K, listener: TreeChangeEvents[K]): () => void;
    /**
     * Returns the {@link TreeStatus} of the given node.
     */
    status(node: TreeNode): TreeStatus;
    /**
     * Returns the {@link SchemaFactory.identifier | identifier} of the given node in the most compressed form possible.
     * @remarks
     * If the node is {@link Unhydrated | hydrated}  and its identifier is a valid UUID that was automatically generated by the SharedTree it is part of (or something else using the same {@link @fluidframework/id-compressor#IIdCompressor}), then this will return a process-unique integer corresponding to that identifier.
     * This is useful for performance-sensitive scenarios involving many nodes with identifiers that need to be compactly retained in memory or used for efficient lookup.
     * Note that automatically generated identifiers that were accessed before the node was hydrated will return the generated UUID, not the process-unique integer.
     *
     * If the node's identifier is any other user-provided string, then this will return that string.
     *
     * If the node has no identifier (that is, it has no {@link SchemaFactory.identifier | identifier} field), then this returns `undefined`.
     *
     * If the node has more than one identifier, then this will throw an error.
     *
     * The returned integer should not be serialized or preserved outside of the current process.
     * Its lifetime is that of the current in-memory instance of the FF container for this client, and it is not guaranteed to be unique or stable outside of that context.
     * The same node's identifier may, for example, be different across multiple sessions for the same client and document, or different across two clients in the same session.
     */
    shortId(node: TreeNode): number | string | undefined;
}
/**
 * {@inheritDoc TreeNodeApi}
 */
export declare const treeNodeApi: TreeNodeApi;
/**
 * Converts an array of internal {@link DeltaMark}s for a sequence field into sequential
 * array delta ops suitable for inclusion in {@link NodeChangedDataDelta.delta}.
 *
 * Each mark in the delta describes a contiguous run of positions in the original array:
 * - A mark with only `count` (no attach/detach) → `"retain"` with no subtree information
 * - A mark with only `attach` → `"insert"` (new elements added)
 * - A mark with only `detach` → `"remove"` (elements removed)
 * - A mark with both `attach` and `detach` → `"remove"` + `"insert"`
 *
 * @param marks - The low-level delta marks for the array's sequence field.
 *
 * @privateRemarks
 * The case where both `attach` and `detach` are set is unreachable today: the sequence-field
 * encoder never emits such marks for array (EmptyKey) fields. It is handled defensively.
 */
export declare function deltaMarksToArrayOps(marks: readonly DeltaMark[]): ArrayNodeDeltaOp[];
/**
 * Converts an array of internal {@link DeltaMark}s for a sequence field into sequential
 * {@link ArrayNodeTreeChangedDeltaOp}s suitable for inclusion in
 * {@link NodeChangedDataTreeDelta.delta} (delivered to {@link TreeChangeEventsAlpha.treeChanged}).
 *
 * Same conversion rules as {@link deltaMarksToArrayOps}, but retain ops additionally carry a
 * {@link ArrayNodeTreeChangedRetainOp.subtreeChanged} flag derived from whether the mark has
 * a `fields` property (indicating a descendant changed).
 *
 * @param marks - The low-level delta marks for the array's sequence field.
 *
 * @privateRemarks
 * The case where both `attach` and `detach` are set is unreachable today: the sequence-field
 * encoder never emits such marks for array (EmptyKey) fields. It is handled defensively.
 */
export declare function deltaMarksToArrayOpsForTreeChanged(marks: readonly DeltaMark[]): ArrayNodeTreeChangedDeltaOp[];
/**
 * Returns a schema for a value if the value is a {@link TreeNode} or a {@link TreeLeafValue}.
 * Returns undefined for other values.
 */
export declare function tryGetSchema(value: unknown): undefined | TreeNodeSchema;
/**
 * Gets the identifier from a node.
 *
 * @param node - {@link TreeNode} where you want to extract the identifier from.
 * @param compression - string value to determine what type of identifier you want to retrieve.
 *
 * @remarks
 * If the node does not contain an identifier field, it returns undefined.
 *
 * If `compression` is set to `compressed`:
 *
 * - If the node contains a compressible identifier known by the id compressor, the compressed identifier is returned.
 *
 * - If the node contains an identifier, but is not compressible or unknown by the id compressor, `undefined` is returned.
 *
 * If `compression` is set to `preferCompressed`:
 *
 * - If the node contains a compressible identifier known by the id compressor, the compressed identifier is returned.
 *
 * - If the node contains an identifier, but is not compressible or unknown by the id compressor, the uncompressed identifier is returned.
 *
 * If `compression` is set to `uncompressed`:
 * - If the node contains an identifier field, the uncompressed identifier is returned.
 */
export declare function getIdentifierFromNode(node: TreeNode, compression: "preferCompressed"): number | string | undefined;
export declare function getIdentifierFromNode(node: TreeNode, compression: "compressed"): number | undefined;
export declare function getIdentifierFromNode(node: TreeNode, compression: "uncompressed"): string | undefined;
/**
 * Gets the stored key with which the provided node is associated in the parent.
 */
export declare function getStoredKey(node: TreeNode): string | number;
/**
 * Given a node schema, gets the property key corresponding with the provided {@link FieldProps.key | stored key}.
 */
export declare function getPropertyKeyFromStoredKey(schema: TreeNodeSchema, storedKey: string | number): string | number;
//# sourceMappingURL=treeNodeApi.d.ts.map