using System;
namespace Neo.Afx.Services
{
///
/// The poll time is specified as d.hh:mm:ss where seconds are always ignored.
/// Hours and minutes are used to specify the time of day for all frequencies.
/// If the poll frequency is then
/// days refers to the day of week and must be a number between zero (Sun) and 6 (Sat).
/// If the poll frequency is then
/// days refers to the day of month. Otherwise days are ignored.
///
public class ServiceSchedule
{
readonly int _pollDays;
readonly int _pollHours;
readonly int _pollMinutes;
readonly int _pollSeconds;
#region Initialization
///
/// Initializes a new instance of the class.
///
/// The poll frequency.
/// The poll time specified as d.hh:mm:ss
public ServiceSchedule(PollFrequencyEnum pollFrequency, TimeSpan pollTime)
{
PollFrequency = pollFrequency;
_pollDays = pollTime.Days;
_pollHours = pollTime.Hours;
_pollMinutes = pollTime.Minutes;
_pollSeconds = pollTime.Seconds;
switch (pollFrequency)
{
case PollFrequencyEnum.Weekly:
if(_pollDays < (int)DayOfWeek.Sunday)
{
_pollDays = (int)DayOfWeek.Sunday;
}
else if(_pollDays > (int)DayOfWeek.Saturday)
{
_pollDays = (int)DayOfWeek.Saturday;
}
break;
case PollFrequencyEnum.Monthly:
if(_pollDays < 1)
{
_pollDays = 1;
}
else if(_pollDays > 31)
{
_pollDays = 31;
}
break;
}
}
#endregion
#region PollFrequency
///
/// Gets the poll frequency.
///
public PollFrequencyEnum PollFrequency
{
get;
private set;
}
#endregion
#region LastRunTime
///
/// Gets or sets the last run time.
///
public DateTime LastRunTime
{
get;
set;
}
#endregion
#region NextRunTime
///
/// Calculates the next run time based on the .
///
/// The signal time.
/// The next run time.
public DateTime NextRunTime(DateTime signalTime)
{
double offset;
var nextTime = signalTime;
switch(PollFrequency)
{
case PollFrequencyEnum.Seconds:
nextTime = new DateTime(LastRunTime.Year, LastRunTime.Month, LastRunTime.Day, LastRunTime.Hour, LastRunTime.Minute, LastRunTime.Second);
break;
case PollFrequencyEnum.Minutes:
nextTime = new DateTime(LastRunTime.Year, LastRunTime.Month, LastRunTime.Day, LastRunTime.Hour, LastRunTime.Minute, 0);
break;
case PollFrequencyEnum.Hourly:
nextTime = new DateTime(LastRunTime.Year, LastRunTime.Month, LastRunTime.Day, LastRunTime.Hour, _pollMinutes, 0);
break;
case PollFrequencyEnum.Daily:
nextTime = new DateTime(LastRunTime.Year, LastRunTime.Month, LastRunTime.Day, _pollHours, _pollMinutes, 0);
break;
case PollFrequencyEnum.Weekly:
nextTime = new DateTime(LastRunTime.Year, LastRunTime.Month, LastRunTime.Day, _pollHours, _pollMinutes, 0);
offset = (int)nextTime.DayOfWeek - _pollDays;
nextTime = nextTime.AddDays(-offset);
break;
case PollFrequencyEnum.Monthly:
nextTime = new DateTime(LastRunTime.Year, LastRunTime.Month, 1, _pollHours, _pollMinutes, 0);
var maxDays = DateTime.DaysInMonth(nextTime.Year, nextTime.Month);
offset = Math.Min(_pollDays, maxDays);
nextTime = nextTime.AddDays(offset - 1);
break;
}
if(nextTime == signalTime)
{
return signalTime;
}
if(nextTime > signalTime)
{
return nextTime;
}
// next < signalTime i.e.
// next run time has already elapsed
// so increment to the next interval
switch(PollFrequency)
{
case PollFrequencyEnum.Seconds:
return nextTime.AddSeconds(_pollSeconds);
case PollFrequencyEnum.Minutes:
return nextTime.AddMinutes(_pollMinutes);
case PollFrequencyEnum.Hourly:
return nextTime.AddHours(1);
case PollFrequencyEnum.Daily:
return nextTime.AddDays(1);
case PollFrequencyEnum.Weekly:
return nextTime.AddDays(7);
case PollFrequencyEnum.Monthly:
return nextTime.AddMonths(1);
}
return signalTime;
}
#endregion
#region IsDue
///
/// Determines if the schedule is due in the given time frame.
///
/// The begin time.
/// The end time.
/// true if the schedule is due; false otherwise.
public bool IsDue(DateTime begin, DateTime end)
{
var next = NextRunTime(begin);
return next <= end;
}
#endregion
}
}