using System; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Linq; using System.Xml; using DominionBase.Cards; using DominionBase.Players; namespace DominionBase { public class TokenCollectionsChangedEventArgs : EventArgs { public enum Operation { Reset, Added, Removed } public TokenCollection AddedTokens { get; } = new TokenCollection(); public TokenCollection RemovedTokens { get; } = new TokenCollection(); public Operation OperationPerformed { get; } public TokenCollection TokenCollection { get; } public IPlayer Player { get; } public int Count => TokenCollection.Count; public TokenCollectionsChangedEventArgs(TokenCollection tokenCollection, Operation operation) { TokenCollection = tokenCollection; OperationPerformed = operation; } public TokenCollectionsChangedEventArgs(TokenCollection tokenCollection, Operation operation, Token tokenChanged) : this(tokenCollection, null, operation, tokenChanged) { } public TokenCollectionsChangedEventArgs(TokenCollection tokenCollection, Operation operation, IEnumerable tokensChanged) : this(tokenCollection, null, operation, tokensChanged) { } public TokenCollectionsChangedEventArgs(TokenCollection tokenCollection, IPlayer player, Operation operation) : this(tokenCollection, operation) { Player = player; } public TokenCollectionsChangedEventArgs(TokenCollection tokenCollection, IPlayer player, Operation operation, Token tokenChanged) : this(tokenCollection, player, operation) { switch (operation) { case Operation.Added: AddedTokens.Add(tokenChanged); break; case Operation.Removed: RemovedTokens.Add(tokenChanged); break; } } public TokenCollectionsChangedEventArgs(TokenCollection tokenCollection, IPlayer player, Operation operation, IEnumerable tokensChanged) : this(tokenCollection, player, operation) { switch (operation) { case Operation.Added: AddedTokens.AddRange(tokensChanged); break; case Operation.Removed: RemovedTokens.AddRange(tokensChanged); break; } } } public class TokenActionEventArgs : EventArgs { public IPlayer Actor { get; } public IPlayer Actee { get; } public Card ActingCard { get; } public List HandledBy { get; } = new List(); public bool Cancelled { get; set; } = false; public TokenActionEventArgs(IPlayer actor, IPlayer actee, Card actingCard) { Actor = actor; Actee = actee; ActingCard = actingCard; } } public abstract class Token : IGameObject { public delegate void TokenActionEventHandler(object sender, TokenActionEventArgs e); protected Token(string displayString, string longDisplayString) { DisplayString = displayString; LongDisplayString = longDisplayString; } public virtual string DisplayString { get; } public virtual string LongDisplayString { get; } #region IGameObject properties public virtual string Name => GetType().Name; public virtual string ImageName => Type.Name; public Type Type => GetType(); #endregion public virtual string Title => Name; public virtual bool Buying(ITable table, IPlayer player) { return false; } public virtual bool Gaining() { return false; } public virtual bool ActDefined => false; public virtual bool IsTemporary => false; public virtual bool IsPlayable => false; public virtual IEnumerable PlayablePhases => new List(); public Guid UniqueId { get; } = Guid.NewGuid(); /// /// Used internally by the base Card class -- Don't use this. /// /// /// internal virtual void Act(Card card, TokenActionEventArgs e) { } /// /// Used internally by the base Card class -- Don't use this. /// internal virtual void Play(IPlayer player, int count) { } internal virtual void AddedTo(ITableable tableItem) { } internal virtual void RemovedFrom(ITableable tableItem) { } /// /// Called when the Token should tear down any control -- used when it's not needed any more /// internal virtual void TearDown(IGame game) { } public static Token CreateInstance(Type type) { return (Token)Activator.CreateInstance(type); } internal XmlNode GenerateXml(XmlDocument doc, string nodeName) { var xe = doc.CreateElement(nodeName); xe.InnerText = GetType().ToString(); return xe; } internal static Token Load(XmlNode xnToken) { var tokenType = Type.GetType(xnToken.InnerText); return CreateInstance(tokenType); } } public class TokenCollection : List { public TokenCollection() { } internal TokenCollection(IEnumerable collection) : base(collection) { } internal void TearDown(IGame game) { foreach (var token in this) token.TearDown(game); } internal XmlNode GenerateXml(XmlDocument doc, string nodeName) { var xeTokens = doc.CreateElement(nodeName); foreach (var token in this) xeTokens.AppendChild(token.GenerateXml(doc, "token")); return xeTokens; } internal static TokenCollection Load(XmlNode xnTokens) { var tc = new TokenCollection(); tc.AddRange(from XmlNode xnToken in xnTokens.SelectNodes("token") select Token.Load(xnToken)); return tc; } } public class TokenCollections : SerializableDictionary { public delegate void TokenCollectionsChangedEventHandler(object sender, TokenCollectionsChangedEventArgs e); public event TokenCollectionsChangedEventHandler TokenCollectionsChanged; public new TokenCollection this[Type tokenType] { get { if (!ContainsKey(tokenType)) base[tokenType] = new TokenCollection(); return base[tokenType]; } set { base[tokenType] = value; } } public void Refresh(Type tokenType) { if (TokenCollectionsChanged != null) { var tccea = new TokenCollectionsChangedEventArgs(this[tokenType], TokenCollectionsChangedEventArgs.Operation.Reset); TokenCollectionsChanged(this, tccea); } } public void Add(Token token) { Contract.Requires(token != null, "token cannot be null"); var t = token.GetType(); this[t].Add(token); if (TokenCollectionsChanged != null) { var tccea = new TokenCollectionsChangedEventArgs(this[t], TokenCollectionsChangedEventArgs.Operation.Added, token); TokenCollectionsChanged(this, tccea); } } internal void Add(Token token, IPlayer player) { Contract.Requires(token != null, "token cannot be null"); var t = token.GetType(); this[t].Add(token); if (TokenCollectionsChanged != null) { var tccea = new TokenCollectionsChangedEventArgs(this[t], player, TokenCollectionsChangedEventArgs.Operation.Added, token); TokenCollectionsChanged(this, tccea); } } internal void AddCollection(TokenCollection tokens, IPlayer player) { var t = tokens.First().GetType(); this[t].AddRange(tokens); if (TokenCollectionsChanged != null) { var tccea = new TokenCollectionsChangedEventArgs(this[t], player, TokenCollectionsChangedEventArgs.Operation.Added, tokens); TokenCollectionsChanged(this, tccea); } } public Token Remove(Token token) { Contract.Requires(token != null, "token cannot be null"); var t = token.GetType(); this[t].Remove(token); if (TokenCollectionsChanged != null) { var tccea = new TokenCollectionsChangedEventArgs(this[t], TokenCollectionsChangedEventArgs.Operation.Removed, token); TokenCollectionsChanged(this, tccea); } return token; } public void Remove(IEnumerable tokens) { var t = tokens.First().GetType(); var tokensList = new List(tokens); this[t].RemoveAll(token => tokensList.Contains(token)); if (TokenCollectionsChanged != null) { var tccea = new TokenCollectionsChangedEventArgs(this[t], TokenCollectionsChangedEventArgs.Operation.Removed, tokensList); TokenCollectionsChanged(this, tccea); } } internal void Remove(Token token, IPlayer player) { var t = token.GetType(); this[t].Remove(token); if (TokenCollectionsChanged != null) { var tccea = new TokenCollectionsChangedEventArgs(this[t], player, TokenCollectionsChangedEventArgs.Operation.Removed, token); TokenCollectionsChanged(this, tccea); } } internal void Remove(IEnumerable tokens, IPlayer player) { var t = tokens.First().GetType(); this[t].RemoveAll(tokens.Contains); if (TokenCollectionsChanged != null) { var tccea = new TokenCollectionsChangedEventArgs(this[t], player, TokenCollectionsChangedEventArgs.Operation.Removed, tokens); TokenCollectionsChanged(this, tccea); } } internal bool IsAnyPlayable { get { return this.Any(kvp => kvp.Value.Any(t => t.IsPlayable)); } } internal void TearDown(IGame game) { foreach (var tokens in Values) tokens.TearDown(game); } internal XmlNode GenerateXml(XmlDocument doc, string nodeName) { var xeTokenPiles = doc.CreateElement(nodeName); foreach (var kvpTokenCollection in this) { var xeTokenPile = doc.CreateElement("tokenpile"); xeTokenPiles.AppendChild(xeTokenPile); var xe = doc.CreateElement("type"); xe.InnerText = kvpTokenCollection.Key.ToString(); xeTokenPile.AppendChild(xe); xeTokenPile.AppendChild(kvpTokenCollection.Value.GenerateXml(doc, "tokens")); } return xeTokenPiles; } internal void Load(XmlNode xnRoot) { foreach (XmlNode xnTokenPile in xnRoot.SelectNodes("tokenpile")) { var xnType = xnTokenPile.SelectSingleNode("type"); if (xnType == null) continue; var type = Type.GetType(xnType.InnerText); this[type] = TokenCollection.Load(xnTokenPile.SelectSingleNode("tokens")); if (TokenCollectionsChanged != null) { var tccea = new TokenCollectionsChangedEventArgs(this[type], TokenCollectionsChangedEventArgs.Operation.Added, this[type]); TokenCollectionsChanged(this, tccea); } } } } }