/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { Comparer, List, Stack } from "./collections";
import { LocalReference, LocalReferenceCollection, LocalReferencePosition } from "./localReference";
import { IMergeTreeDeltaOpArgs, MergeTreeDeltaCallback, MergeTreeMaintenanceCallback } from "./mergeTreeDeltaCallback";
import { TrackingGroupCollection } from "./mergeTreeTracking";
import { ICombiningOp, IJSONSegment, IMarkerDef, IRelativePosition, ReferenceType } from "./ops";
import { PartialSequenceLengths } from "./partialLengths";
import { MapLike, PropertySet } from "./properties";
import { RangeStackMap, ReferencePosition } from "./referencePositions";
import { SegmentGroupCollection } from "./segmentGroupCollection";
import { PropertiesManager } from "./segmentPropertiesManager";
import { Client } from "./client";
export interface IMergeNodeCommon {
    parent?: IMergeBlock;
    /**
     * The length of the contents of the node.
     */
    cachedLength: number;
    index: number;
    ordinal: string;
    isLeaf(): this is ISegment;
}
export declare type IMergeNode = IMergeBlock | ISegment;
export interface IMergeBlock extends IMergeNodeCommon {
    needsScour?: boolean;
    childCount: number;
    children: IMergeNode[];
    partialLengths?: PartialSequenceLengths;
    hierBlock(): IHierBlock | undefined;
    assignChild(child: IMergeNode, index: number, updateOrdinal?: boolean): void;
    setOrdinal(child: IMergeNode, index: number): void;
}
export interface IHierBlock extends IMergeBlock {
    hierToString(indentCount: number): string;
    addNodeReferences(mergeTree: MergeTree, node: IMergeNode): void;
    rightmostTiles: MapLike<ReferencePosition>;
    leftmostTiles: MapLike<ReferencePosition>;
    rangeStacks: RangeStackMap;
}
export interface IRemovalInfo {
    removedSeq: number;
    removedClientIds: number[];
}
export declare function toRemovalInfo(maybe: Partial<IRemovalInfo> | undefined): IRemovalInfo | undefined;
/**
 * A segment representing a portion of the merge tree.
 */
export interface ISegment extends IMergeNodeCommon, Partial<IRemovalInfo> {
    readonly type: string;
    readonly segmentGroups: SegmentGroupCollection;
    readonly trackingCollection: TrackingGroupCollection;
    propertyManager?: PropertiesManager;
    localSeq?: number;
    localRemovedSeq?: number;
    seq?: number;
    clientId: number;
    localRefs?: LocalReferenceCollection;
    properties?: PropertySet;
    addProperties(newProps: PropertySet, op?: ICombiningOp, seq?: number, collabWindow?: CollaborationWindow): PropertySet | undefined;
    clone(): ISegment;
    canAppend(segment: ISegment): boolean;
    append(segment: ISegment): void;
    splitAt(pos: number): ISegment | undefined;
    toJSONObject(): any;
    /**
     * Acks the current segment against the segment group, op, and merge tree.
     *
     * Throws error if the segment state doesn't match segment group or op.
     * E.g. Segment group not first is pending queue.
     * Inserted segment does not have unassigned sequence number.
     *
     * Returns true if the op  modifies the segment, otherwise false.
     * The only current false case is overlapping remove, where a segment is removed
     * by a previously sequenced operation before the current operation is acked.
     */
    ack(segmentGroup: SegmentGroup, opArgs: IMergeTreeDeltaOpArgs, mergeTree: MergeTree): boolean;
}
export interface IMarkerModifiedAction {
    (marker: Marker): void;
}
export interface ISegmentAction<TClientData> {
    (segment: ISegment, pos: number, refSeq: number, clientId: number, start: number, end: number, accum: TClientData): boolean;
}
export interface ISegmentChanges {
    next?: ISegment;
    replaceCurrent?: ISegment;
}
export interface BlockAction<TClientData> {
    (block: IMergeBlock, pos: number, refSeq: number, clientId: number, start: number | undefined, end: number | undefined, accum: TClientData): boolean;
}
export interface NodeAction<TClientData> {
    (node: IMergeNode, pos: number, refSeq: number, clientId: number, start: number | undefined, end: number | undefined, clientData: TClientData): boolean;
}
export interface IncrementalSegmentAction<TContext> {
    (segment: ISegment, state: IncrementalMapState<TContext>): any;
}
export interface IncrementalBlockAction<TContext> {
    (state: IncrementalMapState<TContext>): any;
}
export interface BlockUpdateActions {
    child: (block: IMergeBlock, index: number) => void;
}
export interface InsertContext {
    candidateSegment?: ISegment;
    prepareEvents?: boolean;
    structureChange?: boolean;
    leaf: (segment: ISegment | undefined, pos: number, ic: InsertContext) => ISegmentChanges;
    continuePredicate?: (continueFromBlock: IMergeBlock) => boolean;
}
export interface SegmentActions<TClientData> {
    leaf?: ISegmentAction<TClientData>;
    shift?: NodeAction<TClientData>;
    contains?: NodeAction<TClientData>;
    pre?: BlockAction<TClientData>;
    post?: BlockAction<TClientData>;
}
export interface IncrementalSegmentActions<TContext> {
    leaf: IncrementalSegmentAction<TContext>;
    pre?: IncrementalBlockAction<TContext>;
    post?: IncrementalBlockAction<TContext>;
}
export interface SearchResult {
    text: string;
    pos: number;
}
export interface MergeTreeStats {
    maxHeight: number;
    nodeCount: number;
    leafCount: number;
    removedLeafCount: number;
    liveCount: number;
    histo: number[];
    windowTime?: number;
    packTime?: number;
    ordTime?: number;
    maxOrdTime?: number;
}
export interface SegmentGroup {
    segments: ISegment[];
    localSeq: number;
}
export declare class MergeNode implements IMergeNodeCommon {
    index: number;
    ordinal: string;
    parent?: IMergeBlock;
    cachedLength: number;
    isLeaf(): boolean;
}
export declare function ordinalToArray(ord: string): number[];
export declare const MaxNodesInBlock = 8;
export declare class MergeBlock extends MergeNode implements IMergeBlock {
    childCount: number;
    children: IMergeNode[];
    constructor(childCount: number);
    hierBlock(): HierMergeBlock | undefined;
    setOrdinal(child: IMergeNode, index: number): void;
    assignChild(child: IMergeNode, index: number, updateOrdinal?: boolean): void;
}
declare class HierMergeBlock extends MergeBlock implements IMergeBlock {
    rightmostTiles: MapLike<ReferencePosition>;
    leftmostTiles: MapLike<ReferencePosition>;
    rangeStacks: MapLike<Stack<ReferencePosition>>;
    constructor(childCount: number);
    addNodeReferences(mergeTree: MergeTree, node: IMergeNode): void;
    hierBlock(): this;
    hierToString(indentCount: number): string;
}
export declare abstract class BaseSegment extends MergeNode implements ISegment {
    clientId: number;
    seq: number;
    removedSeq?: number;
    removedClientIds?: number[];
    readonly segmentGroups: SegmentGroupCollection;
    readonly trackingCollection: TrackingGroupCollection;
    propertyManager?: PropertiesManager;
    properties?: PropertySet;
    localRefs?: LocalReferenceCollection;
    abstract readonly type: string;
    localSeq?: number;
    localRemovedSeq?: number;
    addProperties(newProps: PropertySet, op?: ICombiningOp, seq?: number, collabWindow?: CollaborationWindow): PropertySet | undefined;
    hasProperty(key: string): boolean;
    isLeaf(): boolean;
    protected cloneInto(b: ISegment): void;
    canAppend(segment: ISegment): boolean;
    protected addSerializedProps(jseg: IJSONSegment): void;
    abstract toJSONObject(): any;
    ack(segmentGroup: SegmentGroup, opArgs: IMergeTreeDeltaOpArgs, mergeTree: MergeTree): boolean;
    splitAt(pos: number): ISegment | undefined;
    private copyPropertiesTo;
    abstract clone(): ISegment;
    abstract append(segment: ISegment): void;
    protected abstract createSplitSegmentAt(pos: number): BaseSegment | undefined;
}
export declare const reservedMarkerIdKey = "markerId";
export declare const reservedMarkerSimpleTypeKey = "markerSimpleType";
export interface IJSONMarkerSegment extends IJSONSegment {
    marker: IMarkerDef;
}
export declare class Marker extends BaseSegment implements ReferencePosition {
    refType: ReferenceType;
    static readonly type = "Marker";
    static is(segment: ISegment): segment is Marker;
    readonly type = "Marker";
    static make(refType: ReferenceType, props?: PropertySet): Marker;
    constructor(refType: ReferenceType);
    toJSONObject(): IJSONMarkerSegment;
    static fromJSONObject(spec: any): Marker | undefined;
    clone(): Marker;
    getSegment(): this;
    getOffset(): number;
    hasSimpleType(simpleTypeName: string): boolean;
    getProperties(): PropertySet | undefined;
    getId(): string | undefined;
    /**
     * @deprecated - use refHasTileLabels
     */
    hasTileLabels(): boolean;
    /**
     * @deprecated - use refHasRangeLabels
     */
    hasRangeLabels(): boolean;
    /**
     * @deprecated - use refHasTileLabel
     */
    hasTileLabel(label: string): boolean;
    /**
     * @deprecated - use refHasRangeLabel
     */
    hasRangeLabel(label: string): boolean;
    /**
     * @deprecated - use refGetTileLabels
     */
    getTileLabels(): string[] | undefined;
    /**
     * @deprecated - use refGetRangeLabels
     */
    getRangeLabels(): string[] | undefined;
    toString(): string;
    protected createSplitSegmentAt(pos: number): undefined;
    canAppend(segment: ISegment): boolean;
    append(): void;
}
export declare enum IncrementalExecOp {
    Go = 0,
    Stop = 1,
    Yield = 2
}
export declare class IncrementalMapState<TContext> {
    block: IMergeBlock;
    actions: IncrementalSegmentActions<TContext>;
    pos: number;
    refSeq: number;
    clientId: number;
    context: TContext;
    start: number;
    end: number;
    childIndex: number;
    op: IncrementalExecOp;
    constructor(block: IMergeBlock, actions: IncrementalSegmentActions<TContext>, pos: number, refSeq: number, clientId: number, context: TContext, start: number, end: number, childIndex?: number);
}
export declare class CollaborationWindow {
    clientId: number;
    collaborating: boolean;
    minSeq: number;
    currentSeq: number;
    localSeq: number;
    loadFrom(a: CollaborationWindow): void;
}
export declare const compareNumbers: (a: number, b: number) => number;
export declare const compareStrings: (a: string, b: string) => number;
export declare function internedSpaces(n: number): string;
export interface IConsensusInfo {
    marker: Marker;
    callback: (m: Marker) => void;
}
export interface ClientSeq {
    refSeq: number;
    clientId: string;
}
export declare const clientSeqComparer: Comparer<ClientSeq>;
export interface LRUSegment {
    segment?: ISegment;
    maxSeq: number;
}
export interface SegmentAccumulator {
    segments: ISegment[];
}
export interface MinListener {
    minRequired: number;
    onMinGE(minSeq: number): void;
}
export declare type LocalReferenceMapper = (id: string) => LocalReference;
export declare class MergeTree {
    options?: PropertySet | undefined;
    private static readonly zamboniSegmentsMaxCount;
    static readonly options: {
        incrementalUpdate: boolean;
        insertAfterRemovedSegs: boolean;
        zamboniSegments: boolean;
    };
    private static readonly initBlockUpdateActions;
    private static readonly theUnfinishedNode;
    root: IMergeBlock;
    private readonly blockUpdateActions;
    readonly collabWindow: CollaborationWindow;
    pendingSegments: List<SegmentGroup> | undefined;
    private segmentsToScour;
    private readonly idToSegment;
    private minSeqListeners;
    mergeTreeDeltaCallback?: MergeTreeDeltaCallback;
    mergeTreeMaintenanceCallback?: MergeTreeMaintenanceCallback;
    constructor(options?: PropertySet | undefined);
    private makeBlock;
    clone(): void;
    blockClone(block: IMergeBlock, segments?: ISegment[]): MergeBlock;
    private segmentClone;
    localNetLength(segment: ISegment): number;
    mapIdToSegment(id: string, segment: ISegment): void;
    private addNode;
    reloadFromSegments(segments: ISegment[]): void;
    startCollaboration(localClientId: number, minSeq: number, currentSeq: number): void;
    private addToLRUSet;
    private underflow;
    private scourNode;
    private packParent;
    private zamboniSegments;
    getCollabWindow(): CollaborationWindow;
    getStats(): MergeTreeStats;
    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): number;
    getContainingSegment<T extends ISegment>(pos: number, refSeq: number, clientId: number): {
        segment: T | undefined;
        offset: number | undefined;
    };
    /**
     * @internal must only be used by client
     * @param segoff - The segment and offset to slide from
     * @returns The segment and offset to slide to
     */
    _getSlideToSegment(segoff: {
        segment: ISegment | undefined;
        offset: number | undefined;
    }): {
        segment: ISegment | undefined;
        offset: number | 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 slideReferences;
    private updateSegmentRefsAfterMarkRemoved;
    private blockLength;
    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;
    findTile(startPos: number, clientId: number, tileLabel: string, posPrecedesTile?: 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 leftExcursion;
    /**
     * Visit segments starting from node's right siblings, then up to node's parent.
     * All segments past `node` are visited, regardless of their visibility.
     */
    private rightExcursion;
    private insertingWalk;
    private split;
    private nodeUpdateOrdinals;
    /**
     * 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
     */
    annotateRange(start: number, end: number, props: PropertySet, combiningOp: ICombiningOp | undefined, refSeq: number, clientId: number, seq: number, opArgs: IMergeTreeDeltaOpArgs): void;
    markRangeRemoved(start: number, end: number, refSeq: number, clientId: number, seq: number, overwrite: boolean | undefined, opArgs: IMergeTreeDeltaOpArgs): void;
    private nodeUpdateLengthNewStructure;
    removeLocalReferencePosition(lref: LocalReferencePosition): LocalReferencePosition | undefined;
    createLocalReferencePosition(segment: ISegment, offset: number | undefined, refType: ReferenceType, properties: PropertySet | undefined, client: Client): LocalReferencePosition;
    /**
     * @deprecated - use removeLocalReferencePosition
     */
    removeLocalReference(segment: ISegment, lref: LocalReference): void;
    /**
     * @deprecated - use createLocalReference
     */
    addLocalReference(lref: LocalReference): void;
    private blockUpdate;
    private blockUpdatePathLengths;
    private blockUpdateLength;
    map<TClientData>(actions: SegmentActions<TClientData>, refSeq: number, clientId: number, accum: TClientData): void;
    mapRange<TClientData>(actions: SegmentActions<TClientData>, refSeq: number, clientId: number, accum: TClientData, start?: number, end?: number, splitRange?: boolean): void;
    incrementalBlockMap<TContext>(stateStack: Stack<IncrementalMapState<TContext>>): void;
    private nodeMap;
    walkAllSegments<TClientData>(block: IMergeBlock, action: (segment: ISegment, accum?: TClientData) => boolean, accum?: TClientData): boolean;
    private nodeMapReverse;
}
export {};
//# sourceMappingURL=mergeTree.d.ts.map