using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using Itenso.TimePeriod; using Wino.Core.Domain.Entities.Calendar; using Wino.Core.Domain.Interfaces; namespace Wino.Core.Domain.Collections { public class CalendarEventCollection { public event EventHandler CalendarItemAdded; public event EventHandler CalendarItemRemoved; public event EventHandler CalendarItemsCleared; private ObservableRangeCollection _internalRegularEvents = []; private ObservableRangeCollection _internalAllDayEvents = []; public ReadOnlyObservableCollection RegularEvents { get; } public ReadOnlyObservableCollection AllDayEvents { get; } public ITimePeriod Period { get; } private readonly List _allItems = new List(); public CalendarEventCollection(ITimePeriod period) { Period = period; RegularEvents = new ReadOnlyObservableCollection(_internalRegularEvents); AllDayEvents = new ReadOnlyObservableCollection(_internalAllDayEvents); } public bool HasCalendarEvent(AccountCalendar accountCalendar) => _allItems.Any(x => x.AssignedCalendar.Id == accountCalendar.Id); public ICalendarItem GetCalendarItem(Guid calendarItemId) { return _allItems.FirstOrDefault(x => x.Id == calendarItemId); } public void FilterByCalendars(IEnumerable visibleCalendarIds) { foreach (var item in _allItems) { var collection = GetProperCollectionForCalendarItem(item); if (!visibleCalendarIds.Contains(item.AssignedCalendar.Id) && collection.Contains(item)) { RemoveCalendarItemInternal(collection, item, false); } else if (visibleCalendarIds.Contains(item.AssignedCalendar.Id) && !collection.Contains(item)) { AddCalendarItemInternal(collection, item, false); } } } private ObservableRangeCollection GetProperCollectionForCalendarItem(ICalendarItem calendarItem) { // Event duration is not simply enough to determine whether it's an all-day event or not. // Event may start at 11:00 PM and end next day at 11:00 PM. It's not an all-day event. // It's a multi-day event. bool isAllDayEvent = calendarItem.Period.Duration.TotalDays == 1 && calendarItem.Period.Start.TimeOfDay == TimeSpan.Zero; return isAllDayEvent ? _internalAllDayEvents : _internalRegularEvents; } public void AddCalendarItem(ICalendarItem calendarItem) { var collection = GetProperCollectionForCalendarItem(calendarItem); AddCalendarItemInternal(collection, calendarItem); } public void RemoveCalendarItem(ICalendarItem calendarItem) { var collection = GetProperCollectionForCalendarItem(calendarItem); RemoveCalendarItemInternal(collection, calendarItem); } private void AddCalendarItemInternal(ObservableRangeCollection collection, ICalendarItem calendarItem, bool create = true) { if (calendarItem is not ICalendarItemViewModel) throw new ArgumentException("CalendarItem must be of type ICalendarItemViewModel", nameof(calendarItem)); collection.Add(calendarItem); if (create) { _allItems.Add(calendarItem); } CalendarItemAdded?.Invoke(this, calendarItem); } private void RemoveCalendarItemInternal(ObservableRangeCollection collection, ICalendarItem calendarItem, bool destroy = true) { if (calendarItem is not ICalendarItemViewModel) throw new ArgumentException("CalendarItem must be of type ICalendarItemViewModel", nameof(calendarItem)); collection.Remove(calendarItem); if (destroy) { _allItems.Remove(calendarItem); } CalendarItemRemoved?.Invoke(this, calendarItem); } public void Clear() { _internalAllDayEvents.Clear(); _internalRegularEvents.Clear(); _allItems.Clear(); CalendarItemsCleared?.Invoke(this, EventArgs.Empty); } } }