using System; using System.Collections.Generic; using System.Linq; using System.Threading; using FluentValidation; using MfGames.Gallium; using MfGames.Nitride.Generators; namespace MfGames.Nitride.Temporal.Schedules; /// /// Applies schedules against the list of entities. /// [WithProperties] public partial class ApplySchedules : OperationBase { private readonly IValidator validator; public ApplySchedules( IValidator validator, TimeService timeService) { this.TimeService = timeService; this.validator = validator; } /// /// Gets or sets the callback to get the schedules for the entity. This is /// used to allow for per-entity schedules or generic schedules across /// the entire system. If this returns null, then no schedule will be /// applied. /// public Func?>? GetSchedules { get; set; } /// /// Gets or sets the time service associated with this operation. /// public TimeService TimeService { get; set; } /// public override IEnumerable Run( IEnumerable input, CancellationToken cancellationToken = default) { this.validator.ValidateAndThrow(this); return input.Select(this.Apply); } public ApplySchedules WithGetSchedules( Func?> value) where TType : ISchedule { this.GetSchedules = entity => value? .Invoke(entity) ?.Cast() .ToList(); return this; } private Entity Apply(Entity entity) { // Get the schedule for this entity. IList? schedules = this.GetSchedules?.Invoke(entity); if (schedules == null || schedules.Count == 0) { return entity; } // Otherwise, apply the schedules to this entity. foreach (ISchedule schedule in schedules) { if (!schedule.CanApply(entity)) { continue; } entity = schedule.Apply(entity, this.TimeService); } return entity; } }