/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { bufferToString } from "@fluid-internal/client-utils";
import { createSingleBlobSummary } from "@fluidframework/shared-object-base";
import { assert } from "@fluidframework/core-utils";
import { applyDelta, makeDetachedFieldIndex, mapCursorField, mapCursorFields, } from "../core";
import { idAllocatorFromMaxId } from "../util";
import { jsonableTreeFromCursor, singleTextCursor } from "./treeTextCursor";
/**
 * The storage key for the blob in the summary containing tree data
 */
const treeBlobKey = "ForestTree";
/**
 * Provides methods for summarizing and loading a forest.
 */
export class ForestSummarizer {
    constructor(forest) {
        this.forest = forest;
        this.key = "Forest";
        this.cursor = this.forest.allocateCursor();
    }
    /**
     * 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) {
        this.forest.moveCursorToPath(undefined, this.cursor);
        const fields = mapCursorFields(this.cursor, (cursor) => [
            this.cursor.getFieldKey(),
            mapCursorField(cursor, jsonableTreeFromCursor),
        ]);
        this.cursor.clear();
        return stringify(fields);
    }
    getAttachSummary(stringify, fullTree, trackState, telemetryContext) {
        return createSingleBlobSummary(treeBlobKey, this.getTreeString(stringify));
    }
    async summarize(stringify, fullTree, trackState, telemetryContext) {
        return 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 = 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 = parse(treeBufferString);
            const allocator = idAllocatorFromMaxId();
            const delta = fields.map(([fieldKey, content]) => {
                const buildId = { minor: allocator.allocate(content.length) };
                return [
                    fieldKey,
                    {
                        build: [{ id: buildId, trees: content.map(singleTextCursor) }],
                        local: [{ count: content.length, attach: buildId }],
                    },
                ];
            });
            assert(this.forest.isEmpty, 0x797 /* forest must be empty */);
            applyDelta(new Map(delta), this.forest, makeDetachedFieldIndex("init"));
        }
    }
}
//# sourceMappingURL=forestSummarizer.js.map