/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { fail } from "@fluidframework/core-utils/internal";
import { AnchorTreeIndex, isTreeValue, hasElement, } from "../../feature-libraries/index.js";
import { brand } from "../../util/index.js";
import { treeNodeFromAnchor } from "../core/index.js";
import { treeNodeApi } from "./treeNodeApi.js";
import { walkFieldSchema } from "../walkFieldSchema.js";
/**
 * Creates a {@link SimpleTreeIndex} with a specified indexer.
 *
 * @alpha
 */
export function createSimpleTreeIndex(view, indexer, getValue, isKeyValid, indexableSchema) {
    const indexableSchemaMap = new Map();
    if (indexableSchema !== undefined) {
        for (const schemus of indexableSchema) {
            indexableSchemaMap.set(schemus.identifier, schemus);
        }
    }
    else {
        walkFieldSchema(view.schema, {
            node: (schemus) => indexableSchemaMap.set(schemus.identifier, schemus),
        });
    }
    const schemaIndexer = indexableSchema === undefined
        ? (schemaIdentifier) => {
            // if indexable schema isn't provided, we check if the node is in schema
            const schemus = indexableSchemaMap.get(schemaIdentifier);
            if (schemus !== undefined) {
                const keyLocation = typeof indexer === "function" ? indexer(schemus) : indexer.get(schemus);
                if (keyLocation !== undefined) {
                    return makeGenericKeyFinder(brand(keyLocation), isKeyValid);
                }
            }
            else {
                fail(0xb32 /* node is out of schema */);
            }
        }
        : (schemaIdentifier) => {
            const schemus = indexableSchemaMap.get(schemaIdentifier);
            if (schemus !== undefined) {
                const keyLocation = typeof indexer === "function" ? indexer(schemus) : indexer.get(schemus);
                if (keyLocation !== undefined) {
                    return makeGenericKeyFinder(brand(keyLocation), isKeyValid);
                }
            }
        };
    const index = new AnchorTreeIndex(view.getView().checkout.forest, schemaIndexer, (anchorNodes) => {
        const simpleTreeNodes = [];
        for (const anchorNode of anchorNodes) {
            const simpleTree = treeNodeFromAnchor(anchorNode);
            if (!isTreeValue(simpleTree)) {
                simpleTreeNodes.push(simpleTree);
            }
        }
        if (hasElement(simpleTreeNodes)) {
            return getValue(simpleTreeNodes);
        }
    }, (anchorNode) => {
        const simpleTree = treeNodeFromAnchor(anchorNode);
        if (!isTreeValue(simpleTree)) {
            return treeNodeApi.status(simpleTree);
        }
    }, 
    // simple tree indexes are shallow indexes, indicating so allows for a performance optimization
    true);
    // all the type checking guarantees that we put nodes of the correct type in the index
    // but it's not captured in the type system
    return index;
}
function makeGenericKeyFinder(keyField, isKeyValid) {
    return (cursor) => {
        cursor.enterField(keyField);
        cursor.firstNode();
        const value = cursor.value;
        cursor.exitNode();
        cursor.exitField();
        if (value === undefined) {
            fail(0xb33 /* a value for the key does not exist */);
        }
        if (!isKeyValid(value)) {
            fail(0xb34 /* the key is an unexpected type */);
        }
        return value;
    };
}
//# sourceMappingURL=simpleTreeIndex.js.map