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