using HSchool.Content; using HSchool.People; using HSchool.Schedule; namespace HSchool.Ai; /// /// Where this person ought to be right now. The timetable and the job, not the walk graph. /// public static class Duty { /// /// The room of the current obligation, or when they should be off campus. /// A hole in the class table sends the pupil to their homeroom. /// public static string? RoomAt( Person person, SchoolClass? schoolClass, Timetable? timetable, DefCatalog catalog, DateTime time, int weekDays) { ArgumentNullException.ThrowIfNull(person); ArgumentNullException.ThrowIfNull(catalog); if (!ComesToday(person, timetable, catalog, time, weekDays)) { return null; } if (IsOtherStaff(person)) { return person.WorkplaceRoomId; } var utc = DateTime.SpecifyKind(time, DateTimeKind.Utc); if (!SchoolDay.IsWorkday(catalog, utc, weekDays)) { return null; } var slot = SchoolDay.At(catalog, utc, weekDays); var day = SchoolDay.WeekdayIndex(utc); var lessons = LessonsToday(person, schoolClass, timetable, day); if (lessons.Count == 0) { return person.WorkplaceRoomId; } if (slot.Kind == DaySlotKind.Lesson) { var current = lessons.FirstOrDefault(lesson => lesson.Period == slot.Index); if (current is not null) { return current.RoomId; } return schoolClass?.RoomId ?? person.WorkplaceRoomId; } if (slot.Kind == DaySlotKind.Break) { var next = lessons.Where(lesson => lesson.Period > slot.Index).OrderBy(lesson => lesson.Period).FirstOrDefault(); return next?.RoomId ?? schoolClass?.RoomId ?? person.WorkplaceRoomId; } var frame = catalog.DayFrame; if (frame is not null && SchoolDay.TryParseTime(frame.FirstLesson, out var first) && utc.TimeOfDay < first.ToTimeSpan()) { return lessons[0].RoomId; } if (frame is not null && SchoolDay.TryLastBell(catalog, out var last) && utc.TimeOfDay >= last.ToTimeSpan()) { return null; } return lessons[0].RoomId; } public static bool ComesToday( Person person, Timetable? timetable, DefCatalog catalog, DateTime time, int weekDays) { if (person.IsParent && !person.IsStaff && !person.IsStudent) { return false; } if (!SchoolDay.IsWorkday(catalog, time, weekDays)) { return false; } if (IsOtherStaff(person)) { return true; } var day = SchoolDay.WeekdayIndex(time); if (person.IsStudent) { return timetable?.Lessons.Any(lesson => lesson.ClassId == person.ClassId && lesson.Day == day) == true; } if (person.IsStaff) { return timetable?.Lessons.Any(lesson => lesson.TeacherId == person.Id && lesson.Day == day) == true; } return false; } public static bool IsOtherStaff(Person person) => person.IsStaff && !Staffing.TeacherPosition.Equals(person.Position, StringComparison.Ordinal); public static IReadOnlyList LessonsToday( Person person, SchoolClass? schoolClass, Timetable? timetable, int day) { if (timetable is null) { return []; } if (person.IsStudent) { var classId = person.ClassId ?? schoolClass?.Id; return timetable.Lessons .Where(lesson => lesson.ClassId == classId && lesson.Day == day) .OrderBy(lesson => lesson.Period) .ToArray(); } if (person.IsStaff) { return timetable.Lessons .Where(lesson => lesson.TeacherId == person.Id && lesson.Day == day) .OrderBy(lesson => lesson.Period) .ToArray(); } return []; } }