using System.Text; using Core.Calculation; using Core.Entities; using Core.Utility; namespace WebApp.Services; /// /// Service for formatting meeting schedule data for clipboard operations. /// public class MeetingScheduleClipboardService : IMeetingScheduleClipboardService { public string FormatScheduleForClipboard( TeamSchedulerSolution solution, Team[] allTeams, IEnumerable absentStudents, Dictionary<(int teamId, int timeSlotIndex, int studentId), bool> excludedStudents, Func getTimeSlotIndex) { var sb = new StringBuilder(); foreach (var timeslot in solution.TimeSlots) { AppendScheduledTeams(sb, timeslot, allTeams, absentStudents, excludedStudents, getTimeSlotIndex); AppendUnscheduledStudents(sb, timeslot, solution, absentStudents); sb.Append(Environment.NewLine); } return sb.ToString(); } private void AppendScheduledTeams( StringBuilder sb, TeamScheduleTimeSlot timeslot, Team[] allTeams, IEnumerable absentStudents, Dictionary<(int teamId, int timeSlotIndex, int studentId), bool> excludedStudents, Func getTimeSlotIndex) { var timeSlotIndex = getTimeSlotIndex(timeslot.Name); foreach (var scheduledTeam in timeslot.Teams.OrderBy(e => e.ToString())) { var teamName = scheduledTeam.ToString(); if (scheduledTeam.Event.EventFormat is EventFormat.Individual) { sb.Append(teamName); } else { var studentsList = FormatStudentList(scheduledTeam, timeslot, timeSlotIndex, absentStudents, excludedStudents); sb.Append($"{teamName} - {studentsList}"); } sb.Append(Environment.NewLine); } } private string FormatStudentList( Team team, TeamScheduleTimeSlot timeslot, int timeSlotIndex, IEnumerable absentStudents, Dictionary<(int teamId, int timeSlotIndex, int studentId), bool> excludedStudents) { // Filter out excluded students for this team and time slot var excludedStudentIds = excludedStudents.Keys .Where(k => k.teamId == team.Id && k.timeSlotIndex == timeSlotIndex && excludedStudents[k]) .Select(k => k.studentId) .ToHashSet(); var includedStudents = team.Students .Where(s => !excludedStudentIds.Contains(s.Id)) .ToList(); // Create a temporary team with only included students for formatting var teamForFormatting = new Team { Id = team.Id, Event = team.Event, Students = includedStudents, Captain = team.Captain, Identifier = team.Identifier }; return TeamStudentNameFormatter.FormatStudentList( teamForFormatting, new TeamStudentNameFormatter.FormatOptions { Ordering = TeamStudentNameFormatter.OrderingStyle.CaptainFirst, MarkOverlaps = true, HasOverlaps = timeslot.StudentHasOverlaps, MarkAbsent = true, AbsentStudents = absentStudents.ToList() }); } private void AppendUnscheduledStudents( StringBuilder sb, TeamScheduleTimeSlot timeslot, TeamSchedulerSolution solution, IEnumerable absentStudents) { if (!timeslot.UnscheduledStudents.Any()) return; sb.Append("--Unscheduled"); sb.Append(Environment.NewLine); foreach (var student in timeslot.UnscheduledStudents) { var studentName = StudentNameFormatter.FormatStudentName( student, new StudentNameFormatter.FormatOptions { IsAbsent = absentStudents.Contains(student) }); var unassignedTeams = solution.StudentUnassignedTeams(student); var teamsList = string.Join(", ", unassignedTeams.Select(e => e.ToString())); sb.Append($"{studentName} - {teamsList}"); sb.Append(Environment.NewLine); } } }