using System; using System.Collections.Generic; using System.Linq; using System.Reactive; using System.Reactive.Linq; using System.Reactive.Subjects; using Artemis.Core; using ReactiveUI; namespace Artemis.UI.Services.ProfileEditor { public class ProfileEditorHistory { private readonly Subject _canRedo = new(); private readonly Subject _canUndo = new(); private readonly Stack _redoCommands = new(); private readonly Stack _undoCommands = new(); public ProfileEditorHistory(ProfileConfiguration profileConfiguration) { ProfileConfiguration = profileConfiguration; Execute = ReactiveCommand.Create(ExecuteEditorCommand); Undo = ReactiveCommand.Create(ExecuteUndo, CanUndo); Redo = ReactiveCommand.Create(ExecuteRedo, CanRedo); } public ProfileConfiguration ProfileConfiguration { get; } public IObservable CanUndo => _canUndo.AsObservable().DistinctUntilChanged(); public IObservable CanRedo => _canRedo.AsObservable().DistinctUntilChanged(); public ReactiveCommand Execute { get; } public ReactiveCommand Undo { get; } public ReactiveCommand Redo { get; } public void Clear() { ClearRedo(); ClearUndo(); UpdateSubjects(); } public void ExecuteEditorCommand(IProfileEditorCommand command) { command.Execute(); _undoCommands.Push(command); ClearRedo(); UpdateSubjects(); } private void ClearRedo() { foreach (IProfileEditorCommand profileEditorCommand in _redoCommands) if (profileEditorCommand is IDisposable disposable) disposable.Dispose(); _redoCommands.Clear(); } private void ClearUndo() { foreach (IProfileEditorCommand profileEditorCommand in _undoCommands) if (profileEditorCommand is IDisposable disposable) disposable.Dispose(); _undoCommands.Clear(); } private void ExecuteUndo() { if (!_undoCommands.TryPop(out IProfileEditorCommand? command)) return; command.Undo(); _redoCommands.Push(command); UpdateSubjects(); } private void ExecuteRedo() { if (!_redoCommands.TryPop(out IProfileEditorCommand? command)) return; command.Execute(); _undoCommands.Push(command); UpdateSubjects(); } private void UpdateSubjects() { _canUndo.OnNext(_undoCommands.Any()); _canRedo.OnNext(_redoCommands.Any()); } } }