/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { ChangeAtomId, ChangesetLocalId, RevisionMetadataSource, RevisionTag, TaggedChange } from "../../core";
import { RangeMap } from "../../util";
import { CrossFieldManager, CrossFieldQuerySet } from "../modular-schema";
import { Attach, Detach, Insert, LineageEvent, Mark, NoopMark, Changeset, MoveId, Delete, CellId, CellMark, AttachAndDetach, MarkEffect } from "./types";
import { MoveEffectTable } from "./moveEffectTable";
import { EmptyInputCellMark, MoveMarkEffect, DetachOfRemovedNodes, CellRename } from "./helperTypes";
export declare function isEmpty<T>(change: Changeset<T>): boolean;
export declare function isNewAttach(mark: Mark<unknown>, revision?: RevisionTag): boolean;
export declare function isNewAttachEffect(effect: MarkEffect, cellId: CellId | undefined, revision?: RevisionTag): boolean;
export declare function isInsert(mark: MarkEffect): mark is Insert;
export declare function isAttach(effect: MarkEffect): effect is Attach;
export declare function isReattach(mark: Mark<unknown>): boolean;
export declare function isReattachEffect(effect: MarkEffect, cellId: CellId | undefined): boolean;
export declare function isActiveReattach<T>(mark: Mark<T>): mark is CellMark<Insert, T> & {
    conflictsWith?: undefined;
};
export declare function areEqualCellIds(a: CellId | undefined, b: CellId | undefined): boolean;
export declare function getInputCellId(mark: Mark<unknown>, revision: RevisionTag | undefined, metadata: RevisionMetadataSource | undefined): CellId | undefined;
export declare function getOutputCellId(mark: Mark<unknown>, revision: RevisionTag | undefined, metadata: RevisionMetadataSource | undefined): CellId | undefined;
export declare function getDetachOutputId(mark: Detach, revision: RevisionTag | undefined, metadata: RevisionMetadataSource | undefined): ChangeAtomId;
/**
 * Preserves the semantics of the given `mark` but repackages it into a `DetachOfRemovedNodes` when possible.
 */
export declare function normalizeCellRename<TNodeChange>(mark: CellMark<AttachAndDetach, TNodeChange>, nodeChange?: TNodeChange): CellMark<AttachAndDetach | DetachOfRemovedNodes, TNodeChange>;
/**
 * Preserves the semantics of the given `mark` but repackages it into an `AttachAndDetach` mark if it is not already one.
 */
export declare function asAttachAndDetach<TNodeChange>(mark: CellMark<CellRename, TNodeChange>): CellMark<AttachAndDetach, TNodeChange>;
export declare function cloneMark<TMark extends Mark<TNodeChange>, TNodeChange>(mark: TMark): TMark;
export declare function cloneMarkEffect<TEffect extends MarkEffect>(effect: TEffect): TEffect;
export declare function cloneCellId(id: CellId): CellId;
/**
 * @param mark - The mark to get the length of.
 * @param ignorePairing - When true, the length of a paired mark (e.g. MoveIn/MoveOut) whose matching mark is not active
 * will be treated the same as if the matching mark were active.
 * @returns The number of nodes within the output context of the mark.
 */
export declare function getOutputLength(mark: Mark<unknown>, ignorePairing?: boolean): number;
/**
 * @param mark - The mark to get the length of.
 * @returns The number of nodes within the input context of the mark.
 */
export declare function getInputLength(mark: Mark<unknown>): number;
export declare function markEmptiesCells(mark: Mark<unknown>): boolean;
export declare function markFillsCells(mark: Mark<unknown>): boolean;
export declare function markHasCellEffect(mark: Mark<unknown>): boolean;
export declare function isAttachAndDetachEffect(effect: MarkEffect): effect is AttachAndDetach;
export declare function isDetachOfRemovedNodes(mark: Mark<unknown>): mark is CellMark<DetachOfRemovedNodes, unknown>;
export declare function isImpactfulCellRename(mark: Mark<unknown>, revision: RevisionTag | undefined, revisionMetadata: RevisionMetadataSource): mark is CellMark<CellRename, unknown>;
export declare function areInputCellsEmpty<T>(mark: Mark<T>): mark is EmptyInputCellMark<T>;
export declare function areOutputCellsEmpty(mark: Mark<unknown>): boolean;
/**
 * Creates a mark that is equivalent to the given `mark` but with effects removed if those have no impact in the input
 * context of that mark.
 *
 * @param mark - The mark to settle. Never mutated.
 * @param revision - The revision associated with the mark.
 * @param revisionMetadata - Metadata source for the revision associated with the mark.
 * @returns either the original mark or a shallow clone of it with effects stripped out.
 */
export declare function settleMark<TChildChange>(mark: Mark<TChildChange>, revision: RevisionTag | undefined, revisionMetadata: RevisionMetadataSource): Mark<TChildChange>;
/**
 * @returns true, iff the given `mark` would have impact on the field when applied.
 * Ignores the impact of nested changes.
 * CellRename effects are considered impactful if they actually change the ID of the cells.
 */
export declare function isImpactful(mark: Mark<unknown>, revision: RevisionTag | undefined, revisionMetadata: RevisionMetadataSource): boolean;
export declare function isNoopMark<T>(mark: Mark<T>): mark is CellMark<NoopMark, T>;
/**
 * @returns The number of cells in the range which come before the position described by `lineage`.
 */
export declare function getOffsetInCellRange(lineage: LineageEvent[] | undefined, revision: RevisionTag | undefined, id: ChangesetLocalId, count: number): number | undefined;
export declare function areOverlappingIdRanges(id1: ChangesetLocalId, count1: number, id2: ChangesetLocalId, count2: number): boolean;
export declare function compareCellsFromSameRevision(cell1: CellId, count1: number, cell2: CellId, count2: number): number | undefined;
export declare function isDetach(mark: MarkEffect | undefined): mark is Detach;
export declare function isDeleteMark<TNodeChange>(mark: Mark<TNodeChange> | undefined): mark is CellMark<Delete, TNodeChange>;
/**
 * Attempts to extend `lhs` to include the effects of `rhs`.
 * @param lhs - The mark to extend.
 * @param rhs - The effect so extend `rhs` with.
 * @returns `lhs` iff the function was able to mutate `lhs` to include the effects of `rhs`.
 * When `undefined` is returned, `lhs` is left untouched.
 */
export declare function tryMergeMarks<T>(lhs: Mark<T>, rhs: Readonly<Mark<T>>): Mark<T> | undefined;
/**
 * Keeps track of the different ways detached nodes may be referred to.
 * Allows updating changesets so they refer to a detached node by the details
 * of the last detach that affected them.
 *
 * WARNING: this code consumes O(N) space and time for marks that affect N nodes.
 * This is code is currently meant for usage in tests.
 * It should be tested and made more efficient before production use.
 */
export declare class DetachedNodeTracker {
    private nodes;
    private readonly equivalences;
    constructor();
    /**
     * Updates the internals of this instance to account for `change` having been applied.
     * @param change - The change that is being applied. Not mutated.
     * Must be applicable (i.e., `isApplicable(change)` must be true).
     */
    apply(change: TaggedChange<Changeset<unknown>>): void;
    /**
     * Checks whether the given `change` is applicable based on previous changes.
     * @param change - The change to verify the applicability of. Not mutated.
     * @returns false iff `change`'s description of detached nodes is inconsistent with that of changes applied
     * earlier. Returns true otherwise.
     */
    isApplicable(change: Changeset<unknown>): boolean;
    /**
     * Creates an updated representation of the given `change` so that it refers to detached nodes using the revision
     * that last detached them.
     * @param change - The change to update. Not mutated.
     * Must be applicable (i.e., `isApplicable(change)` must be true).
     * @param genId - An ID allocator that produces ID unique within this changeset.
     * @returns A change equivalent to `change` that refers to detached nodes using the revision that last detached
     * them. May reuse parts of the input `change` structure.
     */
    update<T>(change: TaggedChange<Changeset<T>>): TaggedChange<Changeset<T>>;
    private updateMark;
    private getUpdatedDetach;
}
/**
 * Checks whether `branch` changeset is consistent with a `target` changeset that is may be rebased over.
 *
 * WARNING: this code consumes O(N) space and time for marks that affect N nodes.
 * This is code is currently meant for usage in tests.
 * It should be tested and made more efficient before production use.
 *
 * @param branch - The changeset that would be rebased over `target`.
 * @param target - The changeset that `branch` would be rebased over.
 * @returns false iff `branch`'s description of detached nodes is inconsistent with that of `target`.
 * Returns true otherwise.
 */
export declare function areRebasable(branch: Changeset<unknown>, target: Changeset<unknown>): boolean;
/**
 * Checks whether sequential changesets are consistent.
 *
 * WARNING: this code consumes O(N) space and time for marks that affect N nodes.
 * This is code is currently meant for usage in tests.
 * It should be tested and made more efficient before production use.
 *
 * @param changes - The changesets that would be composed together.
 * @returns false iff the changesets in `changes` are inconsistent/incompatible in their description of detached nodes.
 * Returns true otherwise.
 */
export declare function areComposable(changes: TaggedChange<Changeset<unknown>>[]): boolean;
/**
 * @alpha
 */
export interface CrossFieldTable<T = unknown> extends CrossFieldManager<T> {
    srcQueries: CrossFieldQuerySet;
    dstQueries: CrossFieldQuerySet;
    isInvalidated: boolean;
    mapSrc: Map<RevisionTag | undefined, RangeMap<T>>;
    mapDst: Map<RevisionTag | undefined, RangeMap<T>>;
    reset: () => void;
}
/**
 * @alpha
 */
export declare function newCrossFieldTable<T = unknown>(): CrossFieldTable<T>;
/**
 * @alpha
 */
export declare function newMoveEffectTable<T>(): MoveEffectTable<T>;
/**
 * Splits the `mark` into two marks such that the first returned mark has length `length`.
 * @param mark - The mark to split.
 * @param revision - The revision of the changeset the mark is part of.
 * @param length - The desired length for the first of the two returned marks.
 * @param genId - An ID allocator
 * @param moveEffects - The table in which to record splitting of move marks
 * @param recordMoveEffect - Whether when splitting a move an entry should be added to `moveEffects` indicating that the mark should be split (in case we process this mark again).
 * An entry is always added to `moveEffects` indicating that the opposite end of the move should be split.
 * @returns A pair of marks equivalent to the original `mark`
 * such that the first returned mark has input length `length`.
 */
export declare function splitMark<T, TMark extends Mark<T>>(mark: TMark, length: number): [TMark, TMark];
/**
 * @returns -1 if the lineage indicates that cell1 is earlier in the field than cell2.
 * Returns 1 if cell2 is earlier in the field.
 * Returns 0 if the order cannot be determined from the lineage.
 */
export declare function compareLineages(cell1: CellId, cell2: CellId): number;
export declare function extractMarkEffect<TEffect extends MarkEffect>(mark: CellMark<TEffect, unknown>): TEffect;
export declare function omitMarkEffect<TChildChange>(mark: CellMark<unknown, TChildChange>): CellMark<NoopMark, TChildChange>;
export declare function withNodeChange<TMark extends CellMark<TKind, TNodeChange>, TKind extends MarkEffect, TNodeChange>(mark: TMark, changes: TNodeChange | undefined): TMark;
export declare function withRevision<TMark extends Mark<unknown>>(mark: TMark, revision: RevisionTag | undefined): TMark;
export declare function addRevision(effect: MarkEffect, revision: RevisionTag | undefined): void;
export declare function getMarkMoveId(mark: Mark<unknown>): MoveId | undefined;
export declare function getEndpoint(effect: MoveMarkEffect, revision: RevisionTag | undefined): ChangeAtomId;
//# sourceMappingURL=utils.d.ts.map