import { TransformUtils, Command, Transform, UndoManagerObserver, } from "../internal"; export class UndoManager { protected _redoStack: Array; protected _undoStack: Array; protected _transform: Transform; protected _observer: UndoManagerObserver; protected _transformStack(stack: Array, command: Command): void { const transform = this._transform; const sizeof = stack.length - 1; for (let i = sizeof; i >= 0; i--) { const pair1 = transform.transfer(stack[i].redo, command); const pair2 = transform.transfer(stack[i].undo, pair1[1]); stack[i].redo = pair1[0]; stack[i].undo = pair2[0]; command = pair2[1]; } } public constructor(transform: Transform) { this._redoStack = []; this._undoStack = []; this._transform = transform; this._observer = new UndoManagerObserver(); } public transform(command: Command): void { this._transformStack(this._undoStack, command); this._transformStack(this._redoStack, command); } public canUndo(): boolean { return this._undoStack.length !== 0; } public canRedo(): boolean { return this._redoStack.length !== 0; } public addRedo(redo: Command, undo: Command): void public addRedo(wrapped: UndoManager.Wrapped): void public addRedo(...parameter: any): void { if (TransformUtils.hasLength(parameter, 1)) { const wrapped = parameter[0]; this._redoStack.push(wrapped); this._observer.dispatchOnAddRedo(wrapped); return; } if (TransformUtils.hasLength(parameter, 2)) { const redo = parameter[0]; const undo = parameter[1]; const wrapped = { redo, undo }; this._redoStack.push(wrapped); this._observer.dispatchOnAddRedo(wrapped); } } public addUndo(redo: Command, undo: Command): void public addUndo(wrapped: UndoManager.Wrapped): void public addUndo(...parameter: any): void { if (TransformUtils.hasLength(parameter, 1)) { const wrapped = parameter[0]; this._undoStack.push(wrapped); this._observer.dispatchOnAddUndo(wrapped); return; } if (TransformUtils.hasLength(parameter, 2)) { const redo = parameter[0]; const undo = parameter[1]; const wrapped = { redo, undo }; this._undoStack.push(wrapped); this._observer.dispatchOnAddUndo(wrapped); } } public performCommand(redo: Command, undo: Command): void public performCommand(wrapped: UndoManager.Wrapped): void public performCommand(...parameter: any): void { if (TransformUtils.hasLength(parameter, 1)) { const wrapped = parameter[0]; this.addRedo(wrapped); return; } if (TransformUtils.hasLength(parameter, 2)) { const redo = parameter[0]; const undo = parameter[1]; const wrapped = { redo, undo }; this.addRedo(wrapped); } } public performRedo(): void { if (this.canRedo()) { const wrapped = this._redoStack.pop(); this.addUndo(wrapped); this._observer.dispatchOnRedo(wrapped); } } public performUndo(): void { if (this.canUndo()) { const wrapped = this._undoStack.pop(); this.addRedo(wrapped); this._observer.dispatchOnUndo(wrapped); } } public getObserver(): UndoManagerObserver { return this._observer; } } export namespace UndoManager { export interface Wrapped{ undo: Command, redo: Command, } }