using MultiversalDiplomacy.Adjudicate;
using MultiversalDiplomacy.Adjudicate.Decision;
using MultiversalDiplomacy.Model;
using MultiversalDiplomacy.Orders;
using NUnit.Framework;
namespace MultiversalDiplomacyTests;
///
/// An object that provides a view into an order's fate during a test case. This object is
/// stateless and provides data by encapsulating queries on the state of the origin test case
/// builder.
///
public abstract class OrderReference
{
protected TestCaseBuilder Builder { get; }
protected Order Order { get; }
public OrderReference(TestCaseBuilder builder, Order order)
{
this.Builder = builder;
this.Order = order;
}
///
/// The validation result for the order. Throws if validation has not occurred.
///
public OrderValidation Validation
{
get
{
if (this.Builder.ValidationResults == null)
{
throw new InvalidOperationException("Validation has not been done yet");
}
var orderValidation = this.Builder.ValidationResults.Where(v => this.Order == v.Order);
if (!orderValidation.Any())
{
throw new AssertionException($"Missing validation for {this.Order}");
}
return orderValidation.Single();
}
}
///
/// The order that replaced this order, if any. Throws if validation has not occurred.
///
public OrderValidation? Replacement
{
get
{
if (this.Builder.ValidationResults == null)
{
throw new InvalidOperationException("Validation has not been done yet");
}
if (this.Order is UnitOrder unitOrder)
{
var replacementOrder = this.Builder.ValidationResults.Where(
v => v.Order is UnitOrder uo && uo != unitOrder && uo.Unit == unitOrder.Unit);
if (replacementOrder.Any())
{
return replacementOrder.Single();
}
}
return null;
}
}
///
/// Returns an for the order that replaced this order.
///
public OrderReference GetReplacementReference()
where ReplacementOrderType : Order
{
if (this.Replacement == null)
{
throw new InvalidOperationException("This order was not replaced");
}
Assert.That(
this.Replacement.Order,
Is.AssignableTo(typeof(ReplacementOrderType)),
"Unexpected replacement order type");
ReplacementOrderType replacementOrder = (ReplacementOrderType)this.Replacement.Order;
return new(this.Builder, replacementOrder);
}
///
/// A list of all adjudication decisions related to this order. Throws if adjudication has not
/// occurred.
///
public List Adjudications
{
get
{
if (this.Builder.AdjudicationResults == null)
{
throw new InvalidOperationException("Adjudication has not been done yet");
}
var adjudications = this.Builder.AdjudicationResults.Where(ad => ad switch
{
IsDislodged dislodged => dislodged.Order == this.Order,
DoesMove moves => moves.Order == this.Order,
GivesSupport supports => supports.Order == this.Order,
HasPath path => path.Order == this.Order,
AttackStrength attack => attack.Order == this.Order,
DefendStrength defend => defend.Order == this.Order,
PreventStrength prevent => prevent.Order == this.Order,
HoldStrength hold => this.Order is UnitOrder unitOrder
? hold.Province == unitOrder.Unit.Location.Province
: false,
_ => false,
}).ToList();
return adjudications;
}
}
///
/// Returns an adjudication decision of a specified type for this order. Throws if adjudication
/// has not occurred.
///
public DecisionType GetDecision()
where DecisionType : AdjudicationDecision
{
var typeAdjudications = this.Adjudications.OfType();
Assert.That(typeAdjudications.Any(), Is.True, $"No {typeof(DecisionType)} decision found");
return typeAdjudications.Single();
}
///
/// If this order is a unit order and the unit was dislodged, the
/// representing the retreat. Throws if adjudication has not occurred.
///
public RetreatingUnit? Retreat
{
get
{
if (this.Builder.AdjudicationResults == null)
{
throw new InvalidOperationException("Adjudication has not been done yet");
}
if (this.Order is UnitOrder unitOrder)
{
var retreat = this.Builder.World.RetreatingUnits.Where(
ru => ru.Unit == unitOrder.Unit);
if (retreat.Any())
{
return retreat.Single();
}
}
return null;
}
}
}
///
/// An object that provides a view into an order's fate during a test case. This object is
/// stateless and provides data by encapsulating queries on the state of the origin test case
/// builder.
///
public class OrderReference : OrderReference where OrderType : Order
{
///
/// The order.
///
new public OrderType Order { get; }
public OrderReference(TestCaseBuilder builder, OrderType order)
: base(builder, order)
{
this.Order = order;
}
}