"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.stringifySummary = exports.parseSummary = exports.EditManagerSummarizer = void 0;
const common_utils_1 = require("@fluidframework/common-utils");
const shared_object_base_1 = require("@fluidframework/shared-object-base");
const util_1 = require("../util");
const core_1 = require("../core");
/**
 * The storage key for the blob in the summary containing EditManager data
 */
const blobKey = "Blob";
const stringKey = "String";
const formatVersion = 0;
/**
 * Provides methods for summarizing and loading an `EditManager`
 */
class EditManagerSummarizer {
    constructor(runtime, editManager) {
        this.runtime = runtime;
        this.editManager = editManager;
        this.key = "EditManager";
        this.changesetCodec = this.editManager.changeFamily.codecs.resolve(formatVersion);
        this.editDataBlob = (0, core_1.cachedValue)(async (observer) => {
            (0, core_1.recordDependency)(observer, this.editManager);
            const dataString = stringifySummary(this.editManager.getSummaryData(), this.changesetCodec);
            // For now we are not chunking the edit data, but still put it in a reusable blob:
            return this.runtime.uploadBlob(common_utils_1.IsoBuffer.from(dataString));
        });
    }
    getAttachSummary(stringify, fullTree, trackState, telemetryContext) {
        const dataString = stringifySummary(this.editManager.getSummaryData(), this.changesetCodec);
        return (0, shared_object_base_1.createSingleBlobSummary)(stringKey, dataString);
    }
    async summarize(stringify, fullTree, trackState, telemetryContext) {
        const editDataBlobHandle = await this.editDataBlob.get();
        const content = stringify(editDataBlobHandle);
        return (0, shared_object_base_1.createSingleBlobSummary)(blobKey, content);
    }
    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) {
        let schemaBuffer;
        if (await services.contains(blobKey)) {
            const handleBuffer = await services.readBlob(blobKey);
            const handleString = (0, common_utils_1.bufferToString)(handleBuffer, "utf-8");
            const handle = parse(handleString);
            schemaBuffer = await handle.get();
        }
        else {
            (0, common_utils_1.assert)(await services.contains(stringKey), 0x42b /* EditManager data is required in summary */);
            schemaBuffer = await services.readBlob(stringKey);
        }
        // After the awaits, validate that the data is in a clean state.
        // This detects any data that could have been accidentally added through
        // invalid means and is about to be overwritten.
        (0, common_utils_1.assert)(this.editManager.isEmpty(), 0x42c /* There should not already be stored EditManager data when loading from summary */);
        const dataString = (0, common_utils_1.bufferToString)(schemaBuffer, "utf-8");
        const data = parseSummary(dataString, this.changesetCodec);
        this.editManager.loadSummaryData(data);
    }
}
exports.EditManagerSummarizer = EditManagerSummarizer;
function parseSummary(summary, codec) {
    const decodeCommit = (commit) => (Object.assign(Object.assign({}, commit), { change: codec.json.decode(commit.change) }));
    const json = JSON.parse(summary);
    return {
        trunk: json.trunk.map(decodeCommit),
        branches: new Map((0, util_1.mapIterable)(json.branches, ([sessionId, branch]) => [
            sessionId,
            Object.assign(Object.assign({}, branch), { commits: branch.commits.map(decodeCommit) }),
        ])),
    };
}
exports.parseSummary = parseSummary;
function stringifySummary(data, codec) {
    const encodeCommit = (commit) => (Object.assign(Object.assign({}, commit), { change: codec.json.encode(commit.change) }));
    const json = {
        trunk: data.trunk.map(encodeCommit),
        branches: Array.from(data.branches.entries(), ([sessionId, branch]) => [
            sessionId,
            Object.assign(Object.assign({}, branch), { commits: branch.commits.map(encodeCommit) }),
        ]),
    };
    return JSON.stringify(json);
}
exports.stringifySummary = stringifySummary;
//# sourceMappingURL=editManagerSummarizer.js.map