using System.Diagnostics; using System.Text.Json; using System.Text.RegularExpressions; using Core.Calculation; using Core.Entities; using Core.Parsers; using Core.Utility; using Microsoft.AspNetCore.Mvc; using Web.Models; namespace Web.Controllers { public partial class HomeController : Controller { private const string ContentDirectory = @"C:\Users\james\source\TSA Chapter Organizer\Tests\Parsers\TestInput\"; private EventDefinition[] GetEvents() { var fileInfo = FileUtility.GetContentFile(ContentDirectory, "2024-25 RMS TSA student & eventDefinition - EventDefinition Definitions.csv"); var eventRankingsParser = new EventDefinitionParser(fileInfo); return eventRankingsParser.Parse(); } private Student[] GetStudents(IList events) { var fileInfo = FileUtility.GetContentFile(ContentDirectory, "2024-25 RMS TSA student & eventDefinition - Nationals Student EventDefinition Rankings.csv"); var eventRankingsParser = new StudentParser(fileInfo); return eventRankingsParser.Parse(events); } public static StudentEventRanking[] GetStudentEventRankings(Student[] students, EventDefinition[] events) { var fileInfo = FileUtility.GetContentFile(ContentDirectory, "2024-25 RMS TSA - Student Event Rankings.csv"); var rankingParser = new StudentEventRankingParser(fileInfo); return rankingParser.Parse(students, events); } public Team[] GetTeams(IList competitiveEvents, IList students) { var studentEventRankingsCsv = "2024-25 RMS TSA student & eventDefinition - Nationals Teams.csv"; var fileInfo = FileUtility.GetContentFile(ContentDirectory, studentEventRankingsCsv); var eventRankingsParser = new TeamParser(fileInfo); var teams = eventRankingsParser.Parse(competitiveEvents, students); foreach (var student in students) { student.Teams = teams.Where(t => t.Students.Contains(student)).ToList(); } return teams; } public AssignmentAssumption[] GetAssignmentAssumptions(IList competitiveEvents, IList students) { var assumptionsCsv = "2024-25 RMS TSA student & eventDefinition - assumptions.csv"; var fileInfo = FileUtility.GetContentFile(ContentDirectory, assumptionsCsv); var assumptionParser = new AssignmentAssumptionParser(fileInfo); var assumptions = assumptionParser.Parse(competitiveEvents, students); return assumptions; } public IDictionary> GetStateEventOccurrences(IList competitiveEvents) { var eventTimesFilename = "2025 TN TSA State Competition EventDefinition Times.txt"; var fileInfo = FileUtility.GetContentFile(ContentDirectory, eventTimesFilename); var parser = new EventOccurrenceParser(fileInfo, competitiveEvents); return parser.Parse(); } public IDictionary> GetNationalEventOccurrences(IList competitiveEvents) { var eventTimesFilename = "2025 TSA Nationals Competition EventDefinition Times.txt"; var fileInfo = FileUtility.GetContentFile(ContentDirectory, eventTimesFilename); var parser = new EventOccurrenceParser(fileInfo, competitiveEvents); var nationalEventOccurrences = parser.Parse(); var locationPrefixes = new[] { "Cheekwood", "Ryman", "Lincoln", "Canal", "Online", "Magnolia", "Tennessee", "Bayou", "Hermitage", "Belmont", "Davidson", "Washington", "Belle Meade"}; var oredLocations = string.Join("|", locationPrefixes); var regex = new Regex($"^(.*)((?:{oredLocations}).*)"); foreach (var occurrence in nationalEventOccurrences) { foreach (var eventOccurrence in occurrence.Value) { if (!string.IsNullOrEmpty(eventOccurrence.Location)) continue; var match = regex.Match(eventOccurrence.Name); if (!match.Success) continue; eventOccurrence.Name = match.Groups[1].Value.Trim(); eventOccurrence.Location = match.Groups[2].Value.Trim(); } } return nationalEventOccurrences; } private readonly ILogger _logger; public HomeController(ILogger logger) { _logger = logger; } public IActionResult Index() { return View(); } public IActionResult Events() { var competitiveEvents = GetEvents().Where(e => e.Name != "Chapter Team").ToArray(); return View(competitiveEvents); } public IActionResult StudentEventHandout() { var competitiveEvents = GetEvents(); var students = GetStudents(competitiveEvents); var teams = GetTeams(competitiveEvents, students); return View(Tuple.Create(students)); } public IActionResult StudentEvents() { var events = GetEvents(); var students = GetStudents(events); var rankings = GetStudentEventRankings(students, events); var eventStudentPicksArray = StudentEventRanking.GetEventStudentRankings(rankings); var assignmentParameters = new AssignmentParameters { EffortUpperBound = 9, RequireOnSite = true, RequireRegional = true, TeamSizeLimit = 4 }; var eventAssignment = new EventAssigner(events, students, assignmentParameters); var assignmentAssumptions = GetAssignmentAssumptions(events, students); foreach (var assumption in assignmentAssumptions) { switch (assumption.Assumption) { case Assumption.Exclude: eventAssignment.ExcludeFromEvent(assumption.EventAssignment); break; case Assumption.Include: eventAssignment.AssignToEvent(assumption.EventAssignment); break; } } eventAssignment.RemoveEvent(new List { events.First(e => e.Name == "Chapter Team") }); eventAssignment.IncludedEvents(new List { //competitiveEvents.First(e => e.Name == "System Control Technology") }); var eventAssignmentsList = eventAssignment.Solve(); return View(Tuple.Create(events, students, eventStudentPicksArray, eventAssignmentsList, assignmentParameters)); } public IActionResult Teams() { var competitiveEvents = GetEvents(); var students = GetStudents(competitiveEvents); var teams = GetTeams(competitiveEvents, students); //teams = teams.Where(t => t.EventDefinition.RegionalEvent).ToArray(); return View(Tuple.Create(teams)); } public IActionResult Regionals() { var competitiveEvents = GetEvents(); var students = GetStudents(competitiveEvents); var teams = GetTeams(competitiveEvents, students); teams = teams.Where(t => t.EventDefinition.RegionalEvent).ToArray(); var enumerable = students.Where(s => !teams.SelectMany(ts => ts.Students).Contains(s)).ToArray(); return View(Tuple.Create(teams, enumerable)); } public IActionResult State() { var competitiveEvents = GetEvents(); var students = GetStudents(competitiveEvents); var teams = GetTeams(competitiveEvents, students); var eventOccurrences = GetStateEventOccurrences(competitiveEvents); // Filter out pre-conference eventOccurrences = (from kv in eventOccurrences let newV = kv.Value.Where(eo => !eo.Name.Contains("Pre-Conference")) select Tuple.Create(kv.Key, newV)) .ToDictionary(s => s.Item1, s => s.Item2.ToList()); return View(Tuple.Create(teams, students, eventOccurrences)); } public IActionResult Nationals() { var competitiveEvents = GetEvents(); var students = GetStudents(competitiveEvents); var teams = GetTeams(competitiveEvents, students); var eventOccurrences = GetNationalEventOccurrences(competitiveEvents); // Filter out pre-conference eventOccurrences = (from kv in eventOccurrences let newV = kv.Value.Where(eo => !eo.Name.Contains("Pre-Conference")) select Tuple.Create(kv.Key, newV)) .ToDictionary(s => s.Item1, s => s.Item2.ToList()); return View(Tuple.Create(teams, students, eventOccurrences)); } public IActionResult TeamGrid() { var competitiveEvents = GetEvents(); var students = GetStudents(competitiveEvents); var teams = GetTeams(competitiveEvents, students); return View(Tuple.Create(teams, students)); } public IActionResult Students() { var competitiveEvents = GetEvents(); var students = GetStudents(competitiveEvents); GetTeams(competitiveEvents, students); return View(Tuple.Create(students)); } public static Func And(params Func[] predicates) { return t => predicates.All(predicate => predicate(t)); } public IActionResult Schedule() { var scheduleOptions = new ScheduleOptions( timeSlots: 3, mustIncludeEvents:new [] { "Medical Technology", "Electrical Applications" //, "RegionalTeam", ,"Dragster", "Flight" }, extended: new string[] { "Invention", "Construction Challenge", "Mechanical", "Mass", "Micro" //"STEM" //"Community", "Vlogging"// "Microcontroller" }, omittedEvents: new string[] { "Vlogging", "Junior", "Community Service Video", "Digital Photography", "STEM" //"Leadership",// "Electrical", //"Construction" // "Forensic", //"CAD" //"I&I Team 1", "I&I Team 2"//, "Website Design", }, absentStudents: new string[] { //"Eliam" }, reverse: true, slotPush:0); var events = GetEvents(); var students = GetStudents(events); var allTeams = GetTeams(events, students); var omittedEvents = allTeams.Where(t => scheduleOptions.OmittedEvents?.Any(s => t.Name.Contains(s)) == true).ToArray(); allTeams = allTeams.Where(t => !omittedEvents.Contains(t)).ToArray(); bool RegionalPredicate(Team t) => t.EventDefinition.RegionalEvent; bool TeamPredicate(Team t) => t.EventDefinition.EventFormat is EventFormat.Team; bool RegionalTeamPredicate(Team t) => RegionalPredicate(t) && TeamPredicate(t); bool HighEffort(Team t) => t.EventDefinition.LevelOfEffort == 3; bool LowEffort(Team t) => t.EventDefinition.LevelOfEffort == 1; bool RegionalTeamSomeEffortPredicate(Team t) => RegionalTeamPredicate(t) && !LowEffort(t); bool IndividualPredicate(Team t) => t.EventDefinition.EventFormat is EventFormat.Individual; bool negativePredicate(Team t) => false; var mustIncludeTeams = from e in events from t in allTeams where t.EventDefinition == e && (scheduleOptions.MustIncludeEvents?.Any(s => s == "RegionalTeam") == true && RegionalTeamSomeEffortPredicate(t) || scheduleOptions.MustIncludeEvents?.Any( t.EventDefinition.Name.Contains) == true || HighEffort(t)) select t; Debug.WriteLine("Must Include: " + string.Join(", ", mustIncludeTeams.Select(t => t.ToStringWithIndividualAndRegional()))); Debug.WriteLine("Omitted: " + string.Join(", ", omittedEvents.Select(t => t.ToStringWithIndividualAndRegional()))); var teamScheduler = new TeamScheduler(mustIncludeTeams.ToArray(), scheduleOptions.TimeSlots); var schedule = teamScheduler.Solve(); //schedule = schedule.OrderByDescending(ts => new Random(schedule.GetHashCode() + 1).Next()).ToArray(); if (scheduleOptions.SlotPush != 0) { schedule = schedule.Skip(scheduleOptions.SlotPush).Concat(schedule.Take(scheduleOptions.SlotPush)) .ToArray(); } if (scheduleOptions.Reverse) schedule = schedule.Reverse().ToArray(); ////// extend schedules var extendedTeams = from t in allTeams where scheduleOptions.MustIncludeEvents?.Any(s => scheduleOptions.ExtendedTeams?.Any(et => t.Name.Contains(et)) == true) == true select t; foreach (var extendedTeam in extendedTeams) { schedule = new UnassignedStudentScheduler(allTeams, schedule).AddAdditionalTimeSlot(extendedTeam); } schedule = new UnassignedStudentScheduler(allTeams, schedule).ScheduleStrategy(UnassignedScheduleStrategy.LevelOfEffort); schedule = new UnassignedStudentScheduler(allTeams, schedule).ScheduleStrategy(UnassignedScheduleStrategy.BiggestGroup); schedule = new UnassignedStudentScheduler(allTeams, schedule).ScheduleStrategy(UnassignedScheduleStrategy.IndividualEvents); //schedule = new UnassignedStudentScheduler(allTeams, schedule).ScheduleStrategy(UnassignedScheduleStrategy.AnyNotMeetingAlready); var unassignedStudents = UnassignedStudentScheduler.UnassignedStudents(students, schedule).ToArray(); return View(Tuple.Create(schedule, unassignedStudents, scheduleOptions)); } public IActionResult Privacy() { return View(); } [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] public IActionResult Error() { return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); } } }