// Copyright Epic Games, Inc. All Rights Reserved.
using System;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
namespace EpicGames.Horde.Utilities
{
///
/// Parses a time of day into a number of minutes since midnight
///
public class TimeOfDayJsonConverter : JsonConverter
{
///
public override TimeSpan Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return Parse(reader.GetString());
}
///
public override void Write(Utf8JsonWriter writer, TimeSpan value, JsonSerializerOptions options)
{
writer.WriteStringValue($"{value.Hours}:{value.Minutes}");
}
///
/// Parse a string as a number of minutes since midnight
///
public static TimeSpan Parse(string? text)
{
if (String.IsNullOrEmpty(text))
{
ThrowInvalidTimeException(text);
}
Match match = Regex.Match(text, @"(?[0-9]+)(?:[.:](?[0-9]+))?\s*(?am|pm)?$", RegexOptions.IgnoreCase);
if (!match.Success)
{
ThrowInvalidTimeException(text);
}
int hours = Int32.Parse(match.Groups["hours"].Value);
// Parse the number of minutes
int minutes = 0;
Group minutesGroup = match.Groups["minutes"];
if (minutesGroup.Success)
{
minutes = Int32.Parse(minutesGroup.Value);
if (minutes >= 60)
{
ThrowInvalidTimeException(text);
}
}
// Handle 12h/24h suffix
Group morningGroup = match.Groups["morning"];
if (morningGroup.Success)
{
if (hours == 12)
{
hours = 0;
}
else if (hours == 0 || hours > 12)
{
ThrowInvalidTimeException(text);
}
if (String.Equals(morningGroup.Value, "pm", StringComparison.OrdinalIgnoreCase))
{
hours += 12;
}
}
else
{
if (hours >= 24)
{
ThrowInvalidTimeException(text);
}
}
return new TimeSpan(hours, minutes, 0);
}
[DoesNotReturn]
static void ThrowInvalidTimeException(string? text)
{
throw new FormatException($"Unable to parse schedule time value '{text ?? "(null)"}'");
}
}
}