/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { assert, unreachableCase } from "@fluidframework/core-utils/internal";
import { Context, TreeStatus } from "../feature-libraries/index.js";
import { getFlexNode, treeNodeApi, } from "../simple-tree/index.js";
import { fail } from "../util/index.js";
import { SchematizingSimpleTreeView } from "./schematizingTreeView.js";
import { contextToTreeView } from "./treeView.js";
/**
 * The `Tree` object holds various functions for interacting with {@link TreeNode}s.
 * @public
 */
export const treeApi = {
    ...treeNodeApi,
    runTransaction(treeOrNode, transaction, preconditions = []) {
        if (treeOrNode instanceof SchematizingSimpleTreeView) {
            const t = transaction;
            runTransaction(treeOrNode.checkout, () => t(treeOrNode.root), preconditions);
        }
        else {
            const node = treeOrNode;
            const t = transaction;
            const context = getFlexNode(node).context;
            assert(context instanceof Context, 0x901 /* Unsupported context */);
            const treeView = contextToTreeView.get(context) ??
                fail("Expected view to be registered for context");
            runTransaction(treeView.checkout, () => t(node), preconditions);
        }
    },
    contains(parent, child) {
        let toCheck = child;
        while (toCheck !== undefined) {
            if (toCheck === parent) {
                return true;
            }
            toCheck = treeApi.parent(toCheck);
        }
        return false;
    },
};
// TODO: Add more constraint types here
function runTransaction(checkout, transaction, preconditions) {
    checkout.transaction.start();
    for (const constraint of preconditions) {
        switch (constraint.type) {
            case "nodeInDocument": {
                const node = getFlexNode(constraint.node);
                assert(node.treeStatus() === TreeStatus.InDocument, 0x90f /* Attempted to apply "nodeExists" constraint when building a transaction, but the node is not in the document. */);
                checkout.editor.addNodeExistsConstraint(node.anchorNode);
                break;
            }
            default:
                unreachableCase(constraint.type);
        }
    }
    let result;
    try {
        result = transaction();
    }
    catch (e) {
        // If the transaction has an unhandled error, abort and rollback the transaction but continue to propagate the error.
        checkout.transaction.abort();
        throw e;
    }
    if (result === "rollback") {
        checkout.transaction.abort();
    }
    else {
        checkout.transaction.commit();
    }
}
//# sourceMappingURL=treeApi.js.map