using System; using System.Collections.Generic; using System.Linq; using DominionBase.Cards; using DominionBase.Enums; using DominionBase.Players; namespace DominionBase.Piles { public enum DeckPosition { Top, Bottom, Automatic } public class Deck : CardPile { public Deck(DeckLocation deckLocation) { DeckLocation = deckLocation; } public Deck(DeckLocation deckLocation, Visibility visibility, VisibilityTo visibilityTo) : this(deckLocation, visibility, visibilityTo, null, false) { } public Deck(DeckLocation deckLocation, Visibility visibility, VisibilityTo visibilityTo, IComparer comparer, bool collate) : base(visibility, visibilityTo, comparer, collate) { DeckLocation = deckLocation; } public static Deck CreateInstance(Type type) { return (Deck)Activator.CreateInstance(type); } public override event PileChangedEventHandler PileChanged; public DeckLocation DeckLocation { get; } public override void Clear() { base.Clear(); #if DEBUG TestFireAllEvents(); #endif } public override void EndChanges() { AsynchronousChanging = false; if (AsynchronousPileChangedEventArgs != null) { PileChanged?.Invoke(this, AsynchronousPileChangedEventArgs); } AsynchronousPileChangedEventArgs = null; } public void AddRange(IPlayer player, IEnumerable cardCollection) { AddRange(player, cardCollection, DeckPosition.Top); } public void AddRange(IPlayer player, IEnumerable cardCollection, DeckPosition deckPosition) { var cardsChanged = cardCollection as IList ?? cardCollection.ToList(); switch (deckPosition) { case DeckPosition.Top: InsertRange(0, cardsChanged.Reverse()); break; case DeckPosition.Bottom: AddRange(cardsChanged); break; } Sort(); if (cardsChanged.Any()) { var pileChangedCopy = PileChanged; if (AsynchronousChanging) { if (AsynchronousPileChangedEventArgs == null) AsynchronousPileChangedEventArgs = new PileChangedEventArgs(player, Operation.Added, cardsChanged); else AsynchronousPileChangedEventArgs.AddedCards.AddRange(cardsChanged); } else { pileChangedCopy?.Invoke(this, new PileChangedEventArgs(player, Operation.Added, cardsChanged)); } } } public void Refresh(IPlayer player) { var pileChangedCopy = PileChanged; var pcea = new PileChangedEventArgs(player, Operation.Refresh); if (AsynchronousChanging) { AsynchronousPileChangedEventArgs = pcea; } else { pileChangedCopy?.Invoke(this, pcea); } } public Card Retrieve(IPlayer player) { var cc = Retrieve(player, 1); if (cc.Count == 0) throw new Exception("No Cards to draw!"); return cc[0]; } public Card Retrieve(IPlayer player, Card card) { var cc = Retrieve(player, c => c == card); if (cc.Count == 0) throw new Exception($"Cannot find card {card}"); return cc[0]; } public CardCollection Retrieve(IPlayer player, int count) { return Retrieve(player, DeckPosition.Automatic, c => true, count); } public CardCollection Retrieve(IPlayer player, Predicate match) { return Retrieve(player, DeckPosition.Automatic, match, -1); } public CardCollection Retrieve(IPlayer player, Categories category) { return Retrieve(player, category, -1); } public CardCollection Retrieve(IPlayer player, Type type) { return Retrieve(player, DeckPosition.Automatic, c => c.Type == type, -1); } public CardCollection Retrieve(IPlayer player, Categories category, int count) { return Retrieve(player, DeckPosition.Automatic, c => c.Category.HasFlag(category), count); } public CardCollection Retrieve(IPlayer player, Type type, int count) { return Retrieve(player, DeckPosition.Automatic, c => c.Type == type, count); } public CardCollection Retrieve(IPlayer player, DeckPosition position, Predicate match, int count) { var matching = FindAll(match); if (count >= 0 && count < matching.Count) { matching.RemoveRange(position == DeckPosition.Bottom ? 0 : count, matching.Count - count); if (matching.Count != count) throw new Exception("Incorrect number of cards drawn!"); } RemoveAll(c => matching.Contains(c)); if (matching.Any()) { if (AsynchronousChanging) { if (AsynchronousPileChangedEventArgs == null) AsynchronousPileChangedEventArgs = new PileChangedEventArgs(player, Operation.Removed, matching); else AsynchronousPileChangedEventArgs.AddedCards.AddRange(matching); } else if (PileChanged != null) { var pcea = new PileChangedEventArgs(player, Operation.Removed, matching); PileChanged(this, pcea); } } return matching; } public override void TestFireAllEvents() { PileChanged?.Invoke(this, new PileChangedEventArgs(Operation.Refresh)); } } }