601 lines
32 KiB
C#

#if FRAMEWORK20
using System;
using System.Collections.Generic;
using System.Text;
using System.Globalization;
namespace DevComponents.Schedule.Model
{
internal class RecurrenceGenerator : IRecurrenceGenerator
{
#region IRecurrenceGenerator Members
/// <summary>
/// Generates Daily recurring appointments. If appointment is assigned to calendar method must populate the Calendar.Appointments collection as well.
/// </summary>
/// <param name="subsetCollection">Collection to add generated recurrences to</param>
/// <param name="recurrence">Recurrence description, must be of Daily recurrence type.</param>
/// <param name="startDate">Start date for generation.</param>
/// <param name="endDate">End date for generation.</param>
public void GenerateDailyRecurrence(AppointmentSubsetCollection subsetCollection, AppointmentRecurrence recurrence, DateTime startDate, DateTime endDate)
{
Appointment app = recurrence.Appointment;
int appointmentDaysDuration = recurrence.Daily.ExplicitDailyRecurrence ? 0 : (int)Math.Max(0, Math.Ceiling(app.EndTime.Date.Subtract(app.StartTime.Date).TotalDays));
DateTime recurrenceStartDate = DateTimeHelper.MaxDate(recurrence.RecurrenceStartDate,
recurrence.Daily.ExplicitDailyRecurrence ? (app.StartTime.AddDays(1).Date) : (DateTimeHelper.IsBeginningOfDay(app.EndTime) ? app.EndTime : app.EndTime.AddDays(recurrence.Daily.RepeatInterval).Date));
if (recurrenceStartDate > endDate) return;
int repeats = 0;
// Check the range first
if (recurrence.RangeLimitType == eRecurrenceRangeLimitType.RangeEndDate)
{
if (startDate > recurrence.RangeEndDate) return;
}
else if (recurrence.RangeLimitType == eRecurrenceRangeLimitType.RangeNumberOfOccurrences)
{
DateTime rangeStartDate = DateTimeHelper.MaxDate(recurrence.RecurrenceStartDate,
recurrence.Daily.ExplicitDailyRecurrence ? (app.LocalStartTime.AddDays(1).Date) : (DateTimeHelper.IsBeginningOfDay(app.LocalEndTime) ? app.LocalEndTime : app.LocalEndTime.AddDays(recurrence.Daily.RepeatInterval).Date));
int totalDays = (int)Math.Ceiling(startDate.Subtract(rangeStartDate).TotalDays);
switch (recurrence.Daily.RepeatOnDaysOfWeek)
{
case eDailyRecurrenceRepeat.All:
repeats = Math.Max(0, totalDays / (recurrence.Daily.RepeatInterval + appointmentDaysDuration));
if (repeats >= recurrence.RangeNumberOfOccurrences)
return;
break;
case eDailyRecurrenceRepeat.WeekDays:
repeats = Math.Max(0, DateTimeHelper.TotalWeekDays(recurrenceStartDate, startDate) / (recurrence.Daily.RepeatInterval + appointmentDaysDuration));
// Assume weekdays repeat
if (repeats > recurrence.RangeNumberOfOccurrences)
return;
break;
default:
repeats = Math.Max(0, DateTimeHelper.TotalWeekDays(recurrenceStartDate, startDate));
repeats = Math.Max(0, totalDays - repeats);
// Assume weekend days repeat
if (repeats > recurrence.RangeNumberOfOccurrences)
return;
break;
}
//repeats = 0;
}
DateTime currentDay = recurrenceStartDate; // DateTimeHelper.MaxDate(startDate, recurrenceStartDate);
while (currentDay <= endDate)
{
if (currentDay >= startDate || currentDay < startDate && IsRecurringOnDay(currentDay, startDate, endDate, app))
{
if (!IsRecurringOnDay(currentDay, startDate, endDate, app)) break;
if (recurrence.Daily.RepeatOnDaysOfWeek == eDailyRecurrenceRepeat.All ||
(recurrence.Daily.RepeatOnDaysOfWeek == eDailyRecurrenceRepeat.WeekDays && !DateTimeHelper.IsWeekendDay(currentDay)) ||
(recurrence.Daily.RepeatOnDaysOfWeek == eDailyRecurrenceRepeat.WeekendDays && DateTimeHelper.IsWeekendDay(currentDay)))
{
if (!IsIgnoredRecurrence(currentDay, recurrence))
{
subsetCollection.Add(CreateRecurringAppointmentInstance(currentDay, app));
repeats++;
}
}
}
switch (recurrence.Daily.RepeatOnDaysOfWeek)
{
case eDailyRecurrenceRepeat.All:
currentDay = currentDay.AddDays(recurrence.Daily.RepeatInterval + appointmentDaysDuration);
break;
case eDailyRecurrenceRepeat.WeekDays:
//currentDay = currentDay.AddDays(currentDay.DayOfWeek == DayOfWeek.Saturday ? 2 : Math.Max(1, recurrence.Daily.RepeatInterval + appointmentDaysDuration));
currentDay = currentDay.AddDays(Math.Max(1, recurrence.Daily.RepeatInterval + appointmentDaysDuration)); // Changed for consistency
break;
case eDailyRecurrenceRepeat.WeekendDays:
while (true)
{
currentDay = currentDay.AddDays(1);
if (DateTimeHelper.IsWeekendDay(currentDay) == true)
break;
}
break;
}
if (recurrence.RangeLimitType == eRecurrenceRangeLimitType.RangeEndDate && currentDay >= recurrence.RangeEndDate ||
recurrence.RangeLimitType == eRecurrenceRangeLimitType.RangeNumberOfOccurrences && repeats >= recurrence.RangeNumberOfOccurrences)
break;
}
}
private static bool IsIgnoredRecurrence(DateTime currentDay, AppointmentRecurrence recurrence)
{
if (recurrence.SkippedRecurrences.Count == 0) return false;
foreach (DateTime date in recurrence.SkippedRecurrences)
{
if (date.Date == currentDay.Date)
return true;
}
return false;
}
private bool IsRecurringOnDay(DateTime currentDay, DateTime rangeStart, DateTime rangeEnd, Appointment rootAppointment)
{
TimeSpan duration = rootAppointment.EndTime.Subtract(rootAppointment.StartTime);
DateTime startTime = rootAppointment.GetValidDateTime(new DateTime(currentDay.Year, currentDay.Month, currentDay.Day, rootAppointment.StartTime.Hour, rootAppointment.StartTime.Minute, 0));
DateTime endTime = rootAppointment.GetValidDateTime(startTime.Add(duration));
DateTime localStartTime = rootAppointment.GetLocalDateTime(rootAppointment.GetUTCDateTime(startTime));
DateTime localEndTime = rootAppointment.GetLocalDateTime(rootAppointment.GetUTCDateTime(endTime));
// If time-zone is not used return false
//if (startTime == localStartTime) return currentDay >= rangeStart;
return DateTimeHelper.TimePeriodsOverlap(localStartTime, localEndTime, rangeStart, rangeEnd);
}
private DateTime GetAppointmentEndTime(DateTime currentDay, Appointment rootAppointment)
{
TimeSpan duration = rootAppointment.EndTime.Subtract(rootAppointment.StartTime);
DateTime startTime = rootAppointment.GetValidDateTime(new DateTime(currentDay.Year, currentDay.Month, currentDay.Day, rootAppointment.StartTime.Hour, rootAppointment.StartTime.Minute, 0));
DateTime endTime = rootAppointment.GetValidDateTime(startTime.Add(duration));
return endTime;
}
private Appointment CreateRecurringAppointmentInstance(DateTime currentDay, Appointment rootAppointment)
{
Appointment app = rootAppointment.Copy();
TimeSpan duration = rootAppointment.EndTime.Subtract(rootAppointment.StartTime);
DateTime startTime = app.GetValidDateTime(new DateTime(currentDay.Year, currentDay.Month, currentDay.Day, rootAppointment.StartTime.Hour, rootAppointment.StartTime.Minute, 0));
DateTime endTime = app.GetValidDateTime(startTime.Add(duration));
app.StartTime = startTime;
app.EndTime = endTime;
app.IsRecurringInstance = true;
app.RootAppointment = rootAppointment;
app.Tooltip = rootAppointment.Tooltip;
if (rootAppointment.Recurrence == null || !rootAppointment.Recurrence.IndependentVisibility)
app.Visible = rootAppointment.Visible;
foreach (Reminder reminder in app.Reminders)
{
//reminder.ReminderTime = app.StartTime.Add(reminder.ReminderTime.Subtract(rootAppointment.StartTime));
reminder.IsActive = true;
}
return app;
}
/// <summary>
/// Generates Weekly recurring appointments. If appointment is assigned to calendar method must populate the Calendar.Appointments collection as well.
/// </summary>
/// <param name="subsetCollection">Collection to add generated recurrences to</param>
/// <param name="recurrence">Recurrence description, must be of Weekly recurrence type.</param>
/// <param name="startDate">Start date for generation.</param>
/// <param name="endDate">End date for generation.</param>
public void GenerateWeeklyRecurrence(AppointmentSubsetCollection subsetCollection, AppointmentRecurrence recurrence, DateTime startDate, DateTime endDate)
{
Appointment app = recurrence.Appointment;
DateTime baseStartDate = app.EndTime.Date;
if (app.EndTime.Date > app.StartTime.Date && app.EndTime.TimeOfDay > app.StartTime.TimeOfDay && baseStartDate != DateTime.MinValue)
baseStartDate = baseStartDate.AddDays(1);
DateTime recurrenceStartDate = baseStartDate;
int repeatInterval = recurrence.Weekly.RepeatInterval;
if (RepeatsOnSingleDayOnly(recurrence.Weekly.RepeatOnDaysOfWeek) && !(app.StartTime.Date == startDate.Date && endDate.Date == startDate.Date))
{
recurrenceStartDate = baseStartDate.AddMilliseconds(-1).AddDays((repeatInterval) * 7 /*+ (recurrence.Weekly.RepeatInterval > 1 ? (8 - (int)baseStartDate.DayOfWeek) : 1)*/).Date;
if (recurrenceStartDate.DayOfWeek != GetDayOfWeek(recurrence.Weekly.RepeatOnDaysOfWeek))
{
DayOfWeek dayOfWeek = GetDayOfWeek(recurrence.Weekly.RepeatOnDaysOfWeek);
while (recurrenceStartDate.DayOfWeek != dayOfWeek)
recurrenceStartDate = recurrenceStartDate.AddDays(1);
}
}
else
{
if (app.EndTime.Date > app.StartTime.Date && app.EndTime.TimeOfDay < app.StartTime.TimeOfDay)
recurrenceStartDate = app.StartTime.Date.AddDays(1);
else
recurrenceStartDate = app.EndTime.Date.AddDays(1);
}
recurrenceStartDate = DateTimeHelper.MaxDate(recurrence.RecurrenceStartDate, recurrenceStartDate);
if (recurrenceStartDate > endDate) return;
int totalRecurrences = 0;
// Check the range first
if (recurrence.RangeLimitType == eRecurrenceRangeLimitType.RangeEndDate)
{
if (startDate > recurrence.RangeEndDate) return;
}
else if (recurrence.RangeLimitType == eRecurrenceRangeLimitType.RangeNumberOfOccurrences && repeatInterval == 1)
{
int totalDays = (int)Math.Ceiling(endDate.Subtract(recurrenceStartDate).TotalDays);
int occurrencesPerWeek = GetNumberOfDays(recurrence.Weekly.RepeatOnDaysOfWeek);
if (occurrencesPerWeek == 0)
throw new ArgumentException("Weekly recurrence must have at least single day selected using RepeatOnDaysOfWeek property.");
totalRecurrences = DateTimeHelper.TotalNumberOfDays(recurrenceStartDate, endDate, recurrence.Weekly.RepeatOnDaysOfWeek);
if (totalRecurrences > recurrence.RangeNumberOfOccurrences) return;
}
bool countTotalRecurrences = false;
if (repeatInterval > 1 && recurrence.RangeLimitType == eRecurrenceRangeLimitType.RangeNumberOfOccurrences)
countTotalRecurrences = true;
bool spansDays = app.StartTime.Day != app.EndTime.Day && endDate.Subtract(startDate).TotalDays <= 1;
DateTime currentDay = recurrenceStartDate;// DateTimeHelper.MaxDate(recurrenceStartDate, startDate);
while (currentDay <= endDate)
{
if ((currentDay >= startDate || spansDays && GetAppointmentEndTime(currentDay, app) >= startDate) && DateTimeHelper.HasDay(currentDay.DayOfWeek, recurrence.Weekly.RepeatOnDaysOfWeek) &&
!IsIgnoredRecurrence(currentDay, recurrence))
{
subsetCollection.Add(CreateRecurringAppointmentInstance(currentDay, app));
totalRecurrences++;
}
else if (countTotalRecurrences && currentDay < startDate && DateTimeHelper.HasDay(currentDay.DayOfWeek, recurrence.Weekly.RepeatOnDaysOfWeek)
&& !IsIgnoredRecurrence(currentDay, recurrence))
{
totalRecurrences++;
if (totalRecurrences >= recurrence.RangeNumberOfOccurrences)
return;
}
if (currentDay.DayOfWeek != DayOfWeek.Sunday)
{
while (currentDay.DayOfWeek != DayOfWeek.Sunday)
{
currentDay = currentDay.AddDays(1);
if (currentDay > endDate || recurrence.RangeLimitType == eRecurrenceRangeLimitType.RangeEndDate && currentDay > recurrence.RangeEndDate)
break;
if ((currentDay >= startDate || spansDays && GetAppointmentEndTime(currentDay, app) >= startDate) && DateTimeHelper.HasDay(currentDay.DayOfWeek, recurrence.Weekly.RepeatOnDaysOfWeek)
&& !IsIgnoredRecurrence(currentDay, recurrence))
{
subsetCollection.Add(CreateRecurringAppointmentInstance(currentDay, app));
}
else if (countTotalRecurrences && currentDay < startDate && DateTimeHelper.HasDay(currentDay.DayOfWeek, recurrence.Weekly.RepeatOnDaysOfWeek)
&& !IsIgnoredRecurrence(currentDay, recurrence))
{
totalRecurrences++;
if (totalRecurrences >= recurrence.RangeNumberOfOccurrences)
return;
}
}
}
currentDay = currentDay.AddDays(1 + (repeatInterval - 1) * 7);
if (recurrence.RangeLimitType == eRecurrenceRangeLimitType.RangeEndDate && currentDay > recurrence.RangeEndDate ||
recurrence.RangeLimitType == eRecurrenceRangeLimitType.RangeNumberOfOccurrences && totalRecurrences > recurrence.RangeNumberOfOccurrences)
break;
}
}
private DayOfWeek GetDayOfWeek(eDayOfWeekRecurrence d)
{
if (d == eDayOfWeekRecurrence.Monday)
return DayOfWeek.Monday;
else if (d == eDayOfWeekRecurrence.Tuesday)
return DayOfWeek.Tuesday;
else if (d == eDayOfWeekRecurrence.Wednesday)
return DayOfWeek.Wednesday;
else if (d == eDayOfWeekRecurrence.Thursday)
return DayOfWeek.Thursday;
else if (d == eDayOfWeekRecurrence.Friday)
return DayOfWeek.Friday;
else if (d == eDayOfWeekRecurrence.Saturday)
return DayOfWeek.Saturday;
else
return DayOfWeek.Sunday;
}
private bool RepeatsOnSingleDayOnly(eDayOfWeekRecurrence dow)
{
return dow == eDayOfWeekRecurrence.Monday || dow == eDayOfWeekRecurrence.Tuesday ||
dow == eDayOfWeekRecurrence.Wednesday || dow == eDayOfWeekRecurrence.Thursday ||
dow == eDayOfWeekRecurrence.Friday || dow == eDayOfWeekRecurrence.Saturday || dow == eDayOfWeekRecurrence.Sunday;
}
private int GetNumberOfDays(eDayOfWeekRecurrence daysOfWeek)
{
int days = 0;
if ((daysOfWeek & eDayOfWeekRecurrence.Friday) != 0)
days++;
if ((daysOfWeek & eDayOfWeekRecurrence.Monday) != 0)
days++;
if ((daysOfWeek & eDayOfWeekRecurrence.Saturday) != 0)
days++;
if ((daysOfWeek & eDayOfWeekRecurrence.Sunday) != 0)
days++;
if ((daysOfWeek & eDayOfWeekRecurrence.Thursday) != 0)
days++;
if ((daysOfWeek & eDayOfWeekRecurrence.Tuesday) != 0)
days++;
if ((daysOfWeek & eDayOfWeekRecurrence.Wednesday) != 0)
days++;
return days;
}
/// <summary>
/// Generates Monthly recurring appointments. If appointment is assigned to calendar method must populate the Calendar.Appointments collection as well.
/// </summary>
/// <param name="subsetCollection">Collection to add generated recurrences to</param>
/// <param name="recurrence">Recurrence description, must be of Monthly recurrence type.</param>
/// <param name="startDate">Start date for generation.</param>
/// <param name="endDate">End date for generation.</param>
public void GenerateMonthlyRecurrence(AppointmentSubsetCollection subsetCollection, AppointmentRecurrence recurrence, DateTime startDate, DateTime endDate)
{
Appointment app = recurrence.Appointment;
DateTime recurrenceStartDate = DateTimeHelper.MaxDate(recurrence.RecurrenceStartDate, app.EndTime/*.AddDays(1).Date*/);
if (recurrenceStartDate > endDate) return;
int totalRecurrences = 0;
// Check the range first
if (recurrence.RangeLimitType == eRecurrenceRangeLimitType.RangeEndDate)
{
if (startDate > recurrence.RangeEndDate) return;
}
else if (recurrence.RangeLimitType == eRecurrenceRangeLimitType.RangeNumberOfOccurrences && recurrence.RangeNumberOfOccurrences > 0)
{
int count = recurrence.RangeNumberOfOccurrences + 1;
DateTime testDate = DateTimeHelper.BeginningOfDay(recurrenceStartDate);
DateTime startDateOnly = DateTimeHelper.BeginningOfDay(startDate);
while (count > 0 && testDate < startDateOnly)
{
int repeatInterval = recurrence.Monthly.RepeatInterval;
while (repeatInterval > 0)
{
testDate = GetNextMonthlyRecurrence(recurrence, testDate);
repeatInterval--;
}
if (testDate < startDate)
totalRecurrences++;
count--;
}
if (count == 0) return;
}
DateTime currentDate = recurrenceStartDate;// DateTimeHelper.MaxDate(recurrenceStartDate, startDate).AddMonths(-1);
do
{
int repeatCount = recurrence.Monthly.RepeatInterval;
do
{
repeatCount--;
currentDate = GetNextMonthlyRecurrence(recurrence, currentDate);
} while (repeatCount > 0);
if (recurrence.RangeLimitType == eRecurrenceRangeLimitType.RangeEndDate && currentDate > recurrence.RangeEndDate ||
recurrence.RangeLimitType == eRecurrenceRangeLimitType.RangeNumberOfOccurrences && totalRecurrences >= recurrence.RangeNumberOfOccurrences)
break;
if (currentDate >= startDate && currentDate <= endDate && !IsIgnoredRecurrence(currentDate, recurrence))
{
subsetCollection.Add(CreateRecurringAppointmentInstance(currentDate, app));
totalRecurrences++;
}
} while (currentDate <= endDate);
}
private DateTime GetNextMonthlyRecurrence(AppointmentRecurrence recurrence, DateTime startDate)
{
MonthlyRecurrenceSettings monthly = recurrence.Monthly;
return GetNextMonthlyRecurrence(startDate, monthly.RepeatOnRelativeDayInMonth,
monthly.RelativeDayOfWeek, monthly.RepeatOnDayOfMonth, monthly.RepeatOnMonths);
}
private static void AdjustForRepeatOnMonths(ref DateTime dt, eMonthRecurrence repeatOnMonths)
{
while (((int)Math.Pow(2, (dt.Month - 1)) & (int)repeatOnMonths) == 0)
dt = dt.AddMonths(1);
}
private static DateTime GetNextMonthlyRecurrence(DateTime startDate, eRelativeDayInMonth repeatOnRelativeDayInMonth, DayOfWeek relativeDayOfWeek, int repeatOnDayOfMonth, eMonthRecurrence repeatOnMonths)
{
Calendar cal = GetCalendar();
if (repeatOnRelativeDayInMonth == eRelativeDayInMonth.None)
{
DateTime dt = startDate.AddDays(cal.GetDaysInMonth(startDate.Year, startDate.Month) - startDate.Day + 1);
if (repeatOnMonths != eMonthRecurrence.All) AdjustForRepeatOnMonths(ref dt, repeatOnMonths); // Adjust for repeat on Months
return dt.AddDays(Math.Min(cal.GetDaysInMonth(dt.Year, dt.Month), repeatOnDayOfMonth) - 1);
}
else
{
if (repeatOnRelativeDayInMonth == eRelativeDayInMonth.First)
{
DateTime dt = startDate.AddDays(cal.GetDaysInMonth(startDate.Year, startDate.Month) - startDate.Day + 1);
if (repeatOnMonths != eMonthRecurrence.All) AdjustForRepeatOnMonths(ref dt, repeatOnMonths); // Adjust for repeat on Months
while (dt.DayOfWeek != relativeDayOfWeek)
dt = dt.AddDays(1);
return dt;
}
else if (repeatOnRelativeDayInMonth == eRelativeDayInMonth.Last)
{
DateTime dt = startDate.AddDays(cal.GetDaysInMonth(startDate.Year, startDate.Month) - startDate.Day + 1);
if (repeatOnMonths != eMonthRecurrence.All) AdjustForRepeatOnMonths(ref dt, repeatOnMonths); // Adjust for repeat on Months
dt = dt.AddDays(cal.GetDaysInMonth(dt.Year, dt.Month) - 1);
while (dt.DayOfWeek != relativeDayOfWeek)
dt = dt.AddDays(-1);
return dt;
}
else
{
// Second, third and forth
int relCount = 2;
if (repeatOnRelativeDayInMonth == eRelativeDayInMonth.Third)
relCount = 3;
else if (repeatOnRelativeDayInMonth == eRelativeDayInMonth.Fourth)
relCount = 4;
DateTime dt = startDate.AddDays(cal.GetDaysInMonth(startDate.Year, startDate.Month) - startDate.Day);
if (repeatOnMonths != eMonthRecurrence.All) AdjustForRepeatOnMonths(ref dt, repeatOnMonths); // Adjust for repeat on Months
while (relCount > 0)
{
dt = dt.AddDays(1);
if (dt.DayOfWeek == relativeDayOfWeek)
relCount--;
}
return dt;
}
}
throw new InvalidOperationException("Could not find the next relative date for monthly recurrence starting on " + startDate.ToString() + " RelativeDayInMonth=" + repeatOnRelativeDayInMonth.ToString() + " RelativeDayOfWeek=" + relativeDayOfWeek.ToString());
}
private static Calendar GetCalendar()
{
return CultureInfo.CurrentCulture.Calendar;
}
/// <summary>
/// Generates Yearly recurring appointments. If appointment is assigned to calendar method must populate the Calendar.Appointments collection as well.
/// </summary>
/// <param name="subsetCollection">Collection to add generated recurrences to</param>
/// <param name="recurrence">Recurrence description, must be of Monthly recurrence type.</param>
/// <param name="startDate">Start date for generation.</param>
/// <param name="endDate">End date for generation.</param>
public void GenerateYearlyRecurrence(AppointmentSubsetCollection subsetCollection, AppointmentRecurrence recurrence, DateTime startDate, DateTime endDate)
{
Appointment app = recurrence.Appointment;
DateTime recurrenceStartDate = DateTimeHelper.MaxDate(recurrence.RecurrenceStartDate, app.EndTime.AddDays(1).Date);
if (recurrenceStartDate > endDate) return;
if (!(startDate.Month <= recurrence.Yearly.RepeatOnMonth && endDate.Month >= recurrence.Yearly.RepeatOnMonth) && endDate.Subtract(startDate).TotalDays < 28)
return;
int totalRecurrences = 0;
// Check the range first
if (recurrence.RangeLimitType == eRecurrenceRangeLimitType.RangeEndDate)
{
if (startDate > recurrence.RangeEndDate) return;
}
else if (recurrence.RangeLimitType == eRecurrenceRangeLimitType.RangeNumberOfOccurrences && recurrence.RangeNumberOfOccurrences > 0 && recurrenceStartDate < startDate)
{
int count = recurrence.RangeNumberOfOccurrences + 1;
DateTime testDate = DateTimeHelper.BeginningOfDay(recurrenceStartDate.AddDays(-(recurrenceStartDate.Day - 1))).AddMonths(-1);
if (testDate < app.EndTime)
testDate = app.EndTime.Date.AddDays(1);
DateTime startDateOnly = DateTimeHelper.BeginningOfDay(startDate);
while (count > 0 && testDate < startDateOnly)
{
testDate = GetNextYearlyRecurrence(recurrence, testDate);
if (testDate >= startDateOnly) break;
count--;
totalRecurrences++;
}
if (count == 0) return;
}
DateTime currentDate = DateTimeHelper.MaxDate(startDate, recurrenceStartDate).AddDays(-1);
if (recurrence.Yearly.RepeatInterval > 1)
currentDate = recurrenceStartDate;
do
{
currentDate = GetNextYearlyRecurrence(recurrence, currentDate);
if (recurrence.RangeLimitType == eRecurrenceRangeLimitType.RangeEndDate && currentDate > recurrence.RangeEndDate ||
recurrence.RangeLimitType == eRecurrenceRangeLimitType.RangeNumberOfOccurrences && totalRecurrences >= recurrence.RangeNumberOfOccurrences)
break;
if (currentDate >= startDate && currentDate <= endDate && !IsIgnoredRecurrence(currentDate, recurrence))
{
subsetCollection.Add(CreateRecurringAppointmentInstance(currentDate, app));
totalRecurrences++;
}
} while (currentDate <= endDate);
}
internal static DateTime GetNextYearlyRecurrence(AppointmentRecurrence recurrence, DateTime startDate)
{
YearlyRecurrenceSettings yearly = recurrence.Yearly;
if (yearly.RepeatInterval > 1)
{
DateTime currentDate = startDate;
for (int i = 0; i < yearly.RepeatInterval; i++)
{
currentDate = GetNextSingleYearlyRecurrence(recurrence, currentDate);
}
return currentDate;
}
else
{
return GetNextSingleYearlyRecurrence(recurrence, startDate);
}
}
internal static DateTime GetNextSingleYearlyRecurrence(AppointmentRecurrence recurrence, DateTime startDate)
{
YearlyRecurrenceSettings yearly = recurrence.Yearly;
Calendar cal = GetCalendar();
if (startDate.Month < yearly.RepeatOnMonth)
{
startDate = startDate.AddMonths((yearly.RepeatOnMonth - startDate.Month) - 1);
return GetNextMonthlyRecurrence(startDate, yearly.RepeatOnRelativeDayInMonth, yearly.RelativeDayOfWeek, yearly.RepeatOnDayOfMonth, eMonthRecurrence.All);
}
else if (startDate.Month == yearly.RepeatOnMonth)
{
DateTime refDate = startDate.AddDays(-(startDate.Day));
DateTime ret = GetNextMonthlyRecurrence(refDate, yearly.RepeatOnRelativeDayInMonth, yearly.RelativeDayOfWeek, yearly.RepeatOnDayOfMonth, eMonthRecurrence.All);
if (ret > startDate) return ret;
}
// Forward to next year and right month
startDate = startDate.AddDays(cal.GetDaysInYear(startDate.Year) - startDate.DayOfYear).AddMonths(yearly.RepeatOnMonth - 1);
return GetNextMonthlyRecurrence(startDate, yearly.RepeatOnRelativeDayInMonth, yearly.RelativeDayOfWeek, yearly.RepeatOnDayOfMonth, eMonthRecurrence.All);
}
#endregion
}
internal interface IRecurrenceGenerator
{
/// <summary>
/// Generates Daily recurring appointments. If appointment is assigned to calendar method must populate the Calendar.Appointments collection as well.
/// </summary>
/// <param name="subsetCollection">Collection to add generated recurrences to</param>
/// <param name="recurrence">Recurrence description, must be of Daily recurrence type.</param>
/// <param name="startDate">Start date for generation.</param>
/// <param name="endDate">End date for generation.</param>
void GenerateDailyRecurrence(AppointmentSubsetCollection subsetCollection, AppointmentRecurrence recurrence, DateTime startDate, DateTime endDate);
/// <summary>
/// Generates Weekly recurring appointments. If appointment is assigned to calendar method must populate the Calendar.Appointments collection as well.
/// </summary>
/// <param name="subsetCollection">Collection to add generated recurrences to</param>
/// <param name="recurrence">Recurrence description, must be of Weekly recurrence type.</param>
/// <param name="startDate">Start date for generation.</param>
/// <param name="endDate">End date for generation.</param>
void GenerateWeeklyRecurrence(AppointmentSubsetCollection subsetCollection, AppointmentRecurrence recurrence, DateTime startDate, DateTime endDate);
/// <summary>
/// Generates Monthly recurring appointments. If appointment is assigned to calendar method must populate the Calendar.Appointments collection as well.
/// </summary>
/// <param name="subsetCollection">Collection to add generated recurrences to</param>
/// <param name="recurrence">Recurrence description, must be of Monthly recurrence type.</param>
/// <param name="startDate">Start date for generation.</param>
/// <param name="endDate">End date for generation.</param>
void GenerateMonthlyRecurrence(AppointmentSubsetCollection subsetCollection, AppointmentRecurrence recurrence, DateTime startDate, DateTime endDate);
/// <
/// summary>
/// Generates Yearly recurring appointments. If appointment is assigned to calendar method must populate the Calendar.Appointments collection as well.
/// </summary>
/// <param name="subsetCollection">Collection to add generated recurrences to</param>
/// <param name="recurrence">Recurrence description, must be of Monthly recurrence type.</param>
/// <param name="startDate">Start date for generation.</param>
/// <param name="endDate">End date for generation.</param>
void GenerateYearlyRecurrence(AppointmentSubsetCollection subsetCollection, AppointmentRecurrence recurrence, DateTime startDate, DateTime endDate);
}
}
#endif