diff --git a/ICD.Common.Utils/Extensions/DateTimeExtensions.cs b/ICD.Common.Utils/Extensions/DateTimeExtensions.cs index 3bc2d63..77f0b14 100644 --- a/ICD.Common.Utils/Extensions/DateTimeExtensions.cs +++ b/ICD.Common.Utils/Extensions/DateTimeExtensions.cs @@ -1,5 +1,6 @@ using System; using System.Globalization; +using System.Linq; namespace ICD.Common.Utils.Extensions { @@ -28,5 +29,22 @@ namespace ICD.Common.Utils.Extensions // Todo - Better handle different cultures return extends.ToString("HH:mm:ss:fff"); } + + /// + /// Returns the closest DateTime to the target time that is greater than the target time + /// + /// + /// + /// + /// + public static DateTime? NextEarliestTime(this DateTime target, params DateTime[] times) + { + if (times.Length == 0) + return null; + + DateTime[] orderedTimes = times.OrderBy(dt => dt).ToArray(); + var time = orderedTimes.FirstOrDefault(dt => target < dt); + return time == default(DateTime) ? (DateTime?) null : time; + } } } diff --git a/ICD.Common.Utils/Extensions/DayOfWeekExtensions.cs b/ICD.Common.Utils/Extensions/DayOfWeekExtensions.cs new file mode 100644 index 0000000..3b3d3f2 --- /dev/null +++ b/ICD.Common.Utils/Extensions/DayOfWeekExtensions.cs @@ -0,0 +1,17 @@ +using System; + +namespace ICD.Common.Utils.Extensions +{ + public static class DayOfWeekExtensions + { + public static bool IsWeekday(this DayOfWeek day) + { + return !IsWeekend(day); + } + + public static bool IsWeekend(this DayOfWeek day) + { + return day == DayOfWeek.Saturday || day == DayOfWeek.Sunday; + } + } +} \ No newline at end of file diff --git a/ICD.Common.Utils/ICD.Common.Utils_SimplSharp.csproj b/ICD.Common.Utils/ICD.Common.Utils_SimplSharp.csproj index f1b77a5..ecb84b7 100644 --- a/ICD.Common.Utils/ICD.Common.Utils_SimplSharp.csproj +++ b/ICD.Common.Utils/ICD.Common.Utils_SimplSharp.csproj @@ -113,6 +113,7 @@ + diff --git a/ICD.Common.Utils/Services/Scheduler/AbstractScheduledAction.cs b/ICD.Common.Utils/Services/Scheduler/AbstractScheduledAction.cs new file mode 100644 index 0000000..0439f07 --- /dev/null +++ b/ICD.Common.Utils/Services/Scheduler/AbstractScheduledAction.cs @@ -0,0 +1,43 @@ +using System; +using ICD.Common.Utils.EventArguments; +using ICD.Common.Utils.Extensions; + +namespace ICD.Common.Utils.Services.Scheduler +{ + public abstract class AbstractScheduledAction : IScheduledAction + { + public event EventHandler OnScheduledRunTimeChanged; + + private DateTime? m_NextRunTime; + + public DateTime? NextRunTime + { + get { return m_NextRunTime; } + private set + { + if (m_NextRunTime == value) + return; + + m_NextRunTime = value; + + OnScheduledRunTimeChanged.Raise(this); + } + } + + public void Run() + { + RunFinal(); + NextRunTime = UpdateRunTime(); + } + + /// + /// Runs when the action has hit its scheduled time + /// + public abstract void RunFinal(); + + /// + /// Runs after RunFinal in order to set the next run time of this action + /// + public abstract DateTime? UpdateRunTime(); + } +} \ No newline at end of file diff --git a/ICD.Common.Utils/Services/Scheduler/ActionSchedulerService.cs b/ICD.Common.Utils/Services/Scheduler/ActionSchedulerService.cs index ca601d6..d98fb66 100644 --- a/ICD.Common.Utils/Services/Scheduler/ActionSchedulerService.cs +++ b/ICD.Common.Utils/Services/Scheduler/ActionSchedulerService.cs @@ -24,16 +24,10 @@ namespace ICD.Common.Utils.Services.Scheduler public void Dispose() { - foreach (IScheduledAction action in m_Actions) - { - Unsubscribe(action); + Clear(); - IDisposable disposable = action as IDisposable; - if (disposable != null) - disposable.Dispose(); - } - - m_Actions.Clear(); + m_Timer.Stop(); + m_Timer.Dispose(); } #region Methods @@ -50,6 +44,8 @@ namespace ICD.Common.Utils.Services.Scheduler { m_CriticalSection.Leave(); } + + RescheduleTimer(); } public void Remove(IScheduledAction action) @@ -64,6 +60,28 @@ namespace ICD.Common.Utils.Services.Scheduler { m_CriticalSection.Leave(); } + + RescheduleTimer(); + } + + public void Clear() + { + m_CriticalSection.Enter(); + try + { + foreach (IScheduledAction action in m_Actions) + { + Unsubscribe(action); + } + + m_Actions.Clear(); + } + finally + { + m_CriticalSection.Leave(); + } + + RescheduleTimer(); } public override string ToString() @@ -105,15 +123,25 @@ namespace ICD.Common.Utils.Services.Scheduler } } + RescheduleTimer(); + } + + private void RescheduleTimer() + { // enter again to check the closest next run time m_CriticalSection.Enter(); try { - var action = m_Actions.FirstOrDefault(); - if (action == null) + var action = m_Actions.FirstOrDefault(a => a.NextRunTime != null); + if (action == null || action.NextRunTime == null) + { + m_Timer.Stop(); return; + } - m_Timer.Reset((long)(DateTime.Now - action.NextRunTime).TotalMilliseconds); + long msToNextAction = (long)(DateTime.Now - action.NextRunTime.Value).TotalMilliseconds; + long timerDueTime = Math.Min(msToNextAction, MAX_TIMER_INTERVAL); + m_Timer.Reset(timerDueTime); } finally { @@ -169,6 +197,8 @@ namespace ICD.Common.Utils.Services.Scheduler { m_CriticalSection.Leave(); } + + RescheduleTimer(); } #endregion diff --git a/ICD.Common.Utils/Services/Scheduler/IScheduledAction.cs b/ICD.Common.Utils/Services/Scheduler/IScheduledAction.cs index de0f246..cacdfd6 100644 --- a/ICD.Common.Utils/Services/Scheduler/IScheduledAction.cs +++ b/ICD.Common.Utils/Services/Scheduler/IScheduledAction.cs @@ -1,4 +1,5 @@ using System; +using ICD.Common.Utils.EventArguments; namespace ICD.Common.Utils.Services.Scheduler { @@ -12,7 +13,7 @@ namespace ICD.Common.Utils.Services.Scheduler /// /// Gets the next time this action should be run /// - DateTime NextRunTime { get; } + DateTime? NextRunTime { get; } void Run(); }