/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { Comparer, Heap, List, Stack } from "./collections";
import { LocalReferencePosition } from "./localReference";
import { CollaborationWindow, IMergeBlock, IncrementalMapState, ISegment, ISegmentAction, MergeBlock, MergeNode, SegmentGroup } from "./mergeTreeNodes";
import { IMergeTreeDeltaOpArgs, MergeTreeDeltaCallback, MergeTreeMaintenanceCallback } from "./mergeTreeDeltaCallback";
import { ICombiningOp, IMergeTreeDeltaOp, IRelativePosition, ReferenceType } from "./ops";
import { PropertySet } from "./properties";
import { ReferencePosition, RangeStackMap } from "./referencePositions";
import { PropertiesRollback } from "./segmentPropertiesManager";
/**
 * @deprecated For internal use only. public export will be removed.
 * @internal
 */
export interface ClientSeq {
    refSeq: number;
    clientId: string;
}
export interface IMergeTreeOptions {
    catchUpBlobName?: string;
    /**
     * Whether to enable the length calculations implemented in
     * https://github.com/microsoft/FluidFramework/pull/11678
     *
     * These calculations resolve bugginess that causes eventual consistency issues in certain conflicting
     * removal cases, but regress some index-based undo-redo implementations. The suggested path for
     * consumers is to switch to LocalReference-based undo-redo implementation (see
     * https://github.com/microsoft/FluidFramework/pull/11899) and enable this feature flag.
     *
     * default: false
     */
    mergeTreeUseNewLengthCalculations?: boolean;
    mergeTreeSnapshotChunkSize?: number;
    /**
     * Whether to use the SnapshotV1 format over SnapshotLegacy.
     *
     * SnapshotV1 stores a view of the merge-tree at the current sequence number, preserving merge metadata
     * (e.g. clientId, seq, etc.) only for segment changes within the collab window.
     *
     * SnapshotLegacy stores a view of the merge-tree at the minimum sequence number along with the ops between
     * the minimum sequence number and the current sequence number.
     *
     * Both formats merge segments where possible (see {@link ISegment.canAppend})
     *
     * default: false
     *
     * @remarks
     * Despite the "legacy"/"V1" naming, both formats are actively used at the time of writing. SharedString
     * uses legacy and Matrix uses V1.
     */
    newMergeTreeSnapshotFormat?: boolean;
    /**
     * Options related to attribution
     */
    attribution?: IMergeTreeAttributionOptions;
}
export interface IMergeTreeAttributionOptions {
    /**
     * If enabled, segments will store attribution keys which can be used with the runtime to determine
     * attribution information (i.e. who created the content and when it was created).
     *
     * This flag only applied to new documents: if a snapshot is loaded, whether or not attribution keys
     * are tracked is determined by the presence of existing attribution keys in the snapshot.
     *
     * default: false
     */
    track?: boolean;
}
/**
 * @deprecated For internal use only. public export will be removed.
 * @internal
 */
export declare const clientSeqComparer: Comparer<ClientSeq>;
/**
 * @deprecated For internal use only. public export will be removed.
 * @internal
 */
export interface LRUSegment {
    segment?: ISegment;
    maxSeq: number;
}
export interface IRootMergeBlock extends IMergeBlock {
    mergeTree?: MergeTree;
}
/**
 * @internal
 */
export declare class MergeTree {
    options?: IMergeTreeOptions | undefined;
    static readonly options: {
        incrementalUpdate: boolean;
        insertAfterRemovedSegs: boolean;
        zamboniSegments: boolean;
    };
    private static readonly initBlockUpdateActions;
    private static readonly theUnfinishedNode;
    private readonly blockUpdateActions;
    readonly collabWindow: CollaborationWindow;
    pendingSegments: List<SegmentGroup> | undefined;
    private segmentsToScour;
    get getSegmentsToScour(): Heap<LRUSegment> | undefined;
    /**
     * Whether or not all blocks in the mergeTree currently have information about local partial lengths computed.
     * This information is only necessary on reconnect, and otherwise costly to bookkeep.
     * This field enables tracking whether partials need to be recomputed using localSeq information.
     */
    private localPartialsComputed;
    private readonly idToSegment;
    private minSeqListeners;
    mergeTreeDeltaCallback?: MergeTreeDeltaCallback;
    mergeTreeMaintenanceCallback?: MergeTreeMaintenanceCallback;
    constructor(options?: IMergeTreeOptions | undefined);
    private _root;
    get root(): IRootMergeBlock;
    set root(value: IRootMergeBlock);
    makeBlock(childCount: number): MergeBlock;
    clone(): void;
    blockClone(block: IMergeBlock, segments?: ISegment[]): MergeBlock;
    private segmentClone;
    /**
     * Compute the net length of this segment from a local perspective.
     * @param segment - Segment whose length to find
     * @param localSeq - localSeq at which to find the length of this segment. If not provided,
     * default is to consider the local client's current perspective. Only local sequence
     * numbers corresponding to un-acked operations give valid results.
     */
    localNetLength(segment: ISegment, refSeq?: number, localSeq?: number): number | undefined;
    mapIdToSegment(id: string, segment: ISegment): void;
    private addNode;
    reloadFromSegments(segments: ISegment[]): void;
    startCollaboration(localClientId: number, minSeq: number, currentSeq: number): void;
    private addToLRUSet;
    getCollabWindow(): CollaborationWindow;
    getLength(refSeq: number, clientId: number): number;
    /**
     * Returns the current length of the MergeTree for the local client.
     */
    get length(): number;
    getPosition(node: MergeNode, refSeq: number, clientId: number, localSeq?: number): number;
    getContainingSegment<T extends ISegment>(pos: number, refSeq: number, clientId: number, localSeq?: number): {
        segment: T | undefined;
        offset: number | undefined;
    };
    /**
     * @remarks Must only be used by client.
     * @param segment - The segment to slide from.
     * @returns The segment to.
     * @internal
     */
    _getSlideToSegment(segment: ISegment | undefined): ISegment | undefined;
    /**
     * This method should only be called when the current client sequence number is
     * max(remove segment sequence number, add reference sequence number).
     * Otherwise eventual consistency is not guaranteed.
     * See `packages\dds\merge-tree\REFERENCEPOSITIONS.md`
     */
    private slideAckedRemovedSegmentReferences;
    private blockLength;
    /**
     * Compute local partial length information
     *
     * Public only for use by internal tests
     *
     * @internal
     */
    computeLocalPartials(refSeq: number): void;
    private nodeLength;
    addMinSeqListener(minRequired: number, onMinGE: (minSeq: number) => void): void;
    private notifyMinSeqListeners;
    setMinSeq(minSeq: number): void;
    referencePositionToLocalPosition(refPos: ReferencePosition, refSeq?: number, clientId?: number): number;
    getStackContext(startPos: number, clientId: number, rangeLabels: string[]): RangeStackMap;
    /**
     * Finds the nearest reference with ReferenceType.Tile to `startPos` in the direction dictated by `tilePrecedesPos`.
     *
     * @param startPos - Position at which to start the search
     * @param clientId - clientId dictating the perspective to search from
     * @param tileLabel - Label of the tile to search for
     * @param tilePrecedesPos - Whether the desired tile comes before (true) or after (false) `startPos`
     */
    findTile(startPos: number, clientId: number, tileLabel: string, tilePrecedesPos?: boolean): {
        tile: ReferencePosition;
        pos: number;
    } | undefined;
    private search;
    private searchBlock;
    private backwardSearch;
    private backwardSearchBlock;
    private updateRoot;
    /**
     * Assign sequence number to existing segment; update partial lengths to reflect the change
     * @param seq - sequence number given by server to pending segment
     */
    ackPendingSegment(opArgs: IMergeTreeDeltaOpArgs): void;
    private addToPendingList;
    getMarkerFromId(id: string): ISegment | undefined;
    /**
     * Given a position specified relative to a marker id, lookup the marker
     * and convert the position to a character position.
     * @param relativePos - Id of marker (may be indirect) and whether position is before or after marker.
     * @param refseq - The reference sequence number at which to compute the position.
     * @param clientId - The client id with which to compute the position.
     */
    posFromRelativePos(relativePos: IRelativePosition, refseq?: number, clientId?: number): number;
    insertSegments(pos: number, segments: ISegment[], refSeq: number, clientId: number, seq: number, opArgs: IMergeTreeDeltaOpArgs | undefined): void;
    insertAtReferencePosition(referencePosition: ReferencePosition, insertSegment: ISegment, opArgs: IMergeTreeDeltaOpArgs): void;
    /**
     * Resolves a remote client's position against the local sequence
     * and returns the remote client's position relative to the local
     * sequence. The client ref seq must be above the minimum sequence number
     * or the return value will be undefined.
     * Generally this method is used in conjunction with signals which provide
     * point in time values for the below parameters, and is useful for things
     * like displaying user position. It should not be used with persisted values
     * as persisted values will quickly become invalid as the remoteClientRefSeq
     * moves below the minimum sequence number
     * @param remoteClientPosition - The remote client's position to resolve
     * @param remoteClientRefSeq - The reference sequence number of the remote client
     * @param remoteClientId - The client id of the remote client
     */
    resolveRemoteClientPosition(remoteClientPosition: number, remoteClientRefSeq: number, remoteClientId: number): number | undefined;
    private insertChildNode;
    private blockInsert;
    private readonly splitLeafSegment;
    private ensureIntervalBoundary;
    private breakTie;
    private insertingWalk;
    private split;
    nodeUpdateOrdinals(block: IMergeBlock): void;
    /**
     * Annotate a range with properties
     * @param start - The inclusive start position of the range to annotate
     * @param end - The exclusive end position of the range to annotate
     * @param props - The properties to annotate the range with
     * @param combiningOp - Optional. Specifies how to combine values for the property, such as "incr" for increment.
     * @param refSeq - The reference sequence number to use to apply the annotate
     * @param clientId - The id of the client making the annotate
     * @param seq - The sequence number of the annotate operation
     * @param opArgs - The op args for the annotate op. this is passed to the merge tree callback if there is one
     * @param rollback - Whether this is for a local rollback and what kind
     */
    annotateRange(start: number, end: number, props: PropertySet, combiningOp: ICombiningOp | undefined, refSeq: number, clientId: number, seq: number, opArgs: IMergeTreeDeltaOpArgs, rollback?: PropertiesRollback): void;
    markRangeRemoved(start: number, end: number, refSeq: number, clientId: number, seq: number, overwrite: boolean | undefined, opArgs: IMergeTreeDeltaOpArgs): void;
    /**
     * Revert an unacked local op
     */
    rollback(op: IMergeTreeDeltaOp, localOpMetadata: SegmentGroup): void;
    /**
     * Walk the segments up to the current segment and calculate its position
     */
    private findRollbackPosition;
    nodeUpdateLengthNewStructure(node: IMergeBlock, recur?: boolean): void;
    removeLocalReferencePosition(lref: LocalReferencePosition): LocalReferencePosition | undefined;
    createLocalReferencePosition(segment: ISegment, offset: number, refType: ReferenceType, properties: PropertySet | undefined): LocalReferencePosition;
    private normalizeAdjacentSegments;
    /**
     * Normalizes the segments nearby `segmentGroup` to be ordered as they would if the op submitting `segmentGroup`
     * is rebased to the current sequence number.
     * This primarily affects the ordering of adjacent segments that were removed between the original submission of
     * the local ops and now.
     * Consider the following sequence of events:
     * Initial state: "hi my friend" (seq: 0)
     * - Client 1 inserts "good " to make "hi my good friend" (op1, refSeq: 0)
     * - Client 2 deletes "my " to make "hi friend" (op2, refSeq: 0)
     * - op2 is sequenced giving seq 1
     * - Client 1 disconnects and reconnects at seq: 1.
     *
     * At this point in time, client 1 will have segments ["hi ", Removed"my ", Local"good ", "friend"].
     * However, the rebased op that it submits will cause client 2 to have segments
     * ["hi ", Local"good ", Removed"my ", "friend"].
     *
     * The difference in ordering can be problematic for tie-breaking concurrently inserted segments in some scenarios.
     * Rather than incur extra work tie-breaking these scenarios for all clients, when client 1 rebases its operation,
     * it can fix up its local state to align with what would be expected of the op it resubmits.
     */
    normalizeSegmentsOnRebase(): void;
    private blockUpdate;
    blockUpdatePathLengths(startBlock: IMergeBlock | undefined, seq: number, clientId: number, newStructure?: boolean): void;
    private blockUpdateLength;
    mapRange<TClientData>(handler: ISegmentAction<TClientData>, refSeq: number, clientId: number, accum: TClientData, start?: number, end?: number, splitRange?: boolean): void;
    incrementalBlockMap<TContext>(stateStack: Stack<IncrementalMapState<TContext>>): void;
    private nodeMap;
}
//# sourceMappingURL=mergeTree.d.ts.map