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.Shared.Services.ProfileEditor;
///
/// Represents the command history of a profile configuration.
///
public class ProfileEditorHistory
{
private readonly Subject _canRedo = new();
private readonly Subject _canUndo = new();
private readonly Stack _redoCommands = new();
private readonly Stack _undoCommands = new();
///
/// Creates a new instance of the class.
///
/// The profile configuration the history relates to.
public ProfileEditorHistory(ProfileConfiguration profileConfiguration)
{
ProfileConfiguration = profileConfiguration;
Execute = ReactiveCommand.Create(ExecuteEditorCommand);
Undo = ReactiveCommand.Create(ExecuteUndo, CanUndo);
Redo = ReactiveCommand.Create(ExecuteRedo, CanRedo);
}
///
/// Gets the profile configuration the history relates to.
///
public ProfileConfiguration ProfileConfiguration { get; }
///
/// Gets an observable sequence containing a boolean value indicating whether history can be undone.
///
public IObservable CanUndo => _canUndo.AsObservable().DistinctUntilChanged();
///
/// Gets an observable sequence containing a boolean value indicating whether history can be redone.
///
public IObservable CanRedo => _canRedo.AsObservable().DistinctUntilChanged();
///
/// Gets a reactive command that can be executed to execute an instance of a and
/// puts it in history.
///
public ReactiveCommand Execute { get; }
///
/// Gets a reactive command that can be executed to undo history.
///
public ReactiveCommand Undo { get; }
///
/// Gets a reactive command that can be executed to redo history.
///
public ReactiveCommand Redo { get; }
///
/// Clears the history.
///
public void Clear()
{
ClearRedo();
ClearUndo();
UpdateSubjects();
}
///
/// Executes the provided and puts it in history.
///
/// The command to execute
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 IProfileEditorCommand? ExecuteUndo()
{
if (!_undoCommands.TryPop(out IProfileEditorCommand? command))
return null;
command.Undo();
_redoCommands.Push(command);
UpdateSubjects();
return command;
}
private IProfileEditorCommand? ExecuteRedo()
{
if (!_redoCommands.TryPop(out IProfileEditorCommand? command))
return null;
command.Execute();
_undoCommands.Push(command);
UpdateSubjects();
return command;
}
private void UpdateSubjects()
{
_canUndo.OnNext(_undoCommands.Any());
_canRedo.OnNext(_redoCommands.Any());
}
}