using DominionBase.Enums; using DominionBase.Players; using System; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Linq; using System.Reflection; using System.Text; using System.Xml; namespace DominionBase.Cards { public class ItemCollection : List where T : IDisplayable { protected object _MyLock { get; } = new object(); public ItemCollection() { } public ItemCollection(int capacity) : base(capacity) { } public ItemCollection(IEnumerable collection) : base(collection) { } public ItemCollection(T item) : base() { Add(item); } public T PopAt(int index) { T r = this[index]; RemoveAt(index); return r; } public new ItemCollection FindAll(Predicate match) { return new ItemCollection(base.FindAll(match)); } public new ItemCollection GetRange(int index, int count) { return new ItemCollection(base.GetRange(index, count)); } public ItemCollection Except(ItemCollection second) { return new ItemCollection(this.Except(second)); } // Temporary until I figure this out internal void AddedTo(DeckLocation location, IPlayer player) { foreach (var card in this.OfType()) card.AddedTo(location, player); } // Temporary until I figure this out internal void RemovedFrom(DeckLocation location, IPlayer player) { foreach (var card in this.OfType()) card.RemovedFrom(location, player); } // Temporary until I figure this out internal void AddedTo(Type deckType, Player player) { foreach (var card in this.OfType()) card.AddedTo(deckType, player); } // Temporary until I figure this out internal void RemovedFrom(Type deckType, Player player) { foreach (var card in this.OfType()) card.RemovedFrom(deckType, player); } // Temporary until I figure this out internal void ObtainedBy(Player player) { foreach (var card in this.OfType()) card.ObtainedBy(player); } // Temporary until I figure this out internal void LostBy(Player player) { foreach (var card in this.OfType()) card.LostBy(player); } // Temporary until I figure this out internal void ReceivedBy(IPlayer player) { foreach (var card in this.OfType()) card.ReceivedBy(player); } // Temporary until I figure this out internal void TrashedBy(Player player) { foreach (var card in this.OfType()) card.TrashedBy(player); } public override string ToString() { var sb = new StringBuilder(); foreach (var c in this) { if (sb.Length > 0) sb.Append(", "); sb.Append(c); } return sb.ToString(); } public string ToString(bool isCollated) { if (!isCollated) return ToString(); var sb = new StringBuilder(); T previousItem = default; var count = 0; lock (_MyLock) { for (var cIndex = 0; cIndex < Count; cIndex++) { if (previousItem == null) previousItem = this[cIndex]; if (previousItem.Type != this[cIndex].Type) { if (sb.Length != 0) sb.Append(", "); if (count > 1) sb.AppendFormat("{0}x {1}", count, previousItem); else sb.Append(previousItem); previousItem = this[cIndex]; count = 0; } count++; } } if (previousItem != null) { if (sb.Length != 0) sb.Append(", "); if (count > 1) sb.AppendFormat("{0}x {1}", count, previousItem); else sb.Append(previousItem); } return sb.ToString(); } // Caching for fun & profit private static readonly Dictionary CardCache = new Dictionary(); public static IRandomizable GetMatchingCard(Type type, Func predicate) { Contract.Requires(type != null, "type cannot be null"); Contract.Requires(predicate != null, "predicate cannot be null"); if (!CardCache.ContainsKey(type)) { if (type.IsSubclassOf(typeof(Card))) CardCache[type] = Card.CreateInstance(type); else if (type.IsSubclassOf(typeof(Event))) CardCache[type] = Event.CreateInstance(type); else if (type.IsSubclassOf(typeof(Landmark))) CardCache[type] = Landmark.CreateInstance(type); else if (type.IsSubclassOf(typeof(Boon))) CardCache[type] = Boon.CreateInstance(type); else if (type.IsSubclassOf(typeof(Hex))) CardCache[type] = Hex.CreateInstance(type); else if (type.IsSubclassOf(typeof(State))) CardCache[type] = State.CreateInstance(type); else if (type.IsSubclassOf(typeof(Artifact))) CardCache[type] = Artifact.CreateInstance(type); else if (type.IsSubclassOf(typeof(Project))) CardCache[type] = Project.CreateInstance(type); else if (type.IsSubclassOf(typeof(Way))) CardCache[type] = Way.CreateInstance(type); } if (CardCache.ContainsKey(type) && predicate(CardCache[type])) return CardCache[type]; return null; } public static Dictionary, EditionUsage>, IEnumerable> _CardsCache = new Dictionary, EditionUsage>, IEnumerable>(); public static IEnumerable GetAllCards(Func predicate, EditionUsage editionUsage = EditionUsage.SecondPriority) { var cacheKey = new Tuple, EditionUsage>(predicate, editionUsage); if (!_CardsCache.ContainsKey(cacheKey)) { var cards = new List(); var cardSets = Assembly.GetExecutingAssembly().GetTypes().Where(x => x.Namespace != null && x.Namespace.StartsWith("DominionBase.Cards", StringComparison.InvariantCulture) && x.Name == "TypeClass"); foreach (var cardSet in cardSets) { foreach (var fi in cardSet.GetFields()) { // These aren't the ones we're looking for if (!fi.IsPublic || !fi.IsStatic) continue; var t = (Type)fi.GetValue(null); var card = GetMatchingCard(t, predicate); if (card != null) { switch (editionUsage) { case EditionUsage.FirstOnly: if (card.Edition != Edition.All && card.Edition != Edition.First) continue; break; case EditionUsage.SecondOnly: if (card.Edition != Edition.All && card.Edition != Edition.Second) continue; break; case EditionUsage.FirstPriority: if (card.Edition == Edition.First && cards.Any(c => c.Name == card.Name)) cards.RemoveAll(c => c.Name == card.Name); if (card.Edition != Edition.First && cards.Any(c => c.Name == card.Name)) continue; break; case EditionUsage.SecondPriority: if (card.Edition == Edition.Second && cards.Any(c => c.Name == card.Name)) cards.RemoveAll(c => c.Name == card.Name); if (card.Edition != Edition.Second && cards.Any(c => c.Name == card.Name)) continue; break; //case EditionUsage.Errata2019Priority: // // TODO -- This logic seems suspect; I probably need to redo it all // if (card.Edition == Edition.Errata2019 && cards.Any(c => c.Name == card.Name)) // cards.RemoveAll(c => c.Name == card.Name); // if (card.Edition != Edition.Errata2019 && cards.Any(c => c.Name == card.Name)) // continue; // if (card.Edition == Edition.Second && cards.Any(c => c.Name == card.Name)) // cards.RemoveAll(c => c.Name == card.Name); // if (card.Edition != Edition.Second && cards.Any(c => c.Name == card.Name)) // continue; // break; } cards.Add(card); } } } _CardsCache[cacheKey] = cards; } return _CardsCache[cacheKey]; } internal void TearDown(IGame game) { foreach (var card in this) card.TearDown(game); } internal virtual XmlNode GenerateXml(XmlDocument doc, string nodeName) { var xePile = doc.CreateElement(nodeName); //foreach (var card in this) // xePile.AppendChild(card.GenerateXml(doc, "card")); return xePile; } internal static ItemCollection Load(XmlNode xnCards) { var cc = new ItemCollection(); // cc.AddRange(from XmlNode xnCard in xnCards.SelectNodes("card") select T.Load(xnCard)); return cc; } } }