"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.sequenceFieldToDelta = void 0;
const core_utils_1 = require("@fluidframework/core-utils");
const util_1 = require("../../util");
const core_1 = require("../../core");
const treeTextCursor_1 = require("../treeTextCursor");
const format_1 = require("./format");
const utils_1 = require("./utils");
function sequenceFieldToDelta({ change, revision }, deltaFromChild, idAllocator) {
    const out = new util_1.OffsetListFactory();
    for (const mark of change) {
        const changes = (0, utils_1.getEffectiveNodeChanges)(mark);
        const cellDeltas = cellDeltaFromMark(mark, revision, idAllocator, changes === undefined);
        if (changes !== undefined) {
            (0, core_utils_1.assert)(cellDeltas.length === 1, 0x74f /* Invalid nested changes on non length-1 mark */);
            const fullDelta = withChildModifications(changes, cellDeltas[0], deltaFromChild);
            out.push(fullDelta);
        }
        else {
            out.push(...cellDeltas);
        }
    }
    return out.list;
}
exports.sequenceFieldToDelta = sequenceFieldToDelta;
function cellDeltaFromMark(mark, revision, idAllocator, ignoreTransient) {
    if (!(0, utils_1.areInputCellsEmpty)(mark) && !(0, utils_1.areOutputCellsEmpty)(mark)) {
        // Since each cell is associated with exactly one node,
        // the cell starting end ending populated means the cell content has not changed.
        return [mark.count];
    }
    else if ((0, utils_1.areInputCellsEmpty)(mark) &&
        (0, utils_1.areOutputCellsEmpty)(mark) &&
        (!(0, utils_1.markIsTransient)(mark) || ignoreTransient)) {
        // The cell starting and ending empty means the cell content has not changed,
        // unless transient content was inserted/attached.
        return [0];
    }
    else {
        const type = mark.type;
        // Inline into `switch(mark.type)` once we upgrade to TS 4.7
        switch (type) {
            case "Insert": {
                const cursors = mark.content.map(treeTextCursor_1.singleTextCursor);
                const insertMark = {
                    type: core_1.Delta.MarkType.Insert,
                    content: cursors,
                };
                if (mark.transientDetach !== undefined) {
                    insertMark.isTransient = true;
                }
                return [insertMark];
            }
            case "MoveIn":
            case "ReturnTo": {
                const ranges = idAllocator.allocate(mark.revision ?? revision, mark.id, mark.count);
                return ranges.map(({ first, count }) => ({
                    type: core_1.Delta.MarkType.MoveIn,
                    moveId: (0, util_1.brandOpaque)(first),
                    count,
                }));
            }
            case format_1.NoopMarkType: {
                return [mark.count];
            }
            case "Delete": {
                return [
                    {
                        type: core_1.Delta.MarkType.Delete,
                        count: mark.count,
                    },
                ];
            }
            case "MoveOut":
            case "ReturnFrom": {
                const ranges = idAllocator.allocate(mark.revision ?? revision, mark.id, mark.count);
                return ranges.map(({ first, count }) => ({
                    type: core_1.Delta.MarkType.MoveOut,
                    moveId: (0, util_1.brandOpaque)(first),
                    count,
                }));
            }
            case "Revive": {
                const insertMark = {
                    type: core_1.Delta.MarkType.Insert,
                    content: mark.content,
                };
                if (mark.transientDetach !== undefined) {
                    insertMark.isTransient = true;
                }
                return [insertMark];
            }
            case "Placeholder":
                (0, util_1.fail)("Should not have placeholders in a changeset being converted to delta");
            default:
                (0, core_utils_1.unreachableCase)(type);
        }
    }
}
function withChildModifications(changes, deltaMark, deltaFromChild) {
    const modify = deltaFromChild(changes);
    if (modify.fields !== undefined) {
        if (typeof deltaMark === "number") {
            (0, core_utils_1.assert)(deltaMark === 1, 0x72d /* Invalid nested changes on non-1 skip mark */);
            return modify;
        }
        else {
            (0, core_utils_1.assert)(deltaMark.type !== core_1.Delta.MarkType.MoveIn, 0x72e /* Invalid nested changes on MoveIn mark */);
            return { ...deltaMark, fields: modify.fields };
        }
    }
    return deltaMark;
}
//# sourceMappingURL=sequenceFieldToDelta.js.map