"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const AsyncActionQueue_1 = require("../AsyncActionQueue");
const EventEmitter = require('events');
class UndoQueue {
    constructor() {
        // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
        this.inner_ = [];
        this.size_ = 20;
    }
    pop() {
        return this.inner_.pop();
    }
    // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
    push(e) {
        this.inner_.push(e);
        while (this.length > this.size_) {
            this.inner_.splice(0, 1);
        }
    }
    get length() {
        return this.inner_.length;
    }
    // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
    at(index) {
        return this.inner_[index];
    }
}
class UndoRedoService {
    constructor() {
        this.pushAsyncQueue = new AsyncActionQueue_1.default(700);
        this.undoStates = new UndoQueue();
        this.redoStates = new UndoQueue();
        // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
        this.eventEmitter = new EventEmitter();
        this.isUndoing = false;
        this.push = this.push.bind(this);
    }
    // eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
    on(eventName, callback) {
        return this.eventEmitter.on(eventName, callback);
    }
    // eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
    off(eventName, callback) {
        return this.eventEmitter.removeListener(eventName, callback);
    }
    // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
    push(state) {
        this.undoStates.push(state);
        this.redoStates = new UndoQueue();
        this.eventEmitter.emit('stackChange');
    }
    // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
    schedulePush(state) {
        this.pushAsyncQueue.push(async () => {
            this.push(state);
        });
    }
    // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
    async undo(redoState) {
        if (this.isUndoing)
            return;
        if (!this.canUndo)
            throw new Error('Nothing to undo');
        this.isUndoing = true;
        await this.pushAsyncQueue.processAllNow();
        const state = this.undoStates.pop();
        this.redoStates.push(redoState);
        this.eventEmitter.emit('stackChange');
        this.isUndoing = false;
        return state;
    }
    // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
    async redo(undoState) {
        if (this.isUndoing)
            return;
        if (!this.canRedo)
            throw new Error('Nothing to redo');
        this.isUndoing = true;
        await this.pushAsyncQueue.processAllNow();
        const state = this.redoStates.pop();
        this.undoStates.push(undoState);
        this.eventEmitter.emit('stackChange');
        this.isUndoing = false;
        return state;
    }
    async reset() {
        this.undoStates = new UndoQueue();
        this.redoStates = new UndoQueue();
        this.isUndoing = false;
        const output = this.pushAsyncQueue.reset();
        this.eventEmitter.emit('stackChange');
        return output;
    }
    get canUndo() {
        return !!this.undoStates.length;
    }
    get canRedo() {
        return !!this.redoStates.length;
    }
}
exports.default = UndoRedoService;
//# sourceMappingURL=UndoRedoService.js.map