using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using CommunityToolkit.Mvvm.Collections; using CommunityToolkit.Mvvm.ComponentModel; using Wino.Calendar.ViewModels.Data; using Wino.Calendar.ViewModels.Interfaces; using Wino.Core.Domain.Entities.Shared; namespace Wino.Mail.WinUI.Services; /// /// Encapsulated state manager for collectively managing the state of account calendars. /// Callers must react to the events to update their state only from this service. /// public partial class AccountCalendarStateService : ObservableObject, IAccountCalendarStateService { public event EventHandler? CollectiveAccountGroupSelectionStateChanged; public event EventHandler? AccountCalendarSelectionStateChanged; private readonly ObservableCollection _internalGroupedAccountCalendars; private readonly ObservableGroupedCollection _internalGroupedCalendars; [ObservableProperty] public partial ReadOnlyObservableCollection GroupedAccountCalendars { get; set; } [ObservableProperty] public partial ReadOnlyObservableGroupedCollection GroupedCalendars { get; set; } public IEnumerable ActiveCalendars { get { return _internalGroupedAccountCalendars .SelectMany(a => a.AccountCalendars) .Where(b => b.IsChecked); } } public IEnumerable AllCalendars { get { return _internalGroupedAccountCalendars .SelectMany(a => a.AccountCalendars); } } public AccountCalendarStateService() { _internalGroupedAccountCalendars = new ObservableCollection(); GroupedAccountCalendars = new ReadOnlyObservableCollection(_internalGroupedAccountCalendars); _internalGroupedCalendars = new ObservableGroupedCollection(); GroupedCalendars = new ReadOnlyObservableGroupedCollection(_internalGroupedCalendars); } private void SingleGroupCalendarCollectiveStateChanged(object? sender, EventArgs e) => CollectiveAccountGroupSelectionStateChanged?.Invoke(this, sender as GroupedAccountCalendarViewModel ?? throw new InvalidOperationException("Sender must be GroupedAccountCalendarViewModel")); private void SingleCalendarSelectionStateChanged(object? sender, AccountCalendarViewModel e) => AccountCalendarSelectionStateChanged?.Invoke(this, e); public void AddGroupedAccountCalendar(GroupedAccountCalendarViewModel groupedAccountCalendar) { groupedAccountCalendar.CalendarSelectionStateChanged += SingleCalendarSelectionStateChanged; groupedAccountCalendar.CollectiveSelectionStateChanged += SingleGroupCalendarCollectiveStateChanged; _internalGroupedAccountCalendars.Add(groupedAccountCalendar); // Maintain the grouped calendars collection var group = _internalGroupedCalendars.FirstOrDefault>(g => g.Key.Id == groupedAccountCalendar.Account.Id); if (group == null) { _internalGroupedCalendars.Add(new ObservableGroup(groupedAccountCalendar.Account, groupedAccountCalendar.AccountCalendars)); } else { foreach (var calendar in groupedAccountCalendar.AccountCalendars) { group.Add(calendar); } } } public void RemoveGroupedAccountCalendar(GroupedAccountCalendarViewModel groupedAccountCalendar) { groupedAccountCalendar.CalendarSelectionStateChanged -= SingleCalendarSelectionStateChanged; groupedAccountCalendar.CollectiveSelectionStateChanged -= SingleGroupCalendarCollectiveStateChanged; _internalGroupedAccountCalendars.Remove(groupedAccountCalendar); // Maintain the grouped calendars collection var group = _internalGroupedCalendars.FirstOrDefault>(g => g.Key.Id == groupedAccountCalendar.Account.Id); if (group != null) { foreach (var calendar in groupedAccountCalendar.AccountCalendars.ToList()) { group.Remove(calendar); } if (group.Count == 0) { _internalGroupedCalendars.Remove(group); } } } public void ClearGroupedAccountCalendars() { while (_internalGroupedAccountCalendars.Any()) { RemoveGroupedAccountCalendar(_internalGroupedAccountCalendars[0]); } } public void AddAccountCalendar(AccountCalendarViewModel accountCalendar) { // Find the group that this calendar belongs to. var group = _internalGroupedAccountCalendars.FirstOrDefault(g => g.Account.Id == accountCalendar.Account.Id); if (group == null) { // If the group doesn't exist, create it. group = new GroupedAccountCalendarViewModel(accountCalendar.Account, new[] { accountCalendar }); AddGroupedAccountCalendar(group); } else { group.AccountCalendars.Add(accountCalendar); // Maintain the grouped calendars collection var calendarGroup = _internalGroupedCalendars.FirstOrDefault>(g => g.Key.Id == accountCalendar.Account.Id); if (calendarGroup == null) { _internalGroupedCalendars.Add(new ObservableGroup(accountCalendar.Account, new[] { accountCalendar })); } else { calendarGroup.Add(accountCalendar); } } } public void RemoveAccountCalendar(AccountCalendarViewModel accountCalendar) { var group = _internalGroupedAccountCalendars.FirstOrDefault(g => g.Account.Id == accountCalendar.Account.Id); // We don't expect but just in case. if (group == null) return; group.AccountCalendars.Remove(accountCalendar); // Maintain the grouped calendars collection var calendarGroup = _internalGroupedCalendars.FirstOrDefault>(g => g.Key.Id == accountCalendar.Account.Id); if (calendarGroup != null) { calendarGroup.Remove(accountCalendar); if (calendarGroup.Count == 0) { _internalGroupedCalendars.Remove(calendarGroup); } } if (group.AccountCalendars.Count == 0) { RemoveGroupedAccountCalendar(group); } } }