"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.newGenericChangeset = exports.convertGenericChange = exports.genericFieldKind = exports.genericChangeHandler = void 0;
const core_1 = require("../../core");
const util_1 = require("../../util");
const fieldKind_1 = require("./fieldKind");
const genericFieldKindCodecs_1 = require("./genericFieldKindCodecs");
/**
 * {@link FieldChangeHandler} implementation for {@link GenericChangeset}.
 */
exports.genericChangeHandler = {
    rebaser: {
        compose: (changes, composeChildren) => {
            if (changes.length === 0) {
                return [];
            }
            const composed = [];
            for (const change of changes) {
                let listIndex = 0;
                for (const { index, nodeChange } of change.change) {
                    const taggedChange = (0, core_1.tagChange)(nodeChange, change.revision);
                    while (listIndex < composed.length && composed[listIndex].index < index) {
                        listIndex += 1;
                    }
                    const match = composed[listIndex];
                    if (match === undefined) {
                        composed.push({ index, nodeChange: composeChildren([taggedChange]) });
                    }
                    else if (match.index > index) {
                        composed.splice(listIndex, 0, {
                            index,
                            nodeChange: composeChildren([taggedChange]),
                        });
                    }
                    else {
                        composed.splice(listIndex, 1, {
                            index,
                            nodeChange: composeChildren([
                                // `match.nodeChange` was the result of a call to `composeChildren`,
                                // so it does not need a revision tag.
                                // See the contract of `FieldChangeHandler.compose`.
                                (0, core_1.makeAnonChange)(match.nodeChange),
                                taggedChange,
                            ]),
                        });
                    }
                }
            }
            return composed;
        },
        amendCompose: () => (0, util_1.fail)("Not implemented"),
        invert: ({ change }, invertChild) => {
            return change.map(({ index, nodeChange }) => ({
                index,
                nodeChange: invertChild(nodeChange, index),
            }));
        },
        amendInvert: () => (0, util_1.fail)("Not implemented"),
        rebase: rebaseGenericChange,
        amendRebase: rebaseGenericChange,
    },
    codecsFactory: genericFieldKindCodecs_1.makeGenericChangeCodec,
    editor: {
        buildChildChange(index, change) {
            return [{ index, nodeChange: change }];
        },
    },
    intoDelta: ({ change }, deltaFromChild) => {
        let nodeIndex = 0;
        const markList = [];
        for (const { index, nodeChange } of change) {
            if (nodeIndex < index) {
                const offset = index - nodeIndex;
                markList.push({ count: offset });
                nodeIndex = index;
            }
            markList.push({ count: 1, fields: deltaFromChild(nodeChange) });
            nodeIndex += 1;
        }
        return { local: markList };
    },
    isEmpty: (change) => change.length === 0,
};
function rebaseGenericChange(change, { change: over }, rebaseChild) {
    const rebased = [];
    let iChange = 0;
    let iOver = 0;
    while (iChange < change.length || iOver < over.length) {
        const a = change[iChange];
        const b = over[iOver];
        const aIndex = a?.index ?? Infinity;
        const bIndex = b?.index ?? Infinity;
        let nodeChangeA;
        let nodeChangeB;
        let index;
        if (aIndex === bIndex) {
            index = a.index;
            nodeChangeA = a.nodeChange;
            nodeChangeB = b.nodeChange;
            iChange += 1;
            iOver += 1;
        }
        else if (aIndex < bIndex) {
            index = a.index;
            nodeChangeA = a.nodeChange;
            iChange += 1;
        }
        else {
            index = b.index;
            nodeChangeB = b.nodeChange;
            iOver += 1;
        }
        const nodeChange = rebaseChild(nodeChangeA, nodeChangeB);
        if (nodeChange !== undefined) {
            rebased.push({
                index,
                nodeChange,
            });
        }
    }
    return rebased;
}
/**
 * {@link FieldKind} used to represent changes to elements of a field in a field-kind-agnostic format.
 */
exports.genericFieldKind = new fieldKind_1.FieldKindWithEditor("ModularEditBuilder.Generic", fieldKind_1.Multiplicity.Sequence, exports.genericChangeHandler, (types, other) => false, new Set());
/**
 * Converts a {@link GenericChangeset} into a field-kind-specific `TChange`.
 * @param changeset - The generic changeset to convert.
 * @param target - The {@link FieldChangeHandler} for the `FieldKind` that the returned change should target.
 * @param composeChild - A delegate to compose {@link NodeChangeset}s.
 * @returns An equivalent changeset as represented by the `target` field-kind.
 */
function convertGenericChange(changeset, target, composeChild, genId, revisionMetadata) {
    const perIndex = changeset.map(({ index, nodeChange }) => (0, core_1.makeAnonChange)(target.editor.buildChildChange(index, nodeChange)));
    return target.rebaser.compose(perIndex, composeChild, genId, invalidCrossFieldManager, revisionMetadata);
}
exports.convertGenericChange = convertGenericChange;
const invalidFunc = () => (0, util_1.fail)("Should not be called when converting generic changes");
const invalidCrossFieldManager = {
    set: invalidFunc,
    get: invalidFunc,
};
function newGenericChangeset() {
    return [];
}
exports.newGenericChangeset = newGenericChangeset;
//# sourceMappingURL=genericFieldKind.js.map