using Core.Entities; namespace WebApp.Models; /// /// Represents the state of the meeting schedule for dirty/clean tracking and persistence. /// public class MeetingScheduleState : IEquatable { public HashSet ScheduledTeamIds { get; set; } = []; public HashSet AbsentStudentIds { get; set; } = []; public int TimeSlotCount { get; set; } public HashSet ExtendedTeamIds { get; set; } = []; public HashSet<(int teamId, int timeSlotIndex, int studentId)> ExcludedStudents { get; set; } = []; public bool Equals(MeetingScheduleState? other) { if (other == null) return false; return ScheduledTeamIds.SetEquals(other.ScheduledTeamIds) && AbsentStudentIds.SetEquals(other.AbsentStudentIds) && TimeSlotCount == other.TimeSlotCount && ExtendedTeamIds.SetEquals(other.ExtendedTeamIds) && ExcludedStudents.SetEquals(other.ExcludedStudents); } public override bool Equals(object? obj) => Equals(obj as MeetingScheduleState); public override int GetHashCode() { var hash = new HashCode(); hash.Add(ScheduledTeamIds.Count); foreach (var id in ScheduledTeamIds.OrderBy(x => x)) hash.Add(id); hash.Add(AbsentStudentIds.Count); foreach (var id in AbsentStudentIds.OrderBy(x => x)) hash.Add(id); hash.Add(TimeSlotCount); hash.Add(ExtendedTeamIds.Count); foreach (var id in ExtendedTeamIds.OrderBy(x => x)) hash.Add(id); hash.Add(ExcludedStudents.Count); foreach (var key in ExcludedStudents.OrderBy(x => x)) hash.Add(key); return hash.ToHashCode(); } public static MeetingScheduleState FromCurrent( IEnumerable scheduledTeams, IEnumerable absentStudents, int timeSlotCount, IEnumerable extendedTeams, Dictionary<(int teamId, int timeSlotIndex, int studentId), bool> excludedStudents) { return new MeetingScheduleState { ScheduledTeamIds = scheduledTeams.Select(t => t.Id).ToHashSet(), AbsentStudentIds = absentStudents.Select(s => s.Id).ToHashSet(), TimeSlotCount = timeSlotCount, ExtendedTeamIds = extendedTeams.Select(t => t.Id).ToHashSet(), ExcludedStudents = excludedStudents.Keys .Where(k => excludedStudents[k]) .ToHashSet() }; } public static async Task FromLocalStorage( WebApp.LocalStorageService localStorage, Team[] allTeams, Student[] allStudents) { // Load scheduled teams var scheduledTeamIds = await localStorage.GetIntArrayAsync("MeetingSchedule_ScheduledTeams"); var absentStudentIds = await localStorage.GetIntArrayAsync("MeetingSchedule_AbsentStudents"); var timeSlotCount = await localStorage.GetIntAsync("MeetingSchedule_TimeSlotCount", defaultValue: 2); var extendedTeamIds = await localStorage.GetIntArrayAsync("MeetingSchedule_ExtendedTeams"); var exclusions = await localStorage.GetJsonAsync("MeetingSchedule_ExcludedStudents"); // If no state exists, return null if (scheduledTeamIds.Length == 0 && absentStudentIds.Length == 0 && timeSlotCount == 2 && extendedTeamIds.Length == 0 && (exclusions == null || exclusions.Length == 0)) { return null; } var excludedStudentsSet = new HashSet<(int teamId, int timeSlotIndex, int studentId)>(); if (exclusions != null && exclusions.Length > 0) { foreach (var exclusion in exclusions) { excludedStudentsSet.Add((exclusion.TeamId, exclusion.TimeSlotIndex, exclusion.StudentId)); } } return new MeetingScheduleState { ScheduledTeamIds = scheduledTeamIds.ToHashSet(), AbsentStudentIds = absentStudentIds.ToHashSet(), TimeSlotCount = timeSlotCount > 0 ? timeSlotCount : 2, ExtendedTeamIds = extendedTeamIds.ToHashSet(), ExcludedStudents = excludedStudentsSet }; } public async Task SaveToLocalStorage(WebApp.LocalStorageService localStorage) { await localStorage.SetIntArrayAsync("MeetingSchedule_ScheduledTeams", ScheduledTeamIds.ToArray()); await localStorage.SetIntArrayAsync("MeetingSchedule_AbsentStudents", AbsentStudentIds.ToArray()); await localStorage.SetIntAsync("MeetingSchedule_TimeSlotCount", TimeSlotCount); await localStorage.SetIntArrayAsync("MeetingSchedule_ExtendedTeams", ExtendedTeamIds.ToArray()); var exclusions = ExcludedStudents.Select(e => new ExcludedStudent(e.teamId, e.timeSlotIndex, e.studentId)).ToArray(); await localStorage.SetJsonAsync("MeetingSchedule_ExcludedStudents", exclusions); } private record ExcludedStudent(int TeamId, int TimeSlotIndex, int StudentId); }