import { Store } from './store';
import { commands } from './commands';
const HISTORY_SIZE = 100;
export class CommanderStore {
    constructor(data) {
        this.store = new Store(data);
        this.commands = Object.keys(commands).reduce((acc, key) => {
            const SomeCommand = commands[key];
            acc[key] = new SomeCommand(this.store);
            return acc;
        }, {});
        this.undoHistory = {};
        this.redoHistory = {};
    }
    get(path) {
        return this.store.get(path);
    }
    subscribe(listener) {
        return this.store.subscribe(listener);
    }
    dispatch(event) {
        var _a;
        var _b;
        const { command, scope, isEffect, options, } = event;
        const cmd = this.commands[command];
        if (!cmd) {
            return;
        }
        const undo = cmd.execute(options);
        const redo = cmd.execute.bind(cmd, options);
        if (undo === undefined) {
            return;
        }
        (_a = (_b = this.undoHistory)[scope]) !== null && _a !== void 0 ? _a : (_b[scope] = []);
        if (isEffect && this.undoHistory[scope].length > 0) {
            const lastOperation = this.undoHistory[scope].at(-1);
            lastOperation.effects.push({ undo, redo });
            return;
        }
        this.undoHistory[scope].push({ undo, redo, effects: [] });
        if (this.undoHistory[scope].length > HISTORY_SIZE) {
            this.undoHistory[scope].shift();
        }
        this.redoHistory[scope] = [];
    }
    undo(event) {
        var _a;
        const { scope } = event;
        if (((_a = this.undoHistory[scope]) === null || _a === void 0 ? void 0 : _a.length) > 0) {
            const operation = this.undoHistory[scope].pop();
            for (let j = operation.effects.length - 1; j >= 0; j -= 1) {
                operation.effects[j].undo();
            }
            operation.undo();
            this.redoHistory[scope].push(operation);
        }
    }
    redo(event) {
        var _a;
        const { scope } = event;
        if (((_a = this.redoHistory[scope]) === null || _a === void 0 ? void 0 : _a.length) > 0) {
            const operation = this.redoHistory[scope].pop();
            operation.redo();
            operation.effects.forEach((effect) => effect.redo());
            this.undoHistory[scope].push(operation);
        }
    }
    clean(event) {
        const { scope } = event;
        delete this.undoHistory[scope];
        delete this.redoHistory[scope];
    }
}
