/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { type CodecWriteOptions, type ICodecFamily } from "../../codec/index.js";
import { type ChangeEncodingContext, type ChangeFamily, type ChangeFamilyEditor, type ChangeRebaser, type ChangesetLocalId, type DeltaDetachedNodeId, type DeltaRoot, EditBuilder, type FieldKindIdentifier, type FieldUpPath, type RevisionInfo, type RevisionMetadataSource, type RevisionTag, type TaggedChange, type UpPath, type RevisionReplacer } from "../../core/index.js";
import { type ChangeAtomIdBTree } from "../changeAtomIdBTree.js";
import type { TreeChunk } from "../chunked-forest/index.js";
import { type FieldChangeHandler, type RebaseRevisionMetadata } from "./fieldChangeHandler.js";
import type { FlexFieldKind } from "./fieldKind.js";
import { type FieldChangeset, type FieldId, type ModularChangeset, type NodeId } from "./modularChangeTypes.js";
/**
 * Implementation of ChangeFamily which delegates work in a given field to the appropriate FieldKind
 * as determined by the schema.
 */
export declare class ModularChangeFamily implements ChangeFamily<ModularEditBuilder, ModularChangeset>, ChangeRebaser<ModularChangeset> {
    readonly codecs: ICodecFamily<ModularChangeset, ChangeEncodingContext>;
    readonly codecOptions: CodecWriteOptions;
    static readonly emptyChange: ModularChangeset;
    readonly fieldKinds: ReadonlyMap<FieldKindIdentifier, FlexFieldKind>;
    constructor(fieldKinds: ReadonlyMap<FieldKindIdentifier, FlexFieldKind>, codecs: ICodecFamily<ModularChangeset, ChangeEncodingContext>, codecOptions: CodecWriteOptions);
    get rebaser(): ChangeRebaser<ModularChangeset>;
    /**
     * Produces an equivalent list of `FieldChangeset`s that all target the same {@link FlexFieldKind}.
     * @param changes - The list of `FieldChange`s whose `FieldChangeset`s needs to be normalized.
     * @returns An object that contains both the equivalent list of `FieldChangeset`s that all
     * target the same {@link FlexFieldKind}, and the `FieldKind` that they target.
     * The returned `FieldChangeset`s may be a shallow copy of the input `FieldChange`s.
     */
    private normalizeFieldChanges;
    private normalizeFieldChange;
    compose(changes: TaggedChange<ModularChangeset>[]): ModularChangeset;
    private composePair;
    private composeAllFields;
    private composeInvalidatedField;
    /**
     * Updates everything in the composed output which may no longer be valid.
     * This could be due to
     * - discovering that two node changesets refer to the same node (`nodeIdsToCompose`)
     * - a previously composed field being invalidated by a cross field effect (`invalidatedFields`)
     * - a field which was copied directly from an input changeset being invalidated by a cross field effect
     * (`affectedBaseFields` and `affectedNewFields`)
     *
     * Updating an element may invalidate further elements. This function runs until there is no more invalidation.
     */
    private composeInvalidatedElements;
    private processInvalidatedCompositions;
    /**
     * Ensures that each field in `affectedFields` has been updated in the composition output.
     * Any field which has already been composed is ignored.
     * All other fields are optimistically assumed to not have any changes in the other input changeset.
     *
     * @param change - The changeset which contains the affected fields.
     * This should be one of the two changesets being composed.
     * @param areBaseFields - Whether the affected fields are part of the base changeset.
     * If not, they are assumed to be part of the new changeset.
     * @param affectedFields - The set of fields to process.
     */
    private composeAffectedFields;
    private composeFieldMaps;
    /**
     * Returns the composition of the two input fields.
     *
     * Any nodes in this field which were modified by both changesets
     * will be added to `crossFieldTable.pendingCompositions.nodeIdsToCompose`.
     *
     * Any fields which had cross-field information sent to them as part of this field composition
     * will be added to either `affectedBaseFields` or `affectedNewFields` in `crossFieldTable.pendingCompositions`.
     *
     * Any composed `FieldChange` which is invalidated by new cross-field information will be added to `crossFieldTable.invalidatedFields`.
     */
    private composeFieldChanges;
    private composeNodesById;
    private composeNodeChanges;
    /**
     * @param change - The change to invert.
     * @param isRollback - Whether the inverted change is meant to rollback a change on a branch as is the case when
     * performing a sandwich rebase.
     * @param revisionForInvert - The revision for the invert changeset.
     */
    invert(change: TaggedChange<ModularChangeset>, isRollback: boolean, revisionForInvert: RevisionTag): ModularChangeset;
    private invertFieldMap;
    private invertNodeChange;
    rebase(taggedChange: TaggedChange<ModularChangeset>, potentiallyConflictedOver: TaggedChange<ModularChangeset>, revisionMetadata: RevisionMetadataSource, ignoreNoChangeViolation?: boolean): ModularChangeset;
    private rebaseIntersectingFields;
    private rebaseFieldsWithoutNewChanges;
    private rebaseInvalidatedElements;
    private rebaseInvalidatedFields;
    private rebaseFieldsWithUnattachedChild;
    private rebaseInvalidatedField;
    private attachRebasedField;
    private attachRebasedNode;
    private rebaseFieldMap;
    private rebaseNodeChange;
    private updateConstraintsForFields;
    private updateConstraintsForNode;
    private pruneFieldMap;
    private pruneNodeChange;
    getRevisions(change: ModularChangeset): Set<RevisionTag | undefined>;
    changeRevision(change: ModularChangeset, replacer: RevisionReplacer): ModularChangeset;
    private replaceNodeChangesetRevisions;
    private replaceFieldMapRevisions;
    private makeCrossFieldKeyTable;
    private populateCrossFieldKeyTableForFieldMap;
    buildEditor(mintRevisionTag: () => RevisionTag, changeReceiver: (change: TaggedChange<ModularChangeset>) => void): ModularEditBuilder;
    private createEmptyFieldChange;
    validateChangeset(change: ModularChangeset): void;
    /**
     * Asserts that each child and cross field key in each field has a correct entry in
     * `nodeToParent` or `crossFieldKeyTable`.
     * @returns the number of children found.
     */
    private validateFieldChanges;
    private getEffectiveChange;
    /**
     * Returns a copy of the given changeset with the same declarations (e.g., new cells) but no actual changes.
     */
    private muteChange;
    private muteNodeChange;
    private muteFieldChanges;
    private muteFieldChange;
}
/**
 * Returns the set of removed roots that should be in memory for the given change to be applied.
 * A removed root is relevant if any of the following is true:
 * - It is being inserted
 * - It is being restored
 * - It is being edited
 * - The ID it is associated with is being changed
 *
 * May be conservative by returning more removed roots than strictly necessary.
 *
 * Will never return IDs for non-root trees, even if they are removed.
 *
 * @param change - The change to be applied.
 * @param fieldKinds - The field kinds to delegate to.
 */
export declare function relevantRemovedRoots(change: ModularChangeset, fieldKinds: ReadonlyMap<FieldKindIdentifier, FlexFieldKind>): Iterable<DeltaDetachedNodeId>;
/**
 * Adds any refreshers missing from the provided change that are relevant to the change and
 * removes any refreshers from the provided change that are not relevant to the change.
 *
 * @param change - The change that possibly has missing or superfluous refreshers. Not mutated by this function.
 * @param getDetachedNode - The function to retrieve a tree chunk from the corresponding detached node id.
 * @param removedRoots - The set of removed roots that should be in memory for the given change to be applied.
 * Can be retrieved by calling {@link relevantRemovedRoots}.
 * @param requireRefreshers - when true, this function enforces that all relevant removed roots have a
 * corresponding build or refresher.
 */
export declare function updateRefreshers(change: ModularChangeset, getDetachedNode: (id: DeltaDetachedNodeId) => TreeChunk | undefined, removedRoots: Iterable<DeltaDetachedNodeId>, requireRefreshers?: boolean): ModularChangeset;
/**
 * Converts a change into the delta format.
 *
 * @param change - The change to convert into a delta.
 * @param fieldKinds - The field kinds to delegate to.
 */
export declare function intoDelta(taggedChange: TaggedChange<ModularChangeset>, fieldKinds: ReadonlyMap<FieldKindIdentifier, FlexFieldKind>): DeltaRoot;
/**
 * @param revInfos - This should describe the revision being rebased and all revisions in the rebase path,
 * even if not part of the current base changeset.
 * For example, when rebasing change B from a local branch [A, B, C] over a branch [X, Y], the `revInfos` must include
 * the changes [A⁻¹ X, Y, A, B] for each rebase step of B.
 * @param revisionToRebase - The revision of the changeset which is being rebased.
 * @param baseRevisions - The set of revisions in the changeset being rebased over.
 * For example, when rebasing change B from a local branch [A, B, C] over a branch [X, Y], the `baseRevisions` must include
 * revisions [A⁻¹ X, Y, A] if rebasing over the composition of all those changes, or
 * revision [A⁻¹] for the first rebase, then [X], etc. if rebasing over edits individually.
 * @returns RebaseRevisionMetadata to be passed to `FieldChangeRebaser.rebase`*
 */
export declare function rebaseRevisionMetadataFromInfo(revInfos: readonly RevisionInfo[], revisionToRebase: RevisionTag | undefined, baseRevisions: (RevisionTag | undefined)[]): RebaseRevisionMetadata;
export declare function getFieldKind(fieldKinds: ReadonlyMap<FieldKindIdentifier, FlexFieldKind>, kind: FieldKindIdentifier): FlexFieldKind;
export declare function getChangeHandler(fieldKinds: ReadonlyMap<FieldKindIdentifier, FlexFieldKind>, kind: FieldKindIdentifier): FieldChangeHandler<unknown>;
export declare class ModularEditBuilder extends EditBuilder<ModularChangeset> {
    private readonly fieldKinds;
    private transactionDepth;
    private idAllocator;
    private readonly codecOptions;
    constructor(family: ChangeFamily<ChangeFamilyEditor, ModularChangeset>, fieldKinds: ReadonlyMap<FieldKindIdentifier, FlexFieldKind>, changeReceiver: (change: TaggedChange<ModularChangeset>) => void, codecOptions: CodecWriteOptions);
    enterTransaction(): void;
    exitTransaction(): void;
    /**
     * Builds a new tree to use in an edit.
     *
     * @param firstId - The ID to associate with the first node
     * @param content - The node(s) to build.
     * @param revision - The revision to use for the build.
     * @returns A description of the edit that can be passed to `submitChanges`.
     * The returned object may contain an owning reference to the given TreeChunk.
     */
    buildTrees(firstId: ChangesetLocalId, content: TreeChunk, revision: RevisionTag): GlobalEditDescription;
    /**
     * Adds a change to the edit builder
     * @param field - the field which is being edited
     * @param fieldKind - the kind of the field
     * @param change - the change to the field
     * @param revision - the revision of the change
     */
    submitChange(field: FieldUpPath, fieldKind: FieldKindIdentifier, change: FieldChangeset, revision: RevisionTag): void;
    submitChanges(changes: EditDescription[], revision: RevisionTag): void;
    buildChanges(changes: EditDescription[]): ModularChangeset;
    generateId(count?: number): ChangesetLocalId;
    addNodeExistsConstraint(path: UpPath, revision: RevisionTag): void;
    addNodeExistsConstraintOnRevert(path: UpPath, revision: RevisionTag): void;
    addNoChangeConstraint(revision: RevisionTag): void;
    addNoChangeConstraintOnRevert(revision: RevisionTag): void;
}
export interface FieldEditDescription {
    type: "field";
    field: FieldUpPath;
    fieldKind: FieldKindIdentifier;
    change: FieldChangeset;
    revision: RevisionTag;
}
export interface GlobalEditDescription {
    type: "global";
    revision: RevisionTag;
    builds?: ChangeAtomIdBTree<TreeChunk>;
}
export type EditDescription = FieldEditDescription | GlobalEditDescription;
export declare function getParentFieldId(changeset: ModularChangeset, nodeId: NodeId): FieldId;
export declare function normalizeFieldId(fieldId: FieldId, nodeAliases: ChangeAtomIdBTree<NodeId>): FieldId;
//# sourceMappingURL=modularChangeFamily.d.ts.map