using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;
using System.Xml;
using DominionBase.Enums;
using DominionBase.Piles;
using DominionBase.Players;
namespace DominionBase.Cards
{
///
/// This is the standard abstract class for defining an event and declaring what it is, what happens when it is played, and what benefits it may provide.
/// See the standard constructor for more detailed information about basic setup.
///
public abstract class Event : IComparable, IBuyable, IRandomizable, IDisposable
{
public virtual event PileChangedEventHandler PileChanged;
public virtual event BuyCheckEventHandler BuyCheck;
public virtual event TokensChangedEventHandler TokensChanged;
private IGame _Game;
private string _ActionText = "";
private string _ExtraText = string.Empty;
private readonly Traits _Traits = Traits.Basic;
private Cost _Cost = new Cost(0);
private Cost _LastComputedCost;
protected bool _AsynchronousChanging { get; private set; }
protected PileChangedEventArgs _AsynchronousPileChangedEventArgs { get; private set; }
private CardBenefit _Benefit;
internal Event(Source source, int coinCost, Traits traits, Edition edition = Edition.All)
: this(source, new Cost(coinCost), traits, edition)
{
}
internal Event(Source source, Cost cost, Traits traits, Edition edition = Edition.All)
{
Name = ResourcesHelper.Get($"{source}_{Type.Name}_Name");
Source = source;
BaseCost = cost;
_Benefit = new CardBenefit();
if (traits == Traits.None)
_Traits = traits;
else
_Traits |= traits;
Edition = edition;
var text = ResourcesHelper.Get($"{source}_{Type.Name}_{Edition}_Text");
if (string.IsNullOrEmpty(text))
text = ResourcesHelper.Get($"{source}_{Type.Name}_Text");
Text = text;
SetupText = ResourcesHelper.Get($"{source}_{Type.Name}_Setup");
}
public void Init(IGame game, PlayerCollection players)
{
_Game = game;
}
public static Event CreateInstance(Type type)
{
return (Event)Activator.CreateInstance(type);
}
#region ICardBase variables, properties, & methods
public virtual Cost BaseCost
{
get { return _Cost; }
protected set
{
_Cost = value;
}
}
public Type BaseType => GetType();
public virtual Categories Category { get; } = Categories.Event;
public virtual bool HasCost => true;
public virtual bool HasVPs => false;
public virtual string SetupText { get; } = string.Empty;
public virtual Source Source { get; } = Source.All;
public string Text
{
get
{
var sb = new StringBuilder();
var sbBenefitText = new StringBuilder();
if (_Benefit.Any)
{
sbBenefitText.Append(_Benefit.Text);
}
if (!string.IsNullOrEmpty(_ActionText))
{
if (sb.Length > 0 && !_ActionText.StartsWith("
"))
{
sb.AppendLine();
sb.AppendLine();
}
sb.Append(_ActionText.Replace("", sbBenefitText.ToString()));
}
if (!string.IsNullOrEmpty(_ExtraText))
{
sb.Append("
");
sb.AppendLine();
sb.Append(_ExtraText);
}
return sb.ToString();
}
protected set
{
if (value == null)
value = string.Empty;
var strings = value.Split(new[] { "
" }, StringSplitOptions.None);
if (strings.Length > 0)
{
_ActionText = strings[0].Replace("", Environment.NewLine);
if (strings.Length > 1)
_ExtraText = strings[1].Replace("", Environment.NewLine);
}
if (!_ActionText.Contains(""))
_ActionText = $"{(string.IsNullOrEmpty(_ActionText) ? "" : Environment.NewLine)}{_ActionText}";
}
}
public virtual List GetSerializingTypes()
{
return new List();
}
#endregion
#region IDisposable variables, properties, & methods
// Track whether Dispose has been called.
private bool disposed;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if (!disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if (disposing)
{
// Dispose managed resources.
_Cost = null;
_Benefit = null;
}
// Call the appropriate methods to clean up
// unmanaged resources here.
// If disposing is false,
// only the following code is executed.
// Note disposing has been done.
disposed = true;
}
}
~Event()
{
Dispose(false);
}
#endregion
public virtual void CheckSetup(Preset preset, ITable table)
{
}
public virtual void CheckSetup(Preset preset, string cardName, IRandomizable card)
{
}
public virtual CardSettingCollection GenerateSettings()
{
return new CardSettingCollection();
}
public virtual void FinalizeSettings(CardSettingCollection settings)
{
}
public Guid UniqueId { get; } = Guid.NewGuid();
#region ITableable Properties
public virtual bool CanUndo => true;
public int Count => 1;
public Orientation Orientation { get; } = Orientation.Landscape;
public IDisplayable Randomizer => this;
public Type TableableType => Type;
public IEnumerable Types => new List { Type };
#endregion
public Type Type => GetType();
public string Name { get; protected set; }
public string ImageName => Type.Name;
public IDisplayable RootCard => this;
public IDisplayable DisplayCard => this;
public ICost TopCard => this;
public virtual Location Location { get; } = Location.LandscapeCard;
public virtual Traits Traits => _Traits;
public virtual string SpecialPresetKey => null;
public virtual bool IsStackable => false;
public virtual DisplayableCollection Stack() { return new DisplayableCollection { this }; }
public CardBack CardBack { get; } = CardBack.Standard;
public virtual CardBenefit Benefit => _Benefit;
public Edition Edition { get; internal set; }
#region IDisplayable
public virtual Facing Facing { get; private set; } = Facing.FaceUp;
#endregion
public virtual void Clear() { }
public virtual void End(IPlayer player, DisplayableCollection collection)
{
}
public void AddPlayer(IPlayer player)
{
Contract.Requires(player != null, "player cannot be null");
player.PhaseChanged += Player_PhaseChangedEvent;
player.PlayerModeChanged += Player_PlayerModeChangedEvent;
}
public void RemovePlayer(IPlayer player)
{
Contract.Requires(player != null, "player cannot be null");
player.PhaseChanged -= Player_PhaseChangedEvent;
player.PlayerModeChanged -= Player_PlayerModeChangedEvent;
}
void Player_PhaseChangedEvent(object sender, PhaseChangedEventArgs e)
{
PhaseChanged(sender, e);
}
void Player_PlayerModeChangedEvent(object sender, PlayerModeChangedEventArgs e)
{
PlayerModeChanged(sender, e);
}
internal virtual void PhaseChanged(object sender, PhaseChangedEventArgs e)
{
}
internal virtual void PlayerModeChanged(object sender, PlayerModeChangedEventArgs e)
{
}
public TokenCollection Tokens { get; } = new TokenCollection();
public void AddToken(Token token)
{
Tokens.Add(token);
if (TokensChanged != null)
{
var etcea = new TokensChangedEventArgs(token);
TokensChanged(this, etcea);
}
var pcea = new PileChangedEventArgs(Operation.Refresh);
if (_AsynchronousChanging)
_AsynchronousPileChangedEventArgs = pcea;
else
PileChanged?.Invoke(this, pcea);
}
public Token RemoveToken(Type tokenType)
{
var foundToken = Tokens.FirstOrDefault(t => t.GetType() == tokenType);
return foundToken != null ? RemoveToken(foundToken) : null;
}
public Token RemoveToken(Token token)
{
Tokens.Remove(token);
if (TokensChanged != null)
{
var etcea = new TokensChangedEventArgs(token);
TokensChanged(this, etcea);
}
var pcea = new PileChangedEventArgs(Operation.Refresh);
if (_AsynchronousChanging)
_AsynchronousPileChangedEventArgs = pcea;
else
PileChanged?.Invoke(this, pcea);
return token;
}
public int CompareTo(Event eventCard)
{
Contract.Requires(eventCard != default(Event), "eventCard cannot be null");
if (ReferenceEquals(this, eventCard))
return 0;
var nc = -BaseCost.CompareTo(eventCard.BaseCost);
if (nc == 0)
nc = string.Compare(Name, eventCard.Name, StringComparison.CurrentCulture);
if (nc == 0)
nc = UniqueId.CompareTo(eventCard.UniqueId);
return nc;
}
public int CompareTo(IDisplayable obj)
{
Contract.Requires(obj != default(ITableable), "obj cannot be null");
if (ReferenceEquals(this, obj))
return 0;
if (obj is Event oEvt)
return CompareTo(oEvt);
if (obj is Card || obj is ISupply)
return 1;
if (obj is Project || obj is Landmark || obj is State || obj is Boon || obj is Hex || obj is Artifact || obj is Way)
return -1;
var nc = string.Compare(Name, obj.Name, StringComparison.CurrentCulture);
if (nc == 0)
nc = UniqueId.CompareTo(obj.UniqueId);
return nc;
}
public int CompareTo(ITableable obj)
{
Contract.Requires(obj != default(ITableable), "obj cannot be null");
if (obj is IDisplayable oDisp)
return CompareTo(oDisp);
return string.Compare(Name, obj.Name, StringComparison.CurrentCulture);
}
public override string ToString()
{
return Name;
}
public Cost CurrentCost
{
get
{
var currentCost = _Game.ComputeCost(this);
if (_LastComputedCost == (Cost)null)
_LastComputedCost = currentCost;
if (_LastComputedCost != currentCost)
{
var pcea = new PileChangedEventArgs(Operation.Refresh);
if (_AsynchronousChanging)
_AsynchronousPileChangedEventArgs = pcea;
else
PileChanged?.Invoke(this, pcea);
}
_LastComputedCost = currentCost;
return currentCost;
}
}
public bool CanBuy(IPlayer player)
{
Contract.Requires(player != null, "player cannot be null");
return CanBuy(player, player.Currency);
}
public virtual bool CanBuy(IPlayer player, Currency currency)
{
Contract.Requires(player != null, "player cannot be null");
Contract.Requires(currency != default(Currency), "currency cannot be null");
if (currency.Coin >= CurrentCost.Coin && currency.Potion >= CurrentCost.Potion && !player.TokenPiles[Empires.TypeClass.DebtToken].Any())
{
if (BuyCheck != null)
{
var bcea = new BuyCheckEventArgs(player);
BuyCheck(this, bcea);
if (bcea.Cancelled)
return false;
}
return true;
}
return false;
}
public virtual void Bought(IPlayer player)
{
Contract.Requires(player != null, "player cannot be null");
player.ReceiveBenefit(this, Benefit, true);
}
public virtual void TearDown(IGame game)
{
}
public virtual void BeginChanges()
{
_AsynchronousChanging = true;
_AsynchronousPileChangedEventArgs = null;
}
public virtual void EndChanges()
{
_AsynchronousChanging = false;
if (_AsynchronousPileChangedEventArgs != null)
PileChanged?.Invoke(this, _AsynchronousPileChangedEventArgs);
_AsynchronousPileChangedEventArgs = null;
}
public virtual void Reset()
{
}
public void FullSetup()
{
Setup();
SnapshotSetup();
FinalizeSetup();
}
public virtual void Setup()
{
}
public virtual void SnapshotSetup()
{
}
public virtual void FinalizeSetup()
{
Finalize(_Game);
}
public virtual void Finalize(IGame game)
{
}
public XmlNode GenerateXml(XmlDocument doc)
{
Contract.Requires(doc != null, "doc cannot be null");
var xeEvent = doc.CreateElement("event");
return xeEvent;
}
public static Event Load(IGame game, XmlNode xnEntity)
{
Contract.Requires(xnEntity != null, "xnEntity cannot be null");
var xnType = xnEntity.SelectSingleNode("type");
if (xnType == null)
return null;
var type = Type.GetType(xnType.InnerText);
var @event = CreateInstance(type);
@event.Load(xnEntity);
return @event;
}
public void Load(XmlNode xnEntity)
{
if (xnEntity == null)
return;
var eventType = Type.GetType(xnEntity.Attributes["type"].Value);
var @event = CreateInstance(eventType);
//@event.LoadInstance(xnEntity);
}
}
}