"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.createIndependentTreeAlpha = exports.createIndependentTreeBeta = exports.independentInitializedView = exports.independentView = void 0;
const internal_1 = require("@fluidframework/core-utils/internal");
const internal_2 = require("@fluidframework/id-compressor/internal");
const index_js_1 = require("../core/index.js");
const index_js_2 = require("../feature-libraries/index.js");
const index_js_3 = require("../feature-libraries/index.js");
const index_js_4 = require("../util/index.js");
const schematizeTree_js_1 = require("./schematizeTree.js");
const schematizingTreeView_js_1 = require("./schematizingTreeView.js");
const sharedTree_js_1 = require("./sharedTree.js");
const treeCheckout_js_1 = require("./treeCheckout.js");
/**
 * Create an uninitialized {@link TreeView} that is not tied to any {@link ITree} instance.
 *
 * @remarks
 * Such a view can never experience collaboration or be persisted to to a Fluid Container.
 *
 * This can be useful for testing, as well as use-cases like working on local files instead of documents stored in some Fluid service.
 * @alpha
 */
function independentView(config, options) {
    return createIndependentTreeAlpha(options).viewWith(config);
}
exports.independentView = independentView;
/**
 * Create an initialized {@link TreeView} that is not tied to any {@link ITree} instance.
 *
 * @remarks
 * Such a view can never experience collaboration or be persisted to to a Fluid Container.
 *
 * This can be useful for testing, as well as use-cases like working on local files instead of documents stored in some Fluid service.
 * @privateRemarks
 * TODO: Providing an API which generates a {@link ViewableTree} extended with export options from {@link ITreeAlpha} and maybe even branching APIs would likely be better that just exposing a {@link TreeViewAlpha}.
 * @alpha
 */
function independentInitializedView(config, options, content) {
    return createIndependentTreeAlpha({ ...options, content }).viewWith(config);
}
exports.independentInitializedView = independentInitializedView;
/**
 * Create a {@link ViewableTree} that is not tied to any Fluid runtimes or services.
 *
 * @remarks
 * Such a tree can never experience collaboration or be persisted to to a Fluid Container.
 *
 * This can be useful for testing, as well as use-cases like working on local files instead of documents stored in some Fluid service.
 *
 * @example
 * ```typescript
 * const tree = createIndependentTreeBeta();
 *
 * const stagedConfig = new TreeViewConfiguration({
 * 	schema: SchemaFactoryAlpha.types([
 * 		SchemaFactory.number,
 * 		SchemaFactoryAlpha.staged(SchemaFactory.string),
 * 	]),
 * });
 * const afterConfig = new TreeViewConfigurationAlpha({
 * 	schema: [SchemaFactory.number, SchemaFactory.string],
 * });
 *
 * // Initialize tree
 * {
 * 	const view = tree.viewWith(stagedConfig);
 * 	view.initialize(1);
 * 	view.dispose();
 * }
 *
 * // Do schema upgrade
 * {
 * 	const view = tree.viewWith(afterConfig);
 * 	view.upgradeSchema();
 * 	view.root = "A";
 * 	view.dispose();
 * }
 *
 * // Can still view tree with staged schema
 * {
 * 	const view = tree.viewWith(stagedConfig);
 * 	assert.equal(view.root, "A");
 * 	view.dispose();
 * }
 * ```
 * @privateRemarks
 * Before stabilizing this as public, consider if we can instead just expose a better way to create regular Fluid service based SharedTrees for tests.
 * Something like https://github.com/microsoft/FluidFramework/pull/25422 might be a better long term stable/public solution.
 * @beta
 */
function createIndependentTreeBeta(options) {
    return createIndependentTreeAlpha(options);
}
exports.createIndependentTreeBeta = createIndependentTreeBeta;
/**
 * Alpha extensions to {@link createIndependentTreeBeta}.
 *
 * @param options - Configuration options for the independent tree.
 * This can be used to create an uninitialized tree, or `content` can be provided to create an initialized tree.
 * If content is provided, the idCompressor is a required part of it: otherwise it is optional and provided at the top level.
 *
 * @privateRemarks
 * TODO: Support more of {@link ITreeAlpha}, including branching APIs to allow for merges.
 * TODO: Better unify this logic with SharedTreeKernel and SharedTreeCore.
 *
 * Before further stabilizing: consider better ways to handle initialized vs uninitialized trees.
 * Perhaps it would be better to not allow initialize here at all, but expose the ability to load compressed tree content and stored schema via ITree or TreeView?
 * If keeping the option here, maybe a separate function of overload would be better? Or maybe flatten ViewContent inline to deduplicate the idCompressor options?
 * @alpha
 */
function createIndependentTreeAlpha(options) {
    const breaker = new index_js_4.Breakable("independentView");
    const idCompressor = options?.idCompressor ?? options?.content?.idCompressor ?? (0, internal_2.createIdCompressor)();
    const mintRevisionTag = () => idCompressor.generateCompressedId();
    const revisionTagCodec = new index_js_1.RevisionTagCodec(idCompressor);
    // To ensure the forest is in schema when constructed, start it with an empty schema and set the schema repository content later.
    const schemaRepository = new index_js_1.TreeStoredSchemaRepository();
    const forest = (0, sharedTree_js_1.buildConfiguredForest)(breaker, options?.forest ?? sharedTree_js_1.defaultSharedTreeOptions.forest, schemaRepository, idCompressor, index_js_2.defaultIncrementalEncodingPolicy);
    const checkout = (0, treeCheckout_js_1.createTreeCheckout)(idCompressor, mintRevisionTag, revisionTagCodec, {
        forest,
        schema: schemaRepository,
        breaker,
        codecOptions: options,
    });
    if (options?.content !== undefined) {
        const schemaCodec = index_js_2.schemaCodecBuilder.buildDecoder(options);
        const fieldBatchCodec = index_js_2.fieldBatchCodecBuilder.buildDecoder(options);
        const newSchema = schemaCodec.decode(options.content.schema);
        const context = {
            encodeType: index_js_2.TreeCompressionStrategy.Compressed,
            idCompressor,
            originatorId: idCompressor.localSessionId, // Is this right? If so, why is is needed?
            schema: { schema: newSchema, policy: index_js_2.defaultSchemaPolicy },
        };
        const fieldCursors = fieldBatchCodec.decode(options.content.tree, context);
        (0, internal_1.assert)(fieldCursors.length === 1, 0xa5b /* must have exactly 1 field in batch */);
        const fieldCursor = (0, index_js_4.oneFromIterable)(fieldCursors);
        (0, internal_1.assert)(fieldCursor !== undefined, 0xc94 /* expected exactly one field in batch */);
        (0, schematizeTree_js_1.initialize)(checkout, newSchema, (0, schematizeTree_js_1.initializerFromChunk)(checkout, () => (0, index_js_3.combineChunks)(checkout.forest.chunkField(fieldCursor))));
    }
    return {
        viewWith(config) {
            const out = new schematizingTreeView_js_1.SchematizingSimpleTreeView(checkout, config, (0, index_js_2.createNodeIdentifierManager)(idCompressor));
            return out;
        },
        exportVerbose() {
            return checkout.exportVerbose();
        },
        exportSimpleSchema() {
            return (0, sharedTree_js_1.exportSimpleSchema)(checkout.storedSchema);
        },
    };
}
exports.createIndependentTreeAlpha = createIndependentTreeAlpha;
//# sourceMappingURL=independentView.js.map