/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { assert } from "@fluidframework/common-utils";
import { applyMoveEffectsToMark } from "./moveEffectTable";
import { getMarkLength, splitMark } from "./utils";
export class MarkQueue {
    constructor(list, revision, moveEffects, consumeEffects, genId, composeChanges) {
        this.list = list;
        this.revision = revision;
        this.moveEffects = moveEffects;
        this.consumeEffects = consumeEffects;
        this.genId = genId;
        this.composeChanges = composeChanges;
        this.stack = [];
        this.index = 0;
        this.list = list;
    }
    isEmpty() {
        return this.peek() === undefined;
    }
    dequeue() {
        const output = this.tryDequeue();
        assert(output !== undefined, 0x4e2 /* Unexpected end of mark queue */);
        return output;
    }
    tryDequeue() {
        if (this.stack.length > 0) {
            return this.stack.pop();
        }
        else if (this.index < this.list.length) {
            const mark = this.list[this.index++];
            if (mark === undefined) {
                return undefined;
            }
            const splitMarks = applyMoveEffectsToMark(mark, this.revision, this.moveEffects, this.consumeEffects, this.composeChanges);
            if (splitMarks.length === 0) {
                return undefined;
            }
            const result = splitMarks[0];
            for (let i = splitMarks.length - 1; i > 0; i--) {
                this.stack.push(splitMarks[i]);
            }
            return result;
        }
    }
    /**
     * Dequeues the first `length` sized portion of the next mark.
     * The caller must verify that the next mark (as returned by peek) is longer than this length.
     * @param length - The length to dequeue, measured in the input context.
     */
    dequeueUpTo(length) {
        const mark = this.dequeue();
        if (getMarkLength(mark) <= length) {
            return mark;
        }
        const [mark1, mark2] = splitMark(mark, this.revision, length, this.genId, this.moveEffects, !this.consumeEffects);
        this.stack.push(mark2);
        return mark1;
    }
    peek() {
        const mark = this.tryDequeue();
        if (mark !== undefined) {
            this.stack.push(mark);
        }
        return mark;
    }
}
//# sourceMappingURL=markQueue.js.map