using System;
using System.Collections.Generic;
using System.Threading;
using FluentValidation;
using MfGames.Gallium;
using MfGames.Nitride.Temporal.Validators;
using NodaTime;
namespace MfGames.Nitride.Temporal;
///
/// Sets the instant from another component. This has methods for handling
/// nullable properties inside the component.
///
public class SetInstantFromComponent : OperationBase
{
private readonly TimeService clock;
private readonly IValidator> validator;
public SetInstantFromComponent(TimeService clock)
{
// TODO: Figure out why Autofac won't let us register IValidator of generic classes.
this.validator = new SetInstantFromComponentValidator();
this.clock = clock;
}
///
/// The callback used to get a date time object which is converted into
/// an Instant automatically. This can handle DateTime, DateTimeOffset,
/// LocalDate, and Instant. Nulls are skipped.
///
public Func? GetDateTimeObject
{
get;
set;
}
///
public override IEnumerable Run(
IEnumerable input,
CancellationToken cancellationToken = default)
{
this.validator.ValidateAndThrow(this);
return input.SelectEntity(this.Set);
}
///
/// Sets the callback used to get a date time object which is converted
/// into an Instant automatically. This can handle DateTime,
/// DateTimeOffset, LocalDate, and Instant. Nulls are skipped.
///
public SetInstantFromComponent WithGetDateTimeObject(
Func? callback)
{
this.GetDateTimeObject = callback;
return this;
}
private Entity Set(
Entity entity,
TComponent component)
{
object? temporal = this.GetDateTimeObject!(entity, component);
Instant instant;
switch (temporal)
{
case null:
return entity;
case Instant direct:
instant = direct;
break;
case LocalDate other:
instant = this.clock.CreateInstant(other);
break;
case DateTime other:
instant = this.clock.CreateInstant(other);
break;
case DateTimeOffset other:
instant = this.clock.CreateInstant(other);
break;
default:
throw new InvalidOperationException(
"Did not get a date time object from the callback. "
+ "Can only handle DateTime, DateTimeOffset, LocalDate, "
+ "and Instant. Got a "
+ temporal.GetType()
.Name
+ " instead.");
}
return entity.Set(instant);
}
}