/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { type TelemetryEventBatcher } from "@fluidframework/telemetry-utils/internal";
import { type BranchRebaseResult, type ChangeFamily, type ChangeFamilyEditor, CommitKind, type CommitMetadata, type GraphCommit, type RevisionTag, type TaggedChange, type RebaseStatsWithDuration } from "../core/index.js";
import { EventEmitter, type Listenable } from "../events/index.js";
/**
 * Describes a change to a `SharedTreeBranch`. Various operations can mutate the head of the branch;
 * this change format describes each in terms of the "removed commits" (all commits which were present
 * on the branch before the operation but are no longer present after) and the "new commits" (all
 * commits which are present on the branch after the operation that were not present before). Each of
 * the following event types also provides a `change` which contains the net change to the branch
 * (or is undefined if there was no net change):
 * * Append - when one or more commits are appended to the head of the branch, for example via
 * a change applied by the branch's editor, or as a result of merging another branch into this one
 * * Remove - when one or more commits are removed from the head of the branch. This occurs
 * when a transaction is aborted and all commits pending in that transaction are removed.
 * * Replace - when an operation simultaneously removes and appends commits. For example, when this
 * branch is rebased and some commits are removed and replaced with rebased versions, or when a
 * transaction completes and all pending commits are replaced with a single squash commit.
 */
export type SharedTreeBranchChange<TChange> = {
    type: "append";
    change: TaggedChange<TChange>;
    newCommits: readonly GraphCommit<TChange>[];
} | {
    type: "remove";
    change: TaggedChange<TChange> | undefined;
    removedCommits: readonly GraphCommit<TChange>[];
} | {
    type: "replace";
    change: TaggedChange<TChange> | undefined;
    removedCommits: readonly GraphCommit<TChange>[];
    newCommits: readonly GraphCommit<TChange>[];
};
/**
 * Returns the operation that caused the given {@link SharedTreeBranchChange}.
 */
export declare function getChangeReplaceType(change: SharedTreeBranchChange<unknown> & {
    type: "replace";
}): "transactionCommit" | "rebase";
/**
 * The events emitted by a `SharedTreeBranch`
 */
export interface SharedTreeBranchEvents<TEditor extends ChangeFamilyEditor, TChange> extends BranchTrimmingEvents {
    /**
     * Fired just before the head of this branch changes.
     * @param change - the change to this branch's state and commits
     */
    beforeChange(change: SharedTreeBranchChange<TChange>): void;
    /**
     * Fired just after the head of this branch changes.
     * @param change - the change to this branch's state and commits
     */
    afterChange(change: SharedTreeBranchChange<TChange>): void;
    /**
     * {@inheritdoc TreeViewEvents.commitApplied}
     */
    commitApplied(data: CommitMetadata): void;
    /**
     * Fired when this branch forks
     * @param fork - the new branch that forked off of this branch
     */
    fork(fork: SharedTreeBranch<TEditor, TChange>): void;
    /**
     * Fired after this branch is disposed
     */
    dispose(): void;
    /**
     * Fired after a new transaction is started.
     * @param isOuterTransaction - true iff the transaction being started is the outermost transaction
     * as opposed to a nested transaction.
     */
    transactionStarted(isOuterTransaction: boolean): void;
    /**
     * Fired after the current transaction is aborted.
     * @param isOuterTransaction - true iff the transaction being aborted is the outermost transaction
     * as opposed to a nested transaction.
     */
    transactionAborted(isOuterTransaction: boolean): void;
    /**
     * Fired after the current transaction is committed.
     * @param isOuterTransaction - true iff the transaction being committed is the outermost transaction
     * as opposed to a nested transaction.
     */
    transactionCommitted(isOuterTransaction: boolean): void;
}
/**
 * Events related to branch trimming.
 *
 * @remarks
 * Trimming is a very specific kind of mutation which is the only allowed mutations to branches.
 * References to commits from other commits are removed so that the commit objects can be GC'd by the JS engine.
 * This happens by changing a commit's parent property to undefined, which drops all commits that are in its "ancestry".
 * It is done as a performance optimization when it is determined that commits are no longer needed for future computation.
 */
export interface BranchTrimmingEvents {
    /**
     * Fired when some contiguous range of commits beginning with the "global tail" of this branch are trimmed from the branch.
     * This happens by deleting the parent pointer to the last commit in that range. This event can be fired at any time.
     */
    ancestryTrimmed(trimmedRevisions: RevisionTag[]): void;
}
/**
 * A branch of changes that can be applied to a SharedTree.
 */
export declare class SharedTreeBranch<TEditor extends ChangeFamilyEditor, TChange> extends EventEmitter<SharedTreeBranchEvents<TEditor, TChange>> {
    private head;
    readonly changeFamily: ChangeFamily<TEditor, TChange>;
    private readonly mintRevisionTag;
    private readonly branchTrimmer?;
    private readonly telemetryEventBatcher?;
    readonly editor: TEditor;
    private readonly transactions;
    /**
     * After pushing a starting revision to the transaction stack, this branch might be rebased
     * over commits which are children of that starting revision. When the transaction is committed,
     * those rebased-over commits should not be included in the transaction's squash commit, even though
     * they exist between the starting revision and the final commit within the transaction.
     *
     * Whenever `rebaseOnto` is called during a transaction, this map is augmented with an entry from the
     * original merge-base to the new merge-base.
     *
     * This state need only be retained for the lifetime of the transaction.
     *
     * TODO: This strategy might need to be revisited when adding better support for async transactions.
     * Since:
     *
     * 1. Transactionality is guaranteed primarily by squashing at commit time
     * 2. Branches may be rebased with an ongoing transaction
     *
     * a rebase operation might invalidate only a portion of a transaction's commits, thus defeating the
     * purpose of transactionality.
     *
     * AB#6483 and children items track this work.
     */
    private readonly initialTransactionRevToRebasedRev;
    private disposed;
    private readonly unsubscribeBranchTrimmer?;
    /**
     * Construct a new branch.
     * @param head - the head of the branch
     * @param changeFamily - determines the set of changes that this branch can commit
     * @param branchTrimmer - an optional event emitter that informs the branch it has been trimmed. If this is not supplied, then the branch must
     * never be trimmed. See {@link BranchTrimmingEvents} for details on trimming.
     */
    constructor(head: GraphCommit<TChange>, changeFamily: ChangeFamily<TEditor, TChange>, mintRevisionTag: () => RevisionTag, branchTrimmer?: Listenable<BranchTrimmingEvents> | undefined, telemetryEventBatcher?: TelemetryEventBatcher<keyof RebaseStatsWithDuration> | undefined);
    /**
     * Sets the head of this branch. Emits no change events.
     */
    setHead(head: GraphCommit<TChange>): void;
    /**
     * Apply a change to this branch.
     * @param change - the change to apply
     * @param revision - the revision of the new head commit of the branch that contains `change`
     * @param changeKind - the kind of change to apply
     * @returns the change that was applied and the new head commit of the branch
     */
    apply(change: TChange, revision: RevisionTag, changeKind?: CommitKind): [change: TChange, newCommit: GraphCommit<TChange>];
    /**
     * @returns the commit at the head of this branch.
     */
    getHead(): GraphCommit<TChange>;
    /**
     * Begin a transaction on this branch. If the transaction is committed via {@link commitTransaction},
     * all commits made since this call will be squashed into a single head commit.
     */
    startTransaction(): void;
    /**
     * Commit the current transaction. There must be a transaction in progress that was begun via {@link startTransaction}.
     * If there are commits in the current transaction, they will be squashed into a new single head commit.
     * @returns the commits that were squashed and the new squash commit if a squash occurred, otherwise `undefined`.
     * @remarks If the transaction had no changes applied during its lifetime, then no squash occurs (i.e. this method is a no-op).
     * Even if the transaction contained only one change, it will still be replaced with an (equivalent) squash change.
     */
    commitTransaction(): [squashedCommits: GraphCommit<TChange>[], newCommit: GraphCommit<TChange>] | undefined;
    /**
     * Cancel the current transaction. There must be a transaction in progress that was begun via
     * {@link startTransaction}. All commits made during the transaction will be removed.
     * @returns the change to this branch resulting in the removal of the commits, and a list of the
     * commits that were removed.
     */
    abortTransaction(): [
        change: TChange | undefined,
        abortedCommits: GraphCommit<TChange>[]
    ];
    /**
     * True iff this branch is in the middle of a transaction that was begin via {@link startTransaction}
     */
    isTransacting(): boolean;
    private popTransaction;
    /**
     * Spawn a new branch that is based off of the current state of this branch.
     * Changes made to the new branch will not be applied to this branch until the new branch is merged back in.
     *
     * @remarks Forks created during a transaction will be disposed when the transaction ends.
     */
    fork(): SharedTreeBranch<TEditor, TChange>;
    /**
     * Rebase the changes that have been applied to this branch over divergent changes in the given branch.
     * After this operation completes, this branch will be based off of `branch`.
     *
     * @param branch - the branch to rebase onto
     * @param upTo - the furthest commit on `branch` over which to rebase (inclusive). Defaults to the head commit of `branch`.
     * @returns the result of the rebase or undefined if nothing changed
     */
    rebaseOnto(branch: SharedTreeBranch<TEditor, TChange>, upTo?: GraphCommit<TChange>): BranchRebaseResult<TChange> | undefined;
    /**
     * Apply all the divergent changes on the given branch to this branch.
     *
     * @param branch - the branch to merge into this branch
     * @returns the net change to this branch and the commits that were added to this branch by the merge,
     * or undefined if nothing changed
     */
    merge(branch: SharedTreeBranch<TEditor, TChange>): [change: TChange, newCommits: GraphCommit<TChange>[]] | undefined;
    /** Rebase `branchHead` onto `onto`, but return undefined if nothing changed */
    private rebaseBranch;
    /**
     * Dispose this branch, freezing its state.
     *
     * @remarks
     * Attempts to further mutate the branch will error.
     * Any transactions in progress will be aborted.
     * Calling dispose more than once has no effect.
     */
    dispose(): void;
    private assertNotDisposed;
}
/**
 * Registers an event listener that fires when the given forkable object forks.
 * The listener will also fire when any of those forks fork, and when those forks of forks fork, and so on.
 * @param forkable - an object that emits an event when it is forked
 * @param onFork - the fork event listener
 * @returns a function which when called will deregister all registrations (including transitive) created by this function.
 * The deregister function has undefined behavior if called more than once.
 */
export declare function onForkTransitive<T extends Listenable<{
    fork: (t: T) => void;
}>>(forkable: T, onFork: (fork: T) => void): () => void;
//# sourceMappingURL=branch.d.ts.map