"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.createSimpleTreeIndex = void 0;
const internal_1 = require("@fluidframework/core-utils/internal");
const index_js_1 = require("../../feature-libraries/index.js");
const index_js_2 = require("../../util/index.js");
const index_js_3 = require("../core/index.js");
const treeNodeApi_js_1 = require("./treeNodeApi.js");
const walkFieldSchema_js_1 = require("../walkFieldSchema.js");
/**
 * Creates a {@link SimpleTreeIndex} with a specified indexer.
 *
 * @alpha
 */
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 {
        (0, walkFieldSchema_js_1.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((0, index_js_2.brand)(keyLocation), isKeyValid);
                }
            }
            else {
                (0, internal_1.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((0, index_js_2.brand)(keyLocation), isKeyValid);
                }
            }
        };
    const index = new index_js_1.AnchorTreeIndex(view.checkout.forest, schemaIndexer, (anchorNodes) => {
        const simpleTreeNodes = [];
        for (const anchorNode of anchorNodes) {
            const simpleTree = (0, index_js_3.treeNodeFromAnchor)(anchorNode);
            if (!(0, index_js_1.isTreeValue)(simpleTree)) {
                simpleTreeNodes.push(simpleTree);
            }
        }
        if ((0, index_js_1.hasElement)(simpleTreeNodes)) {
            return getValue(simpleTreeNodes);
        }
    }, (anchorNode) => {
        const simpleTree = (0, index_js_3.treeNodeFromAnchor)(anchorNode);
        if (!(0, index_js_1.isTreeValue)(simpleTree)) {
            return treeNodeApi_js_1.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;
}
exports.createSimpleTreeIndex = createSimpleTreeIndex;
function makeGenericKeyFinder(keyField, isKeyValid) {
    return (cursor) => {
        cursor.enterField(keyField);
        cursor.firstNode();
        const value = cursor.value;
        cursor.exitNode();
        cursor.exitField();
        if (value === undefined) {
            (0, internal_1.fail)(0xb33 /* a value for the key does not exist */);
        }
        if (!isKeyValid(value)) {
            (0, internal_1.fail)(0xb34 /* the key is an unexpected type */);
        }
        return value;
    };
}
//# sourceMappingURL=simpleTreeIndex.js.map