"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.ForestSummarizer = void 0;
const client_utils_1 = require("@fluid-internal/client-utils");
const shared_object_base_1 = require("@fluidframework/shared-object-base");
const core_utils_1 = require("@fluidframework/core-utils");
const core_1 = require("../core");
const util_1 = require("../util");
const codec_1 = require("../codec");
const chunked_forest_1 = require("./chunked-forest");
const treeCompressionUtils_1 = require("./treeCompressionUtils");
const forestSummarizerCodec_1 = require("./forestSummarizerCodec");
/**
 * The storage key for the blob in the summary containing tree data
 */
const treeBlobKey = "ForestTree";
/**
 * Provides methods for summarizing and loading a forest.
 */
class ForestSummarizer {
    constructor(forest, schema, policy, encodeType = treeCompressionUtils_1.TreeCompressionStrategy.Compressed, options) {
        this.forest = forest;
        this.key = "Forest";
        this.schema = schema;
        this.policy = policy;
        this.encodeType = encodeType;
        this.options = options ?? { jsonValidator: codec_1.noopValidator };
        this.codec = (0, forestSummarizerCodec_1.makeForestSummarizerCodec)(this.options);
    }
    /**
     * Synchronous monolithic summarization of tree content.
     *
     * TODO: when perf matters, this should be replaced with a chunked async version using a binary format.
     *
     * @returns a snapshot of the forest's tree as a string.
     */
    getTreeString(stringify) {
        const rootCursor = this.forest.getCursorAboveDetachedFields();
        // TODO: Encode all detached fields in one operation for better performance and compression
        const fields = (0, core_1.mapCursorFields)(rootCursor, (cursor) => [
            rootCursor.getFieldKey(),
            encodeSummary(cursor, this.schema, this.policy, this.encodeType),
        ]);
        return stringify(this.codec.encode(fields));
    }
    getAttachSummary(stringify, fullTree, trackState, telemetryContext) {
        return (0, shared_object_base_1.createSingleBlobSummary)(treeBlobKey, this.getTreeString(stringify));
    }
    async summarize(stringify, fullTree, trackState, telemetryContext) {
        return (0, shared_object_base_1.createSingleBlobSummary)(treeBlobKey, this.getTreeString(stringify));
    }
    getGCData(fullGC) {
        // TODO: Properly implement garbage collection. Right now, garbage collection is performed automatically
        // by the code in SharedObject (from which SharedTreeCore extends). The `runtime.uploadBlob` API delegates
        // to the `BlobManager`, which automatically populates the summary with ISummaryAttachment entries for each
        // blob.
        return {
            gcNodes: {},
        };
    }
    async load(services, parse) {
        if (await services.contains(treeBlobKey)) {
            const treeBuffer = await services.readBlob(treeBlobKey);
            const treeBufferString = (0, client_utils_1.bufferToString)(treeBuffer, "utf8");
            // TODO: this code is parsing data without an optional validator, this should be defined in a typebox schema as part of the
            // forest summary format.
            const fields = this.codec.decode(parse(treeBufferString));
            const allocator = (0, util_1.idAllocatorFromMaxId)();
            const fieldChanges = fields.map(([fieldKey, content]) => {
                const nodeCursors = (0, core_1.mapCursorField)((0, chunked_forest_1.decode)(content).cursor(), (cursor) => cursor.fork());
                const buildId = { minor: allocator.allocate(nodeCursors.length) };
                return [
                    fieldKey,
                    {
                        build: [
                            {
                                id: buildId,
                                trees: nodeCursors,
                            },
                        ],
                        local: [{ count: nodeCursors.length, attach: buildId }],
                    },
                ];
            });
            (0, core_utils_1.assert)(this.forest.isEmpty, 0x797 /* forest must be empty */);
            (0, core_1.applyDelta)({ fields: new Map(fieldChanges) }, this.forest, (0, core_1.makeDetachedFieldIndex)("init"));
        }
    }
}
exports.ForestSummarizer = ForestSummarizer;
function encodeSummary(cursor, schema, policy, encodeType) {
    switch (encodeType) {
        case treeCompressionUtils_1.TreeCompressionStrategy.Compressed:
            return (0, chunked_forest_1.schemaCompressedEncode)(schema, policy, cursor);
        case treeCompressionUtils_1.TreeCompressionStrategy.Uncompressed:
            return (0, chunked_forest_1.uncompressedEncode)(cursor);
        default:
            (0, core_utils_1.unreachableCase)(encodeType);
    }
}
//# sourceMappingURL=forestSummarizer.js.map