"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.runSynchronous = exports.SharedTreeView = exports.createSharedTreeView = exports.create = void 0;
const core_1 = require("../core");
const events_1 = require("../events");
const feature_libraries_1 = require("../feature-libraries");
const shared_tree_core_1 = require("../shared-tree-core");
const util_1 = require("../util");
const schematizedTree_1 = require("./schematizedTree");
const sharedTree_1 = require("./sharedTree");
/**
 * Used as a static property to access the creation function for a {@link SharedTreeView}.
 */
exports.create = Symbol("Create SharedTreeView");
/**
 * Creates a {@link SharedTreeView}.
 * @param args - an object containing optional components that will be used to build the view.
 * Any components not provided will be created by default.
 * @remarks This does not create a {@link SharedTree}, but rather a view with the minimal state
 * and functionality required to implement {@link ISharedTreeView}.
 */
function createSharedTreeView(args) {
    var _a, _b, _c, _d, _e;
    const schema = (_a = args === null || args === void 0 ? void 0 : args.schema) !== null && _a !== void 0 ? _a : new core_1.InMemoryStoredSchemaRepository(feature_libraries_1.defaultSchemaPolicy);
    const forest = (_b = args === null || args === void 0 ? void 0 : args.forest) !== null && _b !== void 0 ? _b : (0, feature_libraries_1.buildForest)(schema, new core_1.AnchorSet());
    const repairDataStoreProvider = (_c = args === null || args === void 0 ? void 0 : args.repairProvider) !== null && _c !== void 0 ? _c : new feature_libraries_1.ForestRepairDataStoreProvider(forest, schema);
    const undoRedoManager = core_1.UndoRedoManager.create(repairDataStoreProvider, feature_libraries_1.defaultChangeFamily);
    const branch = (_d = args === null || args === void 0 ? void 0 : args.branch) !== null && _d !== void 0 ? _d : new shared_tree_core_1.SharedTreeBranch({
        change: feature_libraries_1.defaultChangeFamily.rebaser.compose([]),
        revision: (0, core_1.assertIsRevisionTag)("00000000-0000-4000-8000-000000000000"),
    }, feature_libraries_1.defaultChangeFamily, undoRedoManager, forest.anchors);
    const context = (0, feature_libraries_1.getEditableTreeContext)(forest, branch.editor);
    const identifierIndex = (_e = args === null || args === void 0 ? void 0 : args.identifierIndex) !== null && _e !== void 0 ? _e : new feature_libraries_1.IdentifierIndex(sharedTree_1.identifierKey);
    return SharedTreeView[exports.create](branch, schema, forest, context, identifierIndex);
}
exports.createSharedTreeView = createSharedTreeView;
/**
 * An implementation of {@link ISharedTreeView}.
 * @alpha
 */
class SharedTreeView {
    constructor(branch, _storedSchema, _forest, context, _identifiedIndex) {
        this.branch = branch;
        this._storedSchema = _storedSchema;
        this._forest = _forest;
        this.context = context;
        this._identifiedIndex = _identifiedIndex;
        this.events = (0, events_1.createEmitter)();
        this.transaction = {
            start: () => {
                this.branch.startTransaction((0, feature_libraries_1.repairDataStoreFromForest)(this.forest));
                this.branch.editor.enterTransaction();
            },
            commit: () => {
                this.branch.commitTransaction();
                this.branch.editor.exitTransaction();
                return util_1.TransactionResult.Commit;
            },
            abort: () => {
                this.branch.abortTransaction();
                this.branch.editor.exitTransaction();
                return util_1.TransactionResult.Abort;
            },
            inProgress: () => this.branch.isTransacting(),
        };
        branch.on("change", ({ change }) => {
            if (change !== undefined) {
                const delta = feature_libraries_1.defaultChangeFamily.intoDelta(change);
                this._forest.applyDelta(delta);
                this._identifiedIndex.scanIdentifiers(this.context);
                this.events.emit("afterBatch");
            }
        });
    }
    // SharedTreeView is a public type, but its instantiation is internal
    static [exports.create](branch, storedSchema, forest, context, identifiedIndex) {
        return new SharedTreeView(branch, storedSchema, forest, context, identifiedIndex);
    }
    get storedSchema() {
        return this._storedSchema;
    }
    get forest() {
        return this._forest;
    }
    get identifiedNodes() {
        return this._identifiedIndex;
    }
    get rootEvents() {
        return this._forest.anchors;
    }
    get editor() {
        return this.branch.editor;
    }
    undo() {
        this.branch.undo();
    }
    redo() {
        this.branch.redo();
    }
    schematize(config) {
        return (0, schematizedTree_1.schematizeView)(this, config);
    }
    locate(anchor) {
        return this._forest.anchors.locate(anchor);
    }
    fork() {
        const anchors = new core_1.AnchorSet();
        const storedSchema = this._storedSchema.clone();
        const forest = this._forest.clone(storedSchema, anchors);
        const repairDataStoreProvider = new feature_libraries_1.ForestRepairDataStoreProvider(forest, storedSchema);
        const branch = this.branch.fork(repairDataStoreProvider, anchors);
        const context = (0, feature_libraries_1.getEditableTreeContext)(forest, branch.editor);
        return new SharedTreeView(branch, storedSchema, forest, context, this._identifiedIndex.clone(context));
    }
    /**
     * 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) {
        view.rebase(this);
    }
    merge(fork) {
        this.branch.merge(fork.branch);
    }
    rebase(fork) {
        fork.branch.rebaseOnto(this.branch);
    }
    get root() {
        return this.context.unwrappedRoot;
    }
    set root(data) {
        this.context.unwrappedRoot = data;
    }
    /**
     * Dispose this view, freezing its state and allowing the SharedTree to release resources required by it.
     * Attempts to further mutate or dispose this view will error.
     */
    dispose() {
        this.branch.dispose();
    }
}
exports.SharedTreeView = SharedTreeView;
/**
 * 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
 */
function runSynchronous(view, transaction) {
    view.transaction.start();
    const result = transaction(view);
    return result === util_1.TransactionResult.Abort
        ? view.transaction.abort()
        : view.transaction.commit();
}
exports.runSynchronous = runSynchronous;
//# sourceMappingURL=sharedTreeView.js.map