"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.toDelta = void 0;
const common_utils_1 = require("@fluidframework/common-utils");
const treeTextCursor_1 = require("../../treeTextCursor");
const core_1 = require("../../../core");
const deltaUtils_1 = require("../../deltaUtils");
const util_1 = require("../../../util");
const utils_1 = require("./utils");
/**
 * Converts a Changeset into a Delta.
 * @param changeset - The Changeset to convert
 * @returns A Delta for applying the changes described in the given Changeset.
 */
function toDelta(changeset) {
    // Save result to a constant to work around linter bug:
    // https://github.com/typescript-eslint/typescript-eslint/issues/5014
    const out = convertFieldMarks(changeset.marks);
    return out;
}
exports.toDelta = toDelta;
function convertMarkList(marks) {
    const out = new util_1.OffsetListFactory();
    for (const mark of marks) {
        if ((0, utils_1.isSkipMark)(mark)) {
            out.pushOffset(mark);
        }
        else {
            // Inline into `switch(mark.type)` once we upgrade to TS 4.7
            const type = mark.type;
            switch (type) {
                case "Insert": {
                    const insertMark = {
                        type: core_1.Delta.MarkType.Insert,
                        // TODO: can we skip this clone?
                        content: (0, util_1.clone)(mark.content).map(treeTextCursor_1.singleTextCursor),
                    };
                    out.pushContent(insertMark);
                    break;
                }
                case "MInsert": {
                    const insertMark = {
                        type: core_1.Delta.MarkType.Insert,
                        content: [(0, treeTextCursor_1.singleTextCursor)(mark.content)],
                    };
                    (0, deltaUtils_1.populateChildModifications)(convertModify(mark), insertMark);
                    out.pushContent(insertMark);
                    break;
                }
                case "MoveIn": {
                    const moveMark = {
                        type: core_1.Delta.MarkType.MoveIn,
                        count: mark.count,
                        moveId: (0, util_1.brandOpaque)(mark.id),
                    };
                    out.pushContent(moveMark);
                    break;
                }
                case "MMoveIn":
                    (0, util_1.fail)("MMoveIn not implemented");
                case "Bounce":
                case "Intake":
                    // These have no impacts on the document state.
                    break;
                case "Modify": {
                    if (mark.tomb === undefined) {
                        out.pushContent(Object.assign({ type: core_1.Delta.MarkType.Modify }, convertModify(mark)));
                    }
                    break;
                }
                case "Delete": {
                    const deleteMark = {
                        type: core_1.Delta.MarkType.Delete,
                        count: mark.count,
                    };
                    out.pushContent(deleteMark);
                    break;
                }
                case "MDelete": {
                    const deleteMark = {
                        type: core_1.Delta.MarkType.Delete,
                        count: 1,
                    };
                    (0, deltaUtils_1.populateChildModifications)(convertModify(mark), deleteMark);
                    out.pushContent(deleteMark);
                    break;
                }
                case "MoveOut": {
                    const moveMark = {
                        type: core_1.Delta.MarkType.MoveOut,
                        moveId: (0, util_1.brandOpaque)(mark.id),
                        count: mark.count,
                    };
                    out.pushContent(moveMark);
                    break;
                }
                case "Revive": {
                    const insertMark = {
                        type: core_1.Delta.MarkType.Insert,
                        // TODO: Restore the actual node
                        content: (0, util_1.makeArray)(mark.count, () => (0, treeTextCursor_1.singleTextCursor)({ type: DUMMY_REVIVED_NODE_TYPE })),
                    };
                    out.pushContent(insertMark);
                    break;
                }
                case "MRevive": {
                    const insertMark = {
                        type: core_1.Delta.MarkType.Insert,
                        // TODO: Restore the actual node
                        content: [(0, treeTextCursor_1.singleTextCursor)({ type: DUMMY_REVIVED_NODE_TYPE })],
                    };
                    out.pushContent(insertMark);
                    break;
                }
                case "MMoveOut":
                case "Return":
                case "MReturn":
                case "Gap":
                    (0, util_1.fail)("Gap not implemented");
                case "Tomb": {
                    // These tombs are only used to precisely describe the location of other attaches.
                    // They have no impact on the current state.
                    break;
                }
                default:
                    (0, common_utils_1.unreachableCase)(type);
            }
        }
    }
    return out.list;
}
const DUMMY_REVIVED_NODE_TYPE = (0, util_1.brand)("RevivedNode");
/**
 * Converts tree modifications from the Changeset to the Delta format.
 */
function convertModify(modify) {
    const out = {};
    if (modify.value !== undefined) {
        out.setValue = modify.value.value;
    }
    const fields = modify.fields;
    if (fields !== undefined) {
        out.fields = convertFieldMarks(fields);
    }
    return out;
}
function convertFieldMarks(fields) {
    const outFields = new Map();
    for (const key of Object.keys(fields)) {
        const marks = convertMarkList(fields[key]);
        const brandedKey = (0, util_1.brand)(key);
        outFields.set(brandedKey, marks);
    }
    return outFields;
}
//# sourceMappingURL=toDelta.js.map