using System; using System.Diagnostics.Contracts; using DominionBase.Currencies; namespace DominionBase.Cards { [Serializable] public class Cost : IComparable, IDisposable { private readonly Currency _cost = new Currency(); public Cost() { } public Cost(Currency cost, bool special = false, bool canOverpay = false) { Contract.Requires(cost != default(Currency), "cost cannot be null"); if (cost.Coin != null) _cost.Coin = cost.Coin; if (cost.Potion != null) _cost.Potion = cost.Potion; if (cost.Debt != null) _cost.Debt = cost.Debt; Special = special; CanOverpay = canOverpay; } public Cost(Coin coinCost, Potion potionCost = null, Debt debtCost = null, bool special = false, bool canOverpay = false) : this(new Currency(coinCost, potionCost, debtCost), special, canOverpay) { } public Cost(int coinCost = 0, int potionCost = 0, int debtCost = 0, bool special = false, bool canOverpay = false) { _cost.Coin = new Coin(coinCost); _cost.Potion = new Potion(potionCost); _cost.Debt = new Debt(debtCost); Special = special; CanOverpay = canOverpay; } public Cost Clone() { return new Cost(_cost.Coin, _cost.Potion, _cost.Debt, Special, CanOverpay); } #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.Dispose(); } // 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; } } ~Cost() { Dispose(false); } #endregion public Coin Coin { get { return _cost.Coin; } set { _cost.Coin = value; } } public Potion Potion { get { return _cost.Potion; } set { _cost.Potion = value; } } public Debt Debt { get { return _cost.Debt; } set { _cost.Debt = value; } } public bool Special { get; } public bool CanOverpay { get; } public override string ToString() { return ToString(string.Empty); } public string ToString(string separator) { var s = Coin.ToString(); if (Potion.Value > 0) { if (Coin.Value == 0) s = string.Empty; else s += separator; s += Potion.ToString(); } if (Debt.Value > 0) { if (Coin.Value == 0) s = string.Empty; else s += separator; s += Debt.ToString(); } return s; } public override int GetHashCode() { return Coin.GetHashCode() + 13 * Potion.GetHashCode() + 17 * Debt.GetHashCode(); } public static Cost operator +(Cost x, Cost y) { Contract.Requires(x != default(Cost), "x cannot be null"); Contract.Requires(y != default(Cost), "y cannot be null"); var c = new Cost(x.Coin, x.Potion, x.Debt); c.Coin += y.Coin; c.Potion += y.Potion; c.Debt += y.Debt; return c; } public static Cost Add(Cost left, Cost right) { return left + right; } public static Cost operator -(Cost x, Cost y) { Contract.Requires(x != default(Cost), "x cannot be null"); Contract.Requires(y != default(Cost), "y cannot be null"); var c = new Cost(x.Coin, x.Potion, x.Debt); c.Coin -= y.Coin; c.Potion -= y.Potion; c.Debt -= y.Debt; return c; } public static Cost Subtract(Cost left, Cost right) { return left - right; } public static Cost operator +(Cost x, Currency y) { Contract.Requires(x != default(Cost), "x cannot be null"); Contract.Requires(y != default(Currency), "y cannot be null"); var c = new Cost(x.Coin, x.Potion, x.Debt); c.Coin += y.Coin; c.Potion += y.Potion; c.Debt += y.Debt; return c; } public static Cost operator -(Cost x, Currency y) { Contract.Requires(x != default(Cost), "x cannot be null"); Contract.Requires(y != default(Currency), "y cannot be null"); var c = new Cost(x.Coin, x.Potion, x.Debt); c.Coin -= y.Coin; c.Potion -= y.Potion; c.Debt -= y.Debt; return c; } public static Cost operator +(Cost x, Coin y) { Contract.Requires(x != default(Cost), "x cannot be null"); var c = new Cost(x.Coin, x.Potion, x.Debt); c.Coin += y; return c; } public static Cost operator -(Cost x, Coin y) { Contract.Requires(x != default(Cost), "x cannot be null"); var c = new Cost(x.Coin, x.Potion, x.Debt); c.Coin -= y; return c; } public static Cost operator +(Cost x, Potion y) { Contract.Requires(x != default(Cost), "x cannot be null"); var c = new Cost(x.Coin, x.Potion, x.Debt); c.Potion += y; return c; } public static Cost operator -(Cost x, Potion y) { Contract.Requires(x != default(Cost), "x cannot be null"); var c = new Cost(x.Coin, x.Potion, x.Debt); c.Potion -= y; return c; } public static Cost operator +(Cost x, Debt y) { Contract.Requires(x != default(Cost), "x cannot be null"); var c = new Cost(x.Coin, x.Potion, x.Debt); c.Debt += y; return c; } public static Cost operator -(Cost x, Debt y) { Contract.Requires(x != default(Cost), "x cannot be null"); var c = new Cost(x.Coin, x.Potion, x.Debt); c.Debt -= y; return c; } public static bool operator ==(Cost x, Cost y) { if (ReferenceEquals(x, y)) return true; // If one is null, but not both, return false. if (((object)x == null) || ((object)y == null)) return false; return x.Equals(y); } public static bool operator !=(Cost x, Cost y) { return !(x == y); } public static bool operator ==(Cost x, Currency y) { // If one is null, but not both, return false. if ((x is null) || (y is null)) return false; return x.Equals(y); } public static bool operator !=(Cost x, Currency y) { return !(x == y); } public static bool operator <(Cost x, Cost y) { Contract.Requires(x != default(Cost), "x cannot be null"); Contract.Requires(y != default(Cost), "y cannot be null"); return (x.Coin < y.Coin && x.Potion == y.Potion && x.Debt == y.Debt) || (x.Coin == y.Coin && x.Potion < y.Potion && x.Debt == y.Debt) || (x.Coin == y.Coin && x.Potion == y.Potion && x.Debt < y.Debt) || (x.Coin < y.Coin && x.Potion < y.Potion && x.Debt == y.Debt) || (x.Coin < y.Coin && x.Potion == y.Potion && x.Debt < y.Debt) || (x.Coin == y.Coin && x.Potion < y.Potion && x.Debt < y.Debt) || (x.Coin < y.Coin && x.Potion < y.Potion && x.Debt < y.Debt); } public static bool operator >(Cost x, Cost y) { return y < x; } public static bool operator <(Cost x, Currency y) { Contract.Requires(x != default(Cost), "x cannot be null"); Contract.Requires(y != default(Currency), "y cannot be null"); return (x.Coin < y.Coin && x.Potion == y.Potion && x.Debt == y.Debt) || (x.Coin == y.Coin && x.Potion < y.Potion && x.Debt == y.Debt) || (x.Coin == y.Coin && x.Potion == y.Potion && x.Debt < y.Debt) || (x.Coin < y.Coin && x.Potion < y.Potion && x.Debt == y.Debt) || (x.Coin < y.Coin && x.Potion == y.Potion && x.Debt < y.Debt) || (x.Coin == y.Coin && x.Potion < y.Potion && x.Debt < y.Debt) || (x.Coin < y.Coin && x.Potion < y.Potion && x.Debt < y.Debt); } public static bool operator >(Cost x, Currency y) { return y < x; } public static bool operator <=(Cost x, Cost y) { return x == y || x < y; } public static bool operator >=(Cost x, Cost y) { return x == y || x > y; } public static bool operator <=(Cost x, Currency y) { return x == y || x < y; } public static bool operator >=(Cost x, Currency y) { return x == y || x > y; } public static bool operator <=(Cost x, Coin y) { if (x is null) throw new ArgumentNullException(nameof(x)); return x.Coin <= y && x.Potion <= 0 && x.Debt <= 0; } public static bool operator >=(Cost x, Coin y) { if (x is null) throw new ArgumentNullException(nameof(x)); return x.Coin >= y && x.Potion >= 0 && x.Debt >= 0; } public override bool Equals(object obj) { if (obj is Cost oCost) return Coin.Equals(oCost.Coin) && Potion.Equals(oCost.Potion) && Debt.Equals(oCost.Debt); if (obj is Currency oCurr) return Coin.Equals(oCurr.Coin) && Potion.Equals(oCurr.Potion) && Debt.Equals(oCurr.Debt); return false; } public int CompareTo(object obj) { return CompareTo(obj as Cost); } internal int CompareTo(Cost other) { // Check for null if (other is null) return -1; // Check for same reference if (ReferenceEquals(this, other)) return 0; var output = 0; using (var cur = new Currency(Coin, debt: Debt)) using (var oCur = new Currency(other.Coin, debt: other.Debt)) { if (cur == oCur) { if (Coin == other.Coin) return Potion == other.Potion ? Debt.CompareTo(other.Debt) : Potion.CompareTo(other.Potion); return Coin.CompareTo(other.Coin); } output = cur.CompareTo(oCur); } return output; } } }