#if FRAMEWORK20
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections.ObjectModel;
using DevComponents.Schedule.Model.Primitives;
namespace DevComponents.Schedule.Model
{
///
/// Represents subset of appointments collection.
///
public class AppointmentSubsetCollection : CustomCollection
{
#region Private Variables
private DateTime _StartDate = DateTime.MinValue;
private DateTime _EndDate = DateTime.MinValue;
#endregion
#region Constructor
///
/// Initializes a new instance of the AppointmentSubsetCollection class with appointments between given start and end date.
///
///
///
///
public AppointmentSubsetCollection(CalendarModel calendar, DateTime start, DateTime end)
{
_Calendar = calendar;
_StartDate = start;
_EndDate = end;
PopulateCollection();
}
#endregion
#region Internal Implementation
private CalendarModel _Calendar = null;
///
/// Gets the calendar collection is associated with this collection.
///
public CalendarModel Calendar
{
get { return _Calendar; }
internal set { _Calendar = value; }
}
protected override void InsertItem(int index, Appointment item)
{
OnBeforeInsert(index, item);
base.InsertItem(index, item);
}
private void OnBeforeInsert(int index, Appointment item)
{
item.SubPropertyChanged += this.ChildPropertyChangedEventHandler;
item.Calendar = _Calendar;
if (item.IsRecurringInstance && _Calendar != null)
_Calendar.InternalAppointmentAdded(item);
}
protected override void SetItem(int index, Appointment item)
{
OnBeforeSetItem(index, item);
base.SetItem(index, item);
}
private void OnBeforeSetItem(int index, Appointment item)
{
Appointment app = this[index];
app.SubPropertyChanged -= this.ChildPropertyChangedEventHandler;
app.Calendar = null;
item.SubPropertyChanged += this.ChildPropertyChangedEventHandler;
app.Calendar = _Calendar;
}
protected override void RemoveItem(int index)
{
OnBeforeRemove(index);
base.RemoveItem(index);
}
private void OnBeforeRemove(int index)
{
Appointment item = this[index];
OnAppointmentRemoved(item);
}
private void OnAppointmentRemoved(Appointment item)
{
item.SubPropertyChanged -= this.ChildPropertyChangedEventHandler;
if (item.IsRecurringInstance && _Calendar != null)
_Calendar.InternalAppointmentRemoved(item, false);
if (item.IsRecurringInstance)
item.Calendar = null;
}
protected override void ClearItems()
{
foreach (Appointment item in this.GetItemsDirect())
{
OnAppointmentRemoved(item);
}
base.ClearItems();
}
private void PopulateCollection()
{
this.Clear();
foreach (Appointment app in _Calendar.Appointments)
{
if (app.LocalStartTime >= _StartDate && app.LocalStartTime <= _EndDate || app.LocalEndTime > _StartDate && (app.LocalEndTime <= _EndDate || app.LocalStartTime < _StartDate))
{
this.Add(app);
}
if (app.Recurrence != null && IsRecurrenceInRange(app, _StartDate, _EndDate))
{
int count = this.GetItemsDirect().Count;
app.Recurrence.GenerateSubset(this, _StartDate, _EndDate);
if (count == this.GetItemsDirect().Count && TotalDaysDuration(app.StartTime, app.EndTime) >= 1 &&
app.LocalEndTime < _StartDate)
{
// Nothing generated lets wind back and look to see is there an recurrence that needs to be captured in this view
int daysLookBack = TotalDaysDuration(app.StartTime, app.EndTime);
DateTime start = _StartDate;
for (int i = 0; i < daysLookBack; i++)
{
start = start.AddDays(-1);
AppointmentSubsetCollection dayCollection = _Calendar.GetDay(start).Appointments;
foreach (Appointment subAppointment in dayCollection)
{
if (subAppointment.IsRecurringInstance && subAppointment.RootAppointment == app &&
(subAppointment.LocalStartTime >= _StartDate && subAppointment.LocalStartTime <= _EndDate ||
subAppointment.LocalEndTime > _StartDate && (subAppointment.LocalEndTime <= _EndDate ||
subAppointment.LocalStartTime < _StartDate)))
{
this.Add(subAppointment);
daysLookBack = -1;
break;
}
}
}
}
}
}
_IsCollectionUpToDate = true;
}
private int TotalDaysDuration(DateTime startTime, DateTime endTime)
{
if (endTime.Hour == 0 && endTime.Minute == 0 && endTime.Second == 0)
endTime = endTime.AddMinutes(-1);
return (int)Math.Max(0, Math.Ceiling(endTime.Date.Subtract(startTime.Date).TotalDays));
}
private bool IsRecurrenceInRange(Appointment app, DateTime startDate, DateTime endDate)
{
if (app.Recurrence.RecurrenceType == eRecurrencePatternType.Yearly)
{
// Simple range check on number of occurrences
if (app.Recurrence.RangeLimitType == eRecurrenceRangeLimitType.RangeNumberOfOccurrences && app.LocalEndTime.Subtract(endDate).TotalDays / 365 > app.Recurrence.RangeNumberOfOccurrences)
return false;
// Date check based on next expected recurrence date
if (app.Recurrence.Yearly.RepeatInterval > 1)
{
DateTime nextRecurrence = DateTimeHelper.MaxDate(app.Recurrence.RecurrenceStartDate, app.EndTime.AddDays(1).Date);
while (nextRecurrence < startDate)
nextRecurrence = RecurrenceGenerator.GetNextYearlyRecurrence(app.Recurrence, nextRecurrence);
if (nextRecurrence > endDate || nextRecurrence.Add(endDate.Subtract(startDate)) < startDate)
return false;
}
else
{
DateTime nextRecurrence = RecurrenceGenerator.GetNextYearlyRecurrence(app.Recurrence, startDate.Date.AddDays(-startDate.DayOfYear));
if (nextRecurrence > endDate || nextRecurrence.Add(endDate.Subtract(startDate)) < startDate)
return false;
}
}
if (app.Recurrence.RangeEndDate == DateTime.MinValue || app.Recurrence.RangeEndDate >= _EndDate || app.Recurrence.RangeEndDate < _EndDate && app.Recurrence.RangeEndDate > _StartDate)
return true;
return false;
}
private SubPropertyChangedEventHandler _ChildPropertyChangedEventHandler = null;
private SubPropertyChangedEventHandler ChildPropertyChangedEventHandler
{
get
{
if (_ChildPropertyChangedEventHandler == null) _ChildPropertyChangedEventHandler = new SubPropertyChangedEventHandler(ChildPropertyChanged);
return _ChildPropertyChangedEventHandler;
}
}
private void ChildPropertyChanged(object sender, SubPropertyChangedEventArgs e)
{
InvalidateCollection();
}
///
/// Invalidates collection content due to the change to appointments or some other condition. Invalidating collection
/// content causes the collection elements to be re-generated on next collection read access.
///
public virtual void InvalidateCollection()
{
_IsCollectionUpToDate = false;
}
protected override void OnCollectionReadAccess()
{
if (!_IsCollectionUpToDate) PopulateCollection();
base.OnCollectionReadAccess();
}
private bool _IsCollectionUpToDate = false;
internal bool IsCollectionUpToDate
{
get { return _IsCollectionUpToDate; }
set
{
_IsCollectionUpToDate = value;
}
}
#endregion
}
}
#endif