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();
}