/home/techb158/workloadmatch.com/Manager/Inc
Edit: /home/techb158/workloadmatch.com/Manager/Inc/ScheduleGenerator.php (8811B)
db = $db;
$this->engine = new ScheduleEngine($db);
}
public function generate(int $programId, int $groupId, string $startDate, ?string $endDate, array $selectedCourses, array $priorityCourses = []): array {
$endDate = $endDate ?: date('Y-m-d', strtotime('+1 year', strtotime($startDate)));
$group = $this->engine->getGroupInfo($groupId);
if (!$group) {
throw new RuntimeException("Group info not found for Group_ID: $groupId");
}
$classDays = explode(',', $group['class_days']);
if (!$group['Weekend_Class'] && in_array('Saturday', $classDays)) {
$classDays = array_filter($classDays, fn($day) => $day !== 'Saturday');
}
$slotLabels = explode(',', $group['Time_Slot']);
$managerStart = new DateTime(trim($group['Time_From']));
$managerEnd = new DateTime(trim($group['Time_To']));
[$timeFrom, $timeTo] = $this->engine->fetchSlotTimes($slotLabels, $managerStart, $managerEnd);
$sessionLength = $this->engine->calculateSessionLength($timeFrom, $timeTo);
$courseSessions = $this->engine->calculateCourseSessions($programId, $sessionLength);
$holidayDates = $this->engine->getHolidays($startDate);
$retakeDates = $this->engine->getRetakeDates($programId, $groupId);
$validDates = $this->engine->generateValidDates($startDate, $endDate, $classDays, $holidayDates, $retakeDates);
$courseNames = $this->engine->getCourseNames();
$sortedCourses = $selectedCourses;
usort($sortedCourses, function ($a, $b) use ($priorityCourses) {
$priorityA = $priorityCourses[$a] ?? PHP_INT_MAX;
$priorityB = $priorityCourses[$b] ?? PHP_INT_MAX;
return $priorityA <=> $priorityB;
});
$schedule = $this->buildSchedule($sortedCourses, $courseSessions, $validDates, $timeFrom, $timeTo, $slotLabels);
$lastSessions = $this->getLastSessions($schedule);
$displayDates = $this->buildDisplayDates($schedule, $holidayDates, $retakeDates);
return [
'schedule' => $schedule,
'displayDates' => $displayDates,
'lastSessions' => $lastSessions,
'courseNames' => $courseNames,
'slotLabels' => $slotLabels,
'holidayDates' => $holidayDates,
'retakeDates' => $retakeDates,
'timeFrom' => $timeFrom,
'timeTo' => $timeTo,
];
}
private function buildSchedule(array $selectedCourses, array $courseSessions, array $validDates, array $timeFrom, array $timeTo, array $slotLabels): array {
$schedule = [];
$remainingSessions = [];
foreach ($selectedCourses as $courseID) {
$remainingSessions[$courseID] = $courseSessions[$courseID] ?? 0;
}
$courseQueue = $selectedCourses;
$currentCourses = [0 => null, 1 => null];
$assignedCourses = [];
foreach ([0, 1] as $slotIndex) {
foreach ($courseQueue as $courseID) {
if (!in_array($courseID, $assignedCourses) && ($remainingSessions[$courseID] ?? 0) > 0) {
$currentCourses[$slotIndex] = $courseID;
$assignedCourses[] = $courseID;
break;
}
}
}
foreach ($validDates as $date) {
foreach ([0, 1] as $slotIndex) {
$from = $timeFrom[$slotIndex] ?? null;
$to = $timeTo[$slotIndex] ?? null;
if (!$from || !$to || !isset($currentCourses[$slotIndex]) || !$currentCourses[$slotIndex]) continue;
$courseID = $currentCourses[$slotIndex];
$schedule[] = [
'Date' => $date,
'Slot' => "Slot " . ($slotIndex + 1),
'Time' => $this->engine->formatTimeSlotRange($slotLabels[$slotIndex], $from, $to, (new DateTime($date))->format('l')),
'Course_ID' => $courseID,
];
$remainingSessions[$courseID]--;
if (($remainingSessions[$courseID] ?? 0) <= 0) {
$currentCourses[$slotIndex] = null;
while (!empty($courseQueue)) {
$nextCourse = array_shift($courseQueue);
if (($remainingSessions[$nextCourse] ?? 0) > 0) {
$currentCourses[$slotIndex] = $nextCourse;
break;
}
}
}
}
if (!$currentCourses[0] && !$currentCourses[1]) break;
}
return $schedule;
}
private function getLastSessions(array $schedule): array {
$lastSessions = [];
foreach ($schedule as $index => $entry) {
$lastSessions[$entry['Course_ID']] = $index;
}
return $lastSessions;
}
private function buildDisplayDates(array $schedule, array $holidayDates, array $retakeDates): array {
$displayDates = [];
foreach ($schedule as $row) {
$displayDates[$row['Date']][] = $row;
}
foreach ($holidayDates as $hDate) {
if (!isset($displayDates[$hDate])) {
$displayDates[$hDate] = [];
}
}
foreach ($retakeDates as $rDate) {
if (!isset($displayDates[$rDate])) {
$displayDates[$rDate] = [];
}
}
ksort($displayDates);
return $displayDates;
}
public function renderHtml(array $result): string {
$displayDates = $result['displayDates'];
$lastSessions = $result['lastSessions'];
$courseNames = $result['courseNames'];
$slotLabels = $result['slotLabels'];
$holidayDates = $result['holidayDates'];
$retakeDates = $result['retakeDates'];
if (empty($displayDates)) {
return '
No schedule generated.
';
}
$html = '
';
$html .= '
';
$html .= '| Date | Slot | Time | Course | Action |
';
foreach ($displayDates as $date => $rows) {
$isHoliday = in_array($date, $holidayDates);
$isRetake = in_array($date, $retakeDates);
if (empty($rows)) {
$label = $isHoliday ? 'Holiday' : 'Retake Day';
$bg = $isHoliday ? '#FFD700' : '#CCE5FF';
$html .= "| $date | $label |
";
continue;
}
foreach ($rows as $row) {
$courseName = $courseNames[$row['Course_ID']] ?? "Course ID {$row['Course_ID']}";
$index = array_search($row, $result['schedule']);
$isExam = isset($lastSessions[$row['Course_ID']]) && $index === $lastSessions[$row['Course_ID']];
$dayName = (new DateTime($row['Date']))->format('l');
$isSaturday = ($dayName === 'Saturday');
$slotIndex = (int)filter_var($row['Slot'], FILTER_SANITIZE_NUMBER_INT) - 1;
$slotName = $this->engine->formatTimeSlotLabel($slotLabels[$slotIndex] ?? '', $dayName);
$style = '';
if ($isHoliday) {
$style = "style='background-color: #FFD700;'";
} elseif ($isRetake) {
$style = "style='background-color: #CCE5FF;'";
} elseif ($isExam) {
$style = "style='background-color: #FFCCCC; font-weight: bold;'";
}
$examLabel = $isExam ? ' (Exam Day)' : '';
$action = '-';
if ($isSaturday) {
$action = "
";
}
$html .= "
| ($dayName) {$row['Date']} |
{$slotName} |
{$row['Time']} |
{$courseName}{$examLabel} |
{$action} |
";
}
}
$html .= '
';
return $html;
}
}