using DominionBase.Enums; using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DominionBase { public interface IDisplayable : ICardBase, IComparable { CardBack CardBack { get; } IDisplayable DisplayCard { get; } Edition Edition { get; } Facing Facing { get; } bool IsStackable { get; } Location Location { get; } Orientation Orientation { get; } IDisplayable RootCard { get; } Traits Traits { get; } DisplayableCollection Stack(); void TearDown(IGame game); } public class DisplayableCollectionChangedEventArgs : EventArgs { public enum Operation { Reset, Added, Removed } public DisplayableCollection AddedItems { get; } public DisplayableCollection RemovedItems { get; } public Operation OperationPerformed { get; } public DisplayableCollectionChangedEventArgs(Operation operation) { OperationPerformed = operation; AddedItems = new DisplayableCollection(); RemovedItems = new DisplayableCollection(); } public DisplayableCollectionChangedEventArgs(Operation operation, IDisplayable itemChanged = null) : this(operation) { if (itemChanged != null) switch (operation) { case Operation.Added: AddedItems.Add(itemChanged, true); break; case Operation.Removed: RemovedItems.Add(itemChanged, true); break; } } public DisplayableCollectionChangedEventArgs(Operation operation, IEnumerable itemsChanged) : this(operation) { switch (operation) { case Operation.Added: AddedItems.AddRange(itemsChanged, true); break; case Operation.Removed: RemovedItems.AddRange(itemsChanged, true); break; } } } public delegate void DisplayableCollectionChangedEventHandler(object sender, DisplayableCollectionChangedEventArgs e); public class DisplayableCollection : List { public virtual event DisplayableCollectionChangedEventHandler DisplayableCollectionChanged; protected bool _AsynchronousChanging { get; private set; } protected DisplayableCollectionChangedEventArgs _AsynchronousDisplayableCollectionChangedEventArgs { get; private set; } private readonly object _MyLock = new object(); public DisplayableCollection() { } public DisplayableCollection(int capacity) : base(capacity) { } public DisplayableCollection(IEnumerable collection) : base(collection) { } public virtual void BeginChanges() { _AsynchronousChanging = true; _AsynchronousDisplayableCollectionChangedEventArgs = null; } public virtual void EndChanges() { _AsynchronousChanging = false; var _event = DisplayableCollectionChanged; if (_event != null && _AsynchronousDisplayableCollectionChangedEventArgs != null) { _event(this, _AsynchronousDisplayableCollectionChangedEventArgs); } _AsynchronousDisplayableCollectionChangedEventArgs = null; } private void TriggerEvent(DisplayableCollectionChangedEventArgs.Operation operation, IDisplayable item = null, IEnumerable collection = null) { DisplayableCollectionChangedEventArgs dccea; if (item != null) dccea = new DisplayableCollectionChangedEventArgs(operation, item); else if (collection != null) dccea = new DisplayableCollectionChangedEventArgs(operation, collection); else dccea = new DisplayableCollectionChangedEventArgs(operation); var _event = DisplayableCollectionChanged; if (_AsynchronousChanging) _AsynchronousDisplayableCollectionChangedEventArgs = dccea; else _event?.Invoke(this, dccea); } public void Add(IDisplayable item, bool silent=false) { base.Add(item); if (!silent) TriggerEvent(DisplayableCollectionChangedEventArgs.Operation.Added, item); } public void AddRange(IEnumerable collection, bool silent = false) { base.AddRange(collection); if (!silent) TriggerEvent(DisplayableCollectionChangedEventArgs.Operation.Added, collection: collection); } public new void Insert(int index, IDisplayable item) { base.Insert(index, item); TriggerEvent(DisplayableCollectionChangedEventArgs.Operation.Added, item); } public new void InsertRange(int index, IEnumerable collection) { base.InsertRange(index, collection); TriggerEvent(DisplayableCollectionChangedEventArgs.Operation.Added, collection: collection); } public new bool Remove(IDisplayable item) { var ret = base.Remove(item); TriggerEvent(DisplayableCollectionChangedEventArgs.Operation.Removed, item); return ret; } public new int RemoveAll(Predicate match) { var matching = FindAll(match); var ret = base.RemoveAll(match); TriggerEvent(DisplayableCollectionChangedEventArgs.Operation.Removed, collection: matching); return ret; } public new void RemoveAt(int index) { var item = this[index]; base.RemoveAt(index); TriggerEvent(DisplayableCollectionChangedEventArgs.Operation.Removed, item); } public new void RemoveRange(int index, int count) { var items = this.Skip(index).Take(count); base.RemoveRange(index, count); TriggerEvent(DisplayableCollectionChangedEventArgs.Operation.Removed, collection: items); } public new void Reverse() { base.Reverse(); TriggerEvent(DisplayableCollectionChangedEventArgs.Operation.Reset); } public new void Reverse(int index, int count) { base.Reverse(index, count); TriggerEvent(DisplayableCollectionChangedEventArgs.Operation.Reset); } public new void Sort() { base.Sort(); TriggerEvent(DisplayableCollectionChangedEventArgs.Operation.Reset); } public new void Sort(Comparison comparison) { base.Sort(comparison); TriggerEvent(DisplayableCollectionChangedEventArgs.Operation.Reset); } public new void Sort(IComparer comparer) { base.Sort(comparer); TriggerEvent(DisplayableCollectionChangedEventArgs.Operation.Reset); } public new void Sort(int index, int count, IComparer comparer) { base.Sort(index, count, comparer); TriggerEvent(DisplayableCollectionChangedEventArgs.Operation.Reset); } public new void Clear() { base.Clear(); TriggerEvent(DisplayableCollectionChangedEventArgs.Operation.Reset); } public new DisplayableCollection FindAll(Predicate match) { return new DisplayableCollection(base.FindAll(match)); } public new DisplayableCollection GetRange(int index, int count) { return new DisplayableCollection(base.GetRange(index, count)); } public DisplayableCollection Except(DisplayableCollection second) { return new DisplayableCollection(this.Except(second)); } public override string ToString() { var sb = new StringBuilder(); foreach (var c in this) { if (sb.Length > 0) sb.Append(", "); sb.Append(c.ToString()); } return sb.ToString(); } public string ToString(bool isCollated) { if (!isCollated) return ToString(); var sb = new StringBuilder(); IDisplayable _previousCard = null; var count = 0; lock (_MyLock) { for (var cIndex = 0; cIndex < Count; cIndex++) { if (_previousCard == null) _previousCard = this[cIndex]; if (_previousCard.Type != this[cIndex].Type) { if (sb.Length != 0) sb.Append(", "); if (count > 1) sb.AppendFormat("{0}x {1}", count, _previousCard); else sb.Append(_previousCard); _previousCard = this[cIndex]; count = 0; } count++; } } if (_previousCard != null) { if (sb.Length != 0) sb.Append(", "); if (count > 1) sb.AppendFormat("{0}x {1}", count, _previousCard); else sb.Append(_previousCard); } return sb.ToString(); } internal void TearDown(IGame game) { foreach (var item in this) item.TearDown(game); } } }