"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.invert = exports.DUMMY_INVERSE_VALUE = exports.DUMMY_INVERT_TAG = void 0;
const util_1 = require("../../util");
const changeset_1 = require("./changeset");
/**
 * Dummy value used in place of the actual tag.
 * TODO: give `invert` access real tag data.
 */
exports.DUMMY_INVERT_TAG = "Dummy Invert Changeset Tag";
/**
 * Dummy value used in place of actual repair data.
 * TODO: give `invert` access real repair data.
 */
exports.DUMMY_INVERSE_VALUE = "Dummy inverse value";
/**
 * Inverts a given changeset.
 * @param change - The changeset to produce the inverse of.
 * @returns The inverse of the given `change` such that the inverse can be applied after `change`.
 *
 * @remarks WARNING! This implementation is incomplete:
 *
 * - It is unable to produce adequate inverses for set-value and delete operations.
 * This is because changesets are not given IDs.
 *
 * - Support for moves is not implemented.
 *
 * - Support for slices is not implemented.
 */
function invert(change) {
    // TODO: support the input change being a squash
    const opIdToTag = (id) => {
        return exports.DUMMY_INVERT_TAG;
    };
    return {
        marks: invertFieldMarks(change.change.marks, opIdToTag),
    };
}
exports.invert = invert;
function invertFieldMarks(fieldMarks, opIdToTag) {
    const inverseFieldMarks = {};
    for (const key of Object.keys(fieldMarks)) {
        const markList = fieldMarks[key];
        inverseFieldMarks[key] = invertMarkList(markList, opIdToTag);
    }
    return inverseFieldMarks;
}
function invertMarkList(markList, opIdToTag) {
    const inverseMarkList = [];
    for (const mark of markList) {
        const inverseMarks = invertMark(mark, opIdToTag);
        inverseMarkList.push(...inverseMarks);
    }
    return inverseMarkList;
}
function invertMark(mark, opIdToTag) {
    if ((0, changeset_1.isSkipMark)(mark)) {
        return [mark];
    }
    else {
        switch (mark.type) {
            case "Insert":
            case "MInsert": {
                return [
                    {
                        type: "Delete",
                        id: mark.id,
                        count: mark.type === "Insert" ? mark.content.length : 1,
                    },
                ];
            }
            case "Delete": {
                return [
                    {
                        type: "Revive",
                        id: mark.id,
                        tomb: opIdToTag(mark.id),
                        count: mark.count,
                    },
                ];
            }
            case "Revive": {
                return [
                    {
                        type: "Delete",
                        id: mark.id,
                        count: mark.count,
                    },
                ];
            }
            case "Modify": {
                const modify = {
                    type: "Modify",
                };
                if (mark.value !== undefined) {
                    modify.value = {
                        id: mark.value.id,
                        value: exports.DUMMY_INVERSE_VALUE,
                    };
                }
                if (mark.fields !== undefined) {
                    modify.fields = invertFieldMarks(mark.fields, opIdToTag);
                }
                return [modify];
            }
            default:
                (0, util_1.fail)("Not implemented");
        }
    }
}
//# sourceMappingURL=invert.js.map