This repository has been archived on 2023-02-02. You can view files and clone it, but cannot push or open issues or pull requests.
mfgames-nitride-cil/src/MfGames.Nitride.Calendar/CreateCalender.cs

119 lines
3.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using FluentValidation;
using Ical.Net.CalendarComponents;
using Ical.Net.DataTypes;
using Ical.Net.Serialization;
using MfGames.Gallium;
using MfGames.Nitride.Contents;
using MfGames.Nitride.Generators;
using MfGames.Nitride.Temporal;
using NodaTime;
using Zio;
namespace MfGames.Nitride.Calendar;
/// <summary>
/// Creates an iCalendar file from all the entities passed into the method
/// that have a NodaTime.Instant component. This will write both past and
/// future events.
/// </summary>
[WithProperties]
public partial class CreateCalender : OperationBase
{
private readonly TimeService clock;
private readonly IValidator<CreateCalender> validator;
public CreateCalender(
IValidator<CreateCalender> validator,
TimeService clock)
{
this.validator = validator;
this.clock = clock;
}
/// <summary>
/// Gets or sets a callback to get the summary of the event representing
/// the entity.
/// </summary>
public Func<Entity, string>? GetEventSummary { get; set; }
/// <summary>
/// Gets or sets a callback to get the optional URL of an event for
/// the entity.
/// </summary>
public Func<Entity, Uri?>? GetEventUrl { get; set; }
/// <summary>
/// Gets or sets the file system path for the resulting calendar.
/// </summary>
public UPath? Path { get; set; }
/// <inheritdoc />
public override IEnumerable<Entity> Run(
IEnumerable<Entity> input,
CancellationToken cancellationToken = default)
{
this.validator.ValidateAndThrow(this);
SplitEntityEnumerations split = input.SplitEntity<Instant>();
IEnumerable<Entity> datedAndCalendars =
this.CreateCalendarEntity(split.HasAll);
return datedAndCalendars.Union(split.NotHasAll);
}
private IEnumerable<Entity> CreateCalendarEntity(
IEnumerable<Entity> entities)
{
// Create the calendar in the same time zone as the rest of the system.
var calendar = new Ical.Net.Calendar();
calendar.TimeZones.Add(new VTimeZone(this.clock.DateTimeZone.Id));
// Go through the events and add all of them.
var input = entities.ToList();
IEnumerable<CalendarEvent> events =
input.Select(this.CreateCalendarEvent);
calendar.Events.AddRange(events);
// Create the iCalendar file.
var serializer = new CalendarSerializer();
string serializedCalendar = serializer.SerializeToString(calendar);
// Create the calendar entity and populate everything.
Entity calendarEntity = new Entity().Set(IsCalendar.Instance)
.Set(this.Path!.Value)
.SetTextContent(serializedCalendar);
// Return the results along with the new calendar.
return input.Union(new[] { calendarEntity });
}
private CalendarEvent CreateCalendarEvent(Entity entity)
{
Instant instant = entity.Get<Instant>();
var when = this.clock.ToDateTime(instant);
string summary = this.GetEventSummary!(entity);
Uri? url = this.GetEventUrl?.Invoke(entity);
var calendarEvent = new CalendarEvent
{
Summary = summary,
Start = new CalDateTime(when),
Url = url,
};
return calendarEvent;
}
}