"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transform = void 0;
const util_1 = require("./util");
/**
 * Transforms an operation such that the transformed operations can be
 * applied to a string in reverse order.
 *
 * ```
 * apply(apply(doc, op1), transform(op2, op1)) === apply(apply(doc, op2), transform(op1, op2))
 * ```
 *
 * @param op1 The operation to transform.
 * @param op2 The operation to transform against.
 * @returns A new operation with user intentions preserved.
 */
const transform = (op1, op2, leftInsertFirst) => {
    const op3 = [];
    const len1 = op1.length;
    const len2 = op2.length;
    let i1 = 0;
    let i2 = 0;
    let off1 = 0;
    for (; i2 < len2; i2++) {
        const comp2 = op2[i2];
        let doDelete = false;
        switch (typeof comp2) {
            case 'number': {
                if (comp2 > 0) {
                    let length2 = comp2;
                    while (length2 > 0) {
                        const comp1 = op1[i1];
                        const comp = i1 >= len1 ? length2 : (0, util_1.chunk)(comp1, off1, length2);
                        const compLength = (0, util_1.componentLength)(comp);
                        const length1 = (0, util_1.componentLength)(comp1 || comp);
                        (0, util_1.append)(op3, comp);
                        off1 += compLength;
                        if (off1 >= length1) {
                            i1++;
                            off1 = 0;
                        }
                        if (typeof comp !== 'string')
                            length2 -= compLength;
                    }
                }
                else
                    doDelete = true;
                break;
            }
            case 'string': {
                if (leftInsertFirst) {
                    if (typeof op1[i1] === 'string') {
                        const comp = (0, util_1.chunk)(op1[i1++], off1, Number.POSITIVE_INFINITY);
                        off1 = 0;
                        (0, util_1.append)(op3, comp);
                    }
                }
                (0, util_1.append)(op3, comp2.length);
                break;
            }
            case 'object': {
                doDelete = true;
                break;
            }
        }
        if (doDelete) {
            const isReversible = comp2 instanceof Array;
            const length2 = isReversible ? comp2[0].length : -comp2;
            let off2 = 0;
            while (off2 < length2) {
                const remaining = length2 - off2;
                const comp1 = op1[i1];
                const comp = i1 >= len1 ? remaining : (0, util_1.chunk)(comp1, off1, remaining);
                const compLength = (0, util_1.componentLength)(comp);
                const length1 = (0, util_1.componentLength)(comp1 || comp);
                if (typeof comp === 'string')
                    (0, util_1.append)(op3, comp);
                else
                    off2 += compLength;
                off1 += compLength;
                if (off1 >= length1) {
                    i1++;
                    off1 = 0;
                }
            }
        }
    }
    if (i1 < len1 && off1)
        (0, util_1.append)(op3, (0, util_1.chunk)(op1[i1++], off1, Number.POSITIVE_INFINITY));
    for (; i1 < len1; i1++)
        (0, util_1.append)(op3, op1[i1]);
    (0, util_1.trim)(op3);
    return op3;
};
exports.transform = transform;
//# sourceMappingURL=transform.js.map