using System; using System.Collections.Generic; namespace Artemis.Core; /// /// Provides a default implementation for models that can have a broken state /// public abstract class BreakableModel : CorePropertyChanged, IBreakableModel { private string? _brokenState; private Exception? _brokenStateException; /// /// Invokes the event /// protected virtual void OnBrokenStateChanged() { BrokenStateChanged?.Invoke(this, EventArgs.Empty); } /// public abstract string BrokenDisplayName { get; } /// /// Gets or sets the broken state of this breakable model, if this model is not broken. /// Note: If setting this manually you are also responsible for invoking /// public string? BrokenState { get => _brokenState; set => SetAndNotify(ref _brokenState, value); } /// /// Gets or sets the exception that caused the broken state /// Note: If setting this manually you are also responsible for invoking /// public Exception? BrokenStateException { get => _brokenStateException; set => SetAndNotify(ref _brokenStateException, value); } /// public bool TryOrBreak(Action action, string breakMessage) { try { action(); ClearBrokenState(breakMessage); return true; } catch (Exception e) { SetBrokenState(breakMessage, e); return false; } } /// public void SetBrokenState(string state, Exception? exception = null) { if (state == BrokenState && BrokenStateException?.StackTrace == exception?.StackTrace) return; BrokenState = state ?? throw new ArgumentNullException(nameof(state)); BrokenStateException = exception; OnBrokenStateChanged(); } /// public void ClearBrokenState(string state) { if (state == null) throw new ArgumentNullException(nameof(state)); // If there was no broken state to begin with, done! if (BrokenState == null) return; // Only clear similar broken states if (BrokenState != state) return; BrokenState = null; BrokenStateException = null; OnBrokenStateChanged(); } /// public virtual IEnumerable GetBrokenHierarchy() { if (BrokenState != null) yield return this; } /// public event EventHandler? BrokenStateChanged; }