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);
}
}
}