using System; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Globalization; using System.Linq; using System.Text; using System.Xml; using DominionBase.Cards; using DominionBase.Players; namespace DominionBase.Piles { public class CardMatsChangedEventArgs : EventArgs { public enum Operation { Reset, Added, Removed, Created } public IPlayer Player { get; } = null; public CardCollection AddedCards { get; } public CardCollection RemovedCards { get; } public Operation OperationPerformed { get; } public CardMat CardMat { get; } public CardMatsChangedEventArgs(CardMat cardMat, Operation operation) { CardMat = cardMat; OperationPerformed = operation; AddedCards = new CardCollection(); RemovedCards = new CardCollection(); } public CardMatsChangedEventArgs(CardMat cardMat, IPlayer player, Operation operation) : this(cardMat, operation) { Player = player; } public CardMatsChangedEventArgs(CardMat cardMat, IPlayer player, Operation operation, Card cardChanged) : this(cardMat, player, operation) { switch (operation) { case Operation.Added: AddedCards.Add(cardChanged); break; case Operation.Removed: RemovedCards.Add(cardChanged); break; } } public CardMatsChangedEventArgs(CardMat cardMat, IPlayer player, Operation operation, IEnumerable cardsChanged) : this(cardMat, player, operation) { switch (operation) { case Operation.Added: AddedCards.AddRange(cardsChanged); break; case Operation.Removed: RemovedCards.AddRange(cardsChanged); break; } } } public class CardMat : Deck, IGameObject { public string Name { get; protected set; } public bool IsObtainable { get; protected set; } = true; public virtual string ImageName => ""; public Type Type => GetType(); public TokenCollections TokenPiles { get; private set; } = new TokenCollections(); public CardLabelCollection CardLabels { get; private set; } = new CardLabelCollection(); public CardMat() : base(DeckLocation.PlayerMat) { } public CardMat(Visibility visibility, VisibilityTo visibilityTo) : base(DeckLocation.PlayerMat, visibility, visibilityTo) { } public CardMat(Visibility visibility, VisibilityTo visibilityTo, IComparer comparer, bool collate) : base(DeckLocation.PlayerMat, visibility, visibilityTo, comparer, collate) { } public new static CardMat CreateInstance(Type type) { return (CardMat)Activator.CreateInstance(type); } public virtual void Init(IPlayer player) { } public void AddToken(Token token) { Contract.Requires(token != null, "token cannot be null"); TokenPiles.Add(token); } public void RemoveToken(Token token) { Contract.Requires(token != null, "token cannot be null"); TokenPiles.Remove(token); } public void AddCardLabel(CardLabel label) { Contract.Requires(label != null, "label cannot be null"); CardLabels.Add(label); } public void RemoveCardLabel(CardLabel label) { Contract.Requires(label != null, "label cannot be null"); CardLabels.Remove(label); } internal XmlNode GenerateXml(XmlDocument doc) { var xeCardMat = doc.CreateElement("cardmat"); var xe = doc.CreateElement("type"); xe.InnerText = GetType().ToString(); xeCardMat.AppendChild(xe); xe = doc.CreateElement("isobtainable"); xe.InnerText = IsObtainable.ToString(CultureInfo.InvariantCulture); xeCardMat.AppendChild(xe); xeCardMat.AppendChild(LookThrough(c => true).GenerateXml(doc, "cards")); return xeCardMat; } internal static CardMat Load(XmlNode xnCardMat) { var xnType = xnCardMat.SelectSingleNode("type"); if (xnType == null) return null; var type = Type.GetType(xnType.InnerText); var cardMat = CreateInstance(type); cardMat.LoadInstance(xnCardMat); return cardMat; } internal void LoadInstance(XmlNode xnCardMat) { var xnIsObtainable = xnCardMat.SelectSingleNode("isobtainable"); if (xnIsObtainable != null) { if (bool.TryParse(xnIsObtainable.Value, out bool value)) IsObtainable = value; } foreach (XmlNode xnCard in xnCardMat.SelectNodes("cards/card")) { var type = Type.GetType(xnCard.Attributes?["type"].Value); Add(Card.CreateInstance(type)); } } } public class CardMats : SerializableDictionary { public delegate void CardMatsChangedEventHandler(object sender, CardMatsChangedEventArgs e); public event CardMatsChangedEventHandler CardMatsChanged; public void Add(IPlayer player, Type cardMatType, IEnumerable cards) { if (!ContainsKey(cardMatType)) { this[cardMatType] = CardMat.CreateInstance(cardMatType); this[cardMatType].Init(player); CardMatsChanged?.Invoke(this, new CardMatsChangedEventArgs(this[cardMatType], player, CardMatsChangedEventArgs.Operation.Created)); } var cardList = cards as IList ?? cards.ToList(); this[cardMatType].AddRange(player, cardList); if (CardMatsChanged != null) { var pcea = new CardMatsChangedEventArgs(this[cardMatType], player, CardMatsChangedEventArgs.Operation.Added, cardList); CardMatsChanged(this, pcea); } } public CardCollection Retrieve(IPlayer player, Type cardMatType, Predicate match, int count) { var c = ContainsKey(cardMatType) ? this[cardMatType] : CardMat.CreateInstance(cardMatType); var cc = c.Retrieve(player, DeckPosition.Automatic, match, count); if (CardMatsChanged != null) { var pcea = new CardMatsChangedEventArgs(this[cardMatType], player, CardMatsChangedEventArgs.Operation.Removed, cc); CardMatsChanged(this, pcea); } return cc; } internal void TearDown(IGame game) { foreach (var mat in Values) mat.TearDown(game); } internal XmlNode GenerateXml(XmlDocument doc, string nodeName) { var xeCardMats = doc.CreateElement(nodeName); foreach (var kvpCardMat in this) xeCardMats.AppendChild(kvpCardMat.Value.GenerateXml(doc)); return xeCardMats; } internal void Load(XmlNode xnCardMats) { if (xnCardMats == null) return; foreach (XmlNode xnCardMat in xnCardMats.SelectNodes("cardmat")) { var cardMat = CardMat.Load(xnCardMat); Add(cardMat.GetType(), cardMat); } } } }