using System; using UnityEngine.UIElements; namespace KitsuneCafe.System { public enum TimeUnit : byte { Ticks, Milliseconds, Seconds, Minutes, Hours, Days } public readonly struct Duration : IComparable, IComparable, IComparable, IEquatable, IEquatable { public readonly long Value; private readonly TimeUnit unit; public Duration(long ticks, TimeUnit unit) { Value = ticks; this.unit = unit; } public Duration(long ticks) : this(ticks, TimeUnit.Ticks) { } public static implicit operator TimeSpan(Duration duration) => duration.AsTimeSpan(); public static implicit operator TimeValue(Duration duration) => duration.AsTimeValue(); public readonly TimeSpan AsTimeSpan() => new(Value); public readonly TimeValue AsTimeValue() => new(Into(TimeUnit.Seconds)); public static Duration From(long value, TimeUnit unit) { var ticks = unit switch { TimeUnit.Ticks => value, TimeUnit.Milliseconds => TimeSpan.TicksPerMillisecond * value, TimeUnit.Seconds => TimeSpan.TicksPerSecond * value, TimeUnit.Minutes => TimeSpan.TicksPerMinute * value, TimeUnit.Hours => TimeSpan.TicksPerHour * value, TimeUnit.Days => TimeSpan.TicksPerHour * value, var x => throw new ArgumentException($"{x} is not a valid TimeUnit.") }; return new Duration(ticks, unit); } public static Duration From(double value, TimeUnit unit) { var ticks = unit switch { TimeUnit.Ticks => value, TimeUnit.Milliseconds => TimeSpan.TicksPerMillisecond * value, TimeUnit.Seconds => TimeSpan.TicksPerSecond * value, TimeUnit.Minutes => TimeSpan.TicksPerMinute * value, TimeUnit.Hours => TimeSpan.TicksPerHour * value, TimeUnit.Days => TimeSpan.TicksPerHour * value, var x => throw new ArgumentException($"{x} is not a valid TimeUnit.") }; return new Duration(Convert.ToInt64(ticks), unit); } public long Into(TimeUnit unit) { return unit switch { TimeUnit.Ticks => Value, TimeUnit.Milliseconds => Value / TimeSpan.TicksPerMillisecond, TimeUnit.Seconds => Value / TimeSpan.TicksPerSecond, TimeUnit.Minutes => Value / TimeSpan.TicksPerMinute, TimeUnit.Hours => Value / TimeSpan.TicksPerHour, TimeUnit.Days => Value / TimeSpan.TicksPerHour, var x => throw new ArgumentException($"{x} is not a valid TimeUnit.") }; } public int CompareTo(object obj) { return obj switch { Duration d => CompareTo(d), TimeSpan ts => CompareTo(ts), var value => throw new ArgumentException($"{value} is not a Duration or TimeSpan") }; } public static bool Equals(Duration a, Duration b) { return a.Value == b.Value; } public static int Compare(Duration a, Duration b) { return a.Value.CompareTo(b.Value); } public int CompareTo(Duration other) { return Compare(this, other); } public int CompareTo(TimeSpan other) { return TimeSpan.Compare(this, other); } public bool Equals(Duration other) { return Equals(this, other); } public bool Equals(TimeSpan other) { return other.Equals(this); } public override bool Equals(object obj) { return (obj is Duration d && Equals(this, d)) || (obj is TimeSpan ts && Equals(this, ts)); } public override int GetHashCode() { return HashCode.Combine(Value); } public override string ToString() { return $"{Value} {nameof(unit)}"; } } }