/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { IChannelAttributes, IChannelFactory, IChannelServices, IChannelStorageService, IFluidDataStoreRuntime } from "@fluidframework/datastore-definitions";
import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
import { ISharedObject } from "@fluidframework/shared-object-base";
import { IForestSubscription, StoredSchemaRepository, InMemoryStoredSchemaRepository, Anchor, AnchorLocator, AnchorNode, IEditableForest, AnchorSetRootEvents, GlobalFieldKey, GraphCommit, UndoRedoManager } from "../core";
import { SharedTreeBranch, SharedTreeCore } from "../shared-tree-core";
import { EditableTreeContext, DefaultChangeFamily, DefaultEditBuilder, UnwrappedEditableField, SchemaEditor, DefaultChangeset, ContextuallyTypedNodeData, IDefaultEditBuilder, IdentifierIndex, EditableTree, Identifier, SchemaAware, ModularChangeset } from "../feature-libraries";
import { IEmitter, ISubscribable } from "../events";
import { JsonCompatibleReadOnly, TransactionResult } from "../util";
import { SchematizeConfiguration } from "./schematizedTree";
/**
 * Events for {@link ISharedTreeView}.
 * @alpha
 */
export interface ViewEvents {
    /**
     * A batch of changes has finished processing and the view is in a consistent state.
     * It is once again safe to access the EditableTree, Forest and AnchorSet.
     *
     * @remarks
     * This is mainly useful for knowing when to do followup work scheduled during events from Anchors.
     */
    afterBatch(): void;
}
/**
 * Provides a means for interacting with a SharedTree.
 * This includes reading data from the tree and running transactions to mutate the tree.
 * @alpha
 */
export interface ISharedTreeView extends AnchorLocator {
    /**
     * Gets or sets the root field of the tree.
     *
     * See {@link EditableTreeContext.unwrappedRoot} on how its setter works.
     *
     * Currently this editable tree's fields do not update on edits,
     * so holding onto this root object across edits will only work if its an unwrapped node.
     * TODO: Fix this issue.
     *
     * Currently any access to this view of the tree may allocate cursors and thus require
     * `context.prepareForEdit()` before editing can occur.
     */
    get root(): UnwrappedEditableField;
    set root(data: ContextuallyTypedNodeData | undefined);
    /**
     * Context for controlling the EditableTree nodes produced from {@link ISharedTreeView.root}.
     *
     * TODO: Exposing access to this should be unneeded once editing APIs are finished.
     */
    readonly context: EditableTreeContext;
    /**
     * Read and Write access for schema stored in the document.
     *
     * These APIs are temporary and will be replaced with different abstractions (View Schema based) in a different place later.
     *
     * TODO:
     * Editing of this should be moved into transactions with the rest of tree editing to they can be intermixed.
     * This will be done after the relations between views, branches and Indexes are figured out.
     *
     * TODO:
     * Public APIs for dealing with schema should be in terms of View Schema, and schema update policies.
     * The actual stored schema should be hidden (or ar least not be the most prominent way to interact with schema).
     *
     * TODO:
     * Something should ensure the document contents are always in schema.
     */
    readonly storedSchema: StoredSchemaRepository;
    /**
     * Current contents.
     * Updated by edits (local and remote).
     * Use `editor` to create a local edit.
     */
    readonly forest: IForestSubscription;
    /**
     * Used to edit the state of the tree. Edits will be immediately applied locally to the tree.
     * If there is no transaction currently ongoing, then the edits will be submitted to Fluid immediately as well.
     */
    readonly editor: IDefaultEditBuilder;
    /**
     * Undoes the last completed transaction made by the client.
     * It is invalid to call it while a transaction is open (this will be supported in the future).
     */
    undo(): void;
    /**
     * Redoes the last completed undo made by the client.
     * It is invalid to call it while a transaction is open (this will be supported in the future).
     */
    redo(): void;
    /**
     * An collection of functions for managing transactions.
     * Transactions allow edits to be batched into atomic units.
     * Edits made during a transaction will update the local state of the tree immediately, but will be squashed into a single edit when the transaction is committed.
     * If the transaction is aborted, the local state will be reset to what it was before the transaction began.
     * Transactions may nest, meaning that a transaction may be started while a transaction is already ongoing.
     *
     * To avoid updating observers of the view state with intermediate results during a transaction,
     * use {@link ISharedTreeView#fork} and {@link ISharedTreeFork#merge}.
     */
    readonly transaction: {
        /**
         * Start a new transaction.
         * If a transaction is already in progress when this new transaction starts, then this transaction will be "nested" inside of it,
         * i.e. the outer transaction will still be in progress after this new transaction is committed or aborted.
         */
        start(): void;
        /**
         * Close this transaction by squashing its edits and committing them as a single edit.
         * If this is the root view and there are no ongoing transactions remaining, the squashed edit will be submitted to Fluid.
         */
        commit(): TransactionResult.Commit;
        /**
         * Close this transaction and revert the state of the tree to what it was before this transaction began.
         */
        abort(): TransactionResult.Abort;
        /**
         * True if there is at least one transaction currently in progress on this view, otherwise false.
         */
        inProgress(): boolean;
    };
    /**
     * Spawn a new view which is based off of the current state of this view.
     * Any mutations of the new view will not apply to this view until the new view is merged back into this view via `merge()`.
     */
    fork(): ISharedTreeFork;
    /**
     * Apply all the new changes on the given view to this view.
     * @param view - a view which was created by a call to `fork()`. It is not modified by this operation.
     */
    merge(view: ISharedTreeFork): void;
    /**
     * Events about this view.
     */
    readonly events: ISubscribable<ViewEvents>;
    /**
     * Events about the root of the tree in this view.
     */
    readonly rootEvents: ISubscribable<AnchorSetRootEvents>;
    /**
     * A map of nodes that have been recorded by the identifier index.
     */
    readonly identifiedNodes: ReadonlyMap<Identifier, EditableTree>;
    /**
     * Takes in a tree and returns a view of it that conforms to the view schema.
     * The returned view referees to and can edit the provided one: it is not a fork of it.
     * Updates the stored schema in the tree to match the provided one if requested by config and compatible.
     *
     * If the tree is uninitialized (has no nodes or schema at all),
     * it is initialized to the config's initial tree and the provided schema are stored.
     * This is done even if `AllowedUpdateType.None`.
     *
     * @remarks
     * Doing initialization here, regardless of `AllowedUpdateType`, allows a small API that is hard to use incorrectly.
     * Other approach tend to have leave easy to make mistakes.
     * For example, having a separate initialization function means apps can forget to call it, making an app that can only open existing document,
     * or call it unconditionally leaving an app that can only create new documents.
     * It also would require the schema to be passed into to separate places and could cause issues if they didn't match.
     * Since the initialization function couldn't return a typed tree, the type checking wouldn't help catch that.
     * Also, if an app manages to create a document, but the initialization fails to get persisted, an app that only calls the initialization function
     * on the create code-path (for example how a schematized factory might do it),
     * would leave the document in an unusable state which could not be repaired when it is reopened (by the same or other clients).
     * Additionally, once out of schema content adapters are properly supported (with lazy document updates),
     * this initialization could become just another out of schema content adapter: at tha point it clearly belong here in schematize.
     *
     * TODO:
     * - Implement schema-aware API for return type.
     * - Support adapters for handling out of schema data.
     */
    schematize<TSchema extends SchemaAware.TypedSchemaData>(config: SchematizeConfiguration<TSchema>): ISharedTreeView;
}
/**
 * An `ISharedTreeView` which has been forked from a pre-existing view.
 * @alpha
 */
export interface ISharedTreeFork extends ISharedTreeView {
    /**
     * Rebase the changes that have been applied to this view over all the new changes in the given view.
     * @param view - Either the root view or a view that was created by a call to `fork()`. It is not modified by this operation.
     */
    rebaseOnto(view: ISharedTreeView): void;
    /**
     * Dispose this fork, freezing its state and allowing the SharedTree to release resources required by it.
     * Attempts to further mutate or dispose this view will error.
     */
    dispose(): void;
}
/**
 * Collaboratively editable tree distributed data-structure,
 * powered by {@link @fluidframework/shared-object-base#ISharedObject}.
 *
 * See [the README](../../README.md) for details.
 * @alpha
 */
export interface ISharedTree extends ISharedObject, ISharedTreeView {
}
/**
 * The key for the special identifier field, which allows nodes to be given identifiers that can be used
 * to find the nodes via the identifier index
 * @alpha
 */
export declare const identifierKey: GlobalFieldKey;
/**
 * The global field key symbol that corresponds to {@link identifierKey}
 * @alpha
 */
export declare const identifierKeySymbol: import("../core").GlobalFieldKeySymbol;
/**
 * Shared tree, configured with a good set of indexes and field kinds which will maintain compatibility over time.
 * TODO: node identifier index.
 *
 * TODO: detail compatibility requirements.
 */
export declare class SharedTree extends SharedTreeCore<DefaultEditBuilder, DefaultChangeset> implements ISharedTree {
    readonly context: EditableTreeContext;
    readonly forest: IEditableForest;
    readonly storedSchema: SchemaEditor<InMemoryStoredSchemaRepository>;
    readonly identifiedNodes: IdentifierIndex<typeof identifierKey>;
    readonly transaction: ISharedTreeView["transaction"];
    readonly events: ISubscribable<ViewEvents> & IEmitter<ViewEvents>;
    get rootEvents(): ISubscribable<AnchorSetRootEvents>;
    constructor(id: string, runtime: IFluidDataStoreRuntime, attributes: IChannelAttributes, telemetryContextPrefix: string);
    schematize<TSchema extends SchemaAware.TypedSchemaData>(config: SchematizeConfiguration<TSchema>): ISharedTreeView;
    locate(anchor: Anchor): AnchorNode | undefined;
    get root(): UnwrappedEditableField;
    set root(data: ContextuallyTypedNodeData | undefined);
    get undoRedoManager(): UndoRedoManager<DefaultChangeset, DefaultEditBuilder>;
    fork(): ISharedTreeFork;
    merge(view: ISharedTreeFork): void;
    getLocalBranchHead(): GraphCommit<ModularChangeset>;
    /**
     * TODO: Shared tree needs a pattern for handling non-changeset operations.
     * Whatever pattern is adopted should probably also handle multiple versions of changeset operations.
     * A single top level enum listing all ops (including their different versions),
     * with at least fine grained enough detail to direct them to the correct subsystem would be a good approach.
     * The current use-case (with an op applying to a specific index) is a temporary hack,
     * and its not clear how it would fit into such a system if implemented in shared-tree-core:
     * maybe op dispatch is part of the shared-tree level?
     */
    protected processCore(message: ISequencedDocumentMessage, local: boolean, localOpMetadata: unknown): void;
    protected reSubmitCore(content: JsonCompatibleReadOnly, localOpMetadata: unknown): void;
    protected loadCore(services: IChannelStorageService): Promise<void>;
    /** Finish a batch (see {@link ViewEvents}) */
    private finishBatch;
}
/**
 * A channel factory that creates {@link ISharedTree}s.
 * @alpha
 */
export declare class SharedTreeFactory implements IChannelFactory {
    type: string;
    attributes: IChannelAttributes;
    load(runtime: IFluidDataStoreRuntime, id: string, services: IChannelServices, channelAttributes: Readonly<IChannelAttributes>): Promise<ISharedTree>;
    create(runtime: IFluidDataStoreRuntime, id: string): ISharedTree;
}
export declare class SharedTreeFork implements ISharedTreeFork {
    readonly branch: SharedTreeBranch<DefaultEditBuilder, DefaultChangeset>;
    readonly changeFamily: DefaultChangeFamily;
    readonly storedSchema: InMemoryStoredSchemaRepository;
    readonly forest: IEditableForest;
    readonly context: EditableTreeContext;
    readonly identifiedNodes: IdentifierIndex<typeof identifierKey>;
    readonly events: ISubscribable<ViewEvents> & IEmitter<ViewEvents> & import("../events").HasListeners<ViewEvents>;
    constructor(branch: SharedTreeBranch<DefaultEditBuilder, DefaultChangeset>, changeFamily: DefaultChangeFamily, storedSchema: InMemoryStoredSchemaRepository, forest: IEditableForest, context: EditableTreeContext, identifiedNodes: IdentifierIndex<typeof identifierKey>);
    get rootEvents(): ISubscribable<AnchorSetRootEvents>;
    get editor(): DefaultEditBuilder;
    readonly transaction: ISharedTreeView["transaction"];
    undo(): void;
    redo(): void;
    schematize<TSchema extends SchemaAware.TypedSchemaData>(config: SchematizeConfiguration<TSchema>): ISharedTreeView;
    locate(anchor: Anchor): AnchorNode | undefined;
    fork(): ISharedTreeFork;
    rebaseOnto(view: ISharedTreeView): void;
    merge(view: ISharedTreeFork): void;
    get root(): UnwrappedEditableField;
    set root(data: ContextuallyTypedNodeData | undefined);
    dispose(): void;
}
/**
 * Run a synchronous transaction on the given shared tree view.
 * This is a convenience helper around the {@link SharedTreeFork#transaction} APIs.
 * @param view - the view on which to run the transaction
 * @param transaction - the transaction function. This will be executed immediately. It is passed `view` as an argument for convenience.
 * If this function returns an `Abort` result then the transaction will be aborted. Otherwise, it will be committed.
 * @returns whether or not the transaction was committed or aborted
 * @alpha
 */
export declare function runSynchronous(view: ISharedTreeView, transaction: (view: ISharedTreeView) => TransactionResult | void): TransactionResult;
//# sourceMappingURL=sharedTree.d.ts.map