/home/techb158/workloadmatch.com/Manager
Edit: /home/techb158/workloadmatch.com/Manager/ajax_replace_saturday_backup_latest.php (31474B)
prepare("SELECT Time_Slot, Time_From, Time_To, class_days, Weekend_Class FROM manager_group_name WHERE Group_ID = ?");
$stmt->bind_param("i", $groupID);
$stmt->execute();
return $stmt->get_result()->fetch_assoc();
}
// Fetch slot times
function fetch_slot_times($mysqli, $slotLabels, $managerStart, $managerEnd) {
$timeFrom = [];
$timeTo = [];
foreach ($slotLabels as $label) {
$stmt = $mysqli->prepare("SELECT Time_From, Time_To FROM time_slot_programs WHERE Time_Slot = ?");
$stmt->bind_param("s", $label);
$stmt->execute();
$res = $stmt->get_result();
if ($row = $res->fetch_assoc()) {
$timeFrom[] = $row['Time_From'];
$timeTo[] = $row['Time_To'];
} else {
$timeFrom[] = $managerStart->format('H:i:s');
$timeTo[] = $managerEnd->format('H:i:s');
}
}
return [$timeFrom, $timeTo];
}
// Fetch holidays
function get_holidays($mysqli, $startDate) {
$holidays = [];
$res = $mysqli->query("SELECT Event_Start, Event_End FROM Events WHERE Calendar_Year = YEAR('$startDate')");
while ($row = $res->fetch_assoc()) {
$start = new DateTime($row['Event_Start']);
$end = new DateTime($row['Event_End']);
while ($start <= $end) {
$holidays[] = $start->format('Y-m-d');
$start->modify('+1 day');
}
}
return $holidays;
}
// Fetch retake dates
function get_retake_dates($mysqli, $programID, $groupID) {
$retakes = [];
$stmt = $mysqli->prepare("SELECT Retake_Date FROM retake_records WHERE Program_ID = ? AND Group_ID = ?");
$stmt->bind_param("ii", $programID, $groupID);
$stmt->execute();
$res = $stmt->get_result();
while ($row = $res->fetch_assoc()) {
$retakes[] = $row['Retake_Date'];
}
return $retakes;
}
// Generate all valid class dates, excluding holidays, retakes, and July
function generate_valid_dates($Start_Date, $End_Date, $classDays, $holidayDates, $retakeDates) {
$validDates = [];
$cur = new DateTime($Start_Date);
$end = $End_Date ? new DateTime($End_Date) : null;
while (!$end || $cur <= $end) {
$day = $cur->format('l');
$dateStr = $cur->format('Y-m-d');
$month = (int)$cur->format('m');
// ✅ Check holidays and retakes FIRST
if (in_array($dateStr, $holidayDates)) {
$validDates[] = ['Date' => $dateStr, 'Type' => 'Holiday'];
} elseif (in_array($dateStr, $retakeDates)) {
$validDates[] = ['Date' => $dateStr, 'Type' => 'Retake'];
}
// ✅ Then check for valid class day (not July, must be in classDays)
elseif ($month !== 7 && in_array($day, $classDays)) {
$validDates[] = ['Date' => $dateStr, 'Type' => 'Class'];
}
$cur->modify('+1 day');
if ($end === null && count($validDates) > 500) break;
}
return $validDates;
}
// Calculate the average duration of one session
function calculate_session_length($timeFrom, $timeTo) {
$sessionLength = 0;
foreach ($timeFrom as $i => $from) {
$fromTime = new DateTime($from);
$toTime = new DateTime($timeTo[$i]);
$sessionLength += ($toTime->getTimestamp() - $fromTime->getTimestamp()) / 3600;
}
$slotCount = count($timeFrom);
return $slotCount > 0 ? $sessionLength / $slotCount : 3;
}
// Calculate the number of sessions required for each course
function calculate_course_sessions($mysqli, $Program_ID, $sessionLength) {
$courseSessions = [];
$res = $mysqli->query("SELECT Course_ID, Course_Time FROM Courses WHERE Program_ID = $Program_ID");
while ($row = $res->fetch_assoc()) {
$courseID = $row['Course_ID'];
$courseHours = $row['Course_Time'];
$courseSessions[$courseID] = ceil($courseHours / $sessionLength);
}
return $courseSessions;
}
// --- MAIN LOGIC --- //
/*
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$saturdayDate = $_POST['date'] ?? '';
$programID = intval($_POST['Program_ID'] ?? 0);
$groupID = intval($_POST['Group_ID'] ?? 0);
$startDate = $_POST['Start_Date'] ?? '';
$selectedCourses = json_decode(urldecode($_POST['Selected_Courses'] ?? '[]'), true);
$priorityCourses = json_decode(urldecode($_POST['Priority_Course'] ?? '{}'), true);
if (!$programID || !$groupID || !$saturdayDate || !$startDate || empty($selectedCourses)) {
echo json_encode(['status' => 'error', 'message' => 'Missing required fields.']);
exit;
}
$group = get_group_info($mysqli, $groupID);
if (!$group) {
echo json_encode(['status' => 'error', 'message' => 'Group not found.']);
exit;
}
$classDays = array_map('trim', explode(',', $group['class_days']));
$slotLabels = array_map('trim', explode(',', $group['Time_Slot']));
$managerStart = new DateTime($group['Time_From']);
$managerEnd = new DateTime($group['Time_To']);
list($timeFrom, $timeTo) = fetch_slot_times($mysqli, $slotLabels, $managerStart, $managerEnd);
$holidayDates = get_holidays($mysqli, $startDate);
$retakeDates = get_retake_dates($mysqli, $programID, $groupID);
// 🧹 Find the next valid weekday (limit to 20 days)
$cur = new DateTime($saturdayDate);
$cur->modify('+1 day');
$replacementDate = null;
$attempts = 0;
while ($attempts < 20) {
$day = $cur->format('l');
$dateStr = $cur->format('Y-m-d');
if ($day !== 'Saturday' && in_array($day, $classDays) && !in_array($dateStr, $holidayDates) && !in_array($dateStr, $retakeDates)) {
$replacementDate = $dateStr;
break;
}
$cur->modify('+1 day');
$attempts++;
}
if (!$replacementDate) {
echo json_encode(['status' => 'error', 'message' => 'No available weekday found within 20 days.']);
exit;
}
// 🎯 Sort courses by priority
usort($selectedCourses, function($a, $b) use ($priorityCourses) {
return ($priorityCourses[$a] ?? PHP_INT_MAX) <=> ($priorityCourses[$b] ?? PHP_INT_MAX);
});
$courseID = $selectedCourses[0];
// Fetch course name
$res = $mysqli->query("SELECT Course_Name FROM Courses WHERE Course_ID = $courseID");
$courseData = $res->fetch_assoc();
$courseName = $courseData ? $courseData['Course_Name'] : "Course ID $courseID";
// 🎨 Prepare new HTML row
$dayName = (new DateTime($replacementDate))->format('l');
$slotName = format_time_slot_label($slotLabels[0] ?? 'Morning', $dayName);
$timeRange = format_time_slot_range($slotLabels[0] ?? 'Morning', $timeFrom[0] ?? '08:30', $timeTo[0] ?? '12:30', $dayName);
$newRowHtml = "
| ($dayName) $replacementDate |
$slotName |
$timeRange |
$courseName |
- |
";
echo json_encode([
'status' => 'success',
'original' => $saturdayDate,
'replacement' => $replacementDate,
'newRowHtml' => $newRowHtml
]);
exit;
}
*/
// ------------------- Functions -------------------
function getNextCourseForSlot($remainingSessions, $courseList, $usedToday) {
$available = array_filter($courseList, function($courseID) use ($remainingSessions) {
return ($remainingSessions[$courseID] ?? 0) > 0;
});
$unusedToday = array_filter($available, fn($courseID) => !in_array($courseID, $usedToday));
if (!empty($unusedToday)) {
return reset($unusedToday);
}
// Allow reuse only if it's the last course left
if (count($available) === 1) {
return reset($available);
}
return null;
}
// Handle AJAX request
// Handle AJAX request
// MAIN START
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$Program_ID = intval($_POST['Program_ID'] ?? 0);
$Group_ID = intval($_POST['Group_ID'] ?? 0);
$Start_Date = $_POST['Start_Date'] ?? '';
$Removed_Date = $_POST['date'] ?? '';
$selectedCourses = json_decode($_POST['Selected_Courses'] ?? '[]', true) ?? [];
$priorityCourses = json_decode($_POST['Priority_Course'] ?? '{}', true) ?? [];
$Course_Sessions = json_decode($_POST['Course_Sessions'] ?? '{}', true) ?? [];
/* file_put_contents(__DIR__."/debug_sessions.log", print_r([
'RAW' => $_POST['Course_Sessions'],
'PARSED' => $Course_Sessions
], true)); */
$group = get_group_info($mysqli, $Group_ID);
if (!$group) {
echo json_encode(['status' => 'error', 'message' => 'Group not found']);
exit;
}
$classDays = array_map('trim', explode(',', $group['class_days']));
//$slotLabels = explode(',', $group['Time_Slot']);
$managerStart = new DateTime(trim($group['Time_From']));
$managerEnd = new DateTime(trim($group['Time_To']));
//list($timeFrom, $timeTo) = fetch_slot_times($mysqli, $slotLabels, $managerStart, $managerEnd);
$stmt = $mysqli->prepare("SELECT Group_Slot_ID, Time_Slot, Time_From, Time_To FROM group_slot_mapping WHERE Group_ID = ?");
$stmt->bind_param("i", $Group_ID);
$stmt->execute();
$res = $stmt->get_result();
//$group_slot_id = []; // <- Add this before the while loop
$slotLabels = $timeFrom = $timeTo = [];
//while ($row = $res->fetch_assoc()) {
// $slotLabels[] = $row['Time_Slot'];
// $timeFrom[] = $row['Time_From'];
// $timeTo[] = $row['Time_To'];
// //$group_slot_id[] = $row['Group_Slot_ID'];
//}
$slotData = []; // holds each slot's full data
while ($row = $res->fetch_assoc()) {
$slotLabels[] = $row['Time_Slot'];
$timeFrom[] = $row['Time_From'];
$timeTo[] = $row['Time_To'];
$slotData[] = [
'Group_Slot_ID' => $row['Group_Slot_ID'],
'Time_Slot' => $row['Time_Slot'],
'Time_From' => $row['Time_From'],
'Time_To' => $row['Time_To']
];
}
$sessionLength = calculate_session_length($timeFrom, $timeTo);
$holidayDates = get_holidays($mysqli, $Start_Date);
$retakeDates = get_retake_dates($mysqli, $Program_ID, $Group_ID);
// Generate valid dates
$validDates = generate_valid_dates($Start_Date, null, $classDays, $holidayDates, $retakeDates);
// Replace the Saturday with the next available weekday
$replacementDate = null;
$cur = new DateTime($Removed_Date);
$cur->modify('+1 day');
$attempts = 0;
while ($attempts < 20) {
$day = $cur->format('l');
$dateStr = $cur->format('Y-m-d');
if ($day !== 'Saturday' && in_array($day, $classDays) && !in_array($dateStr, $holidayDates) && !in_array($dateStr, $retakeDates)) {
$replacementDate = $dateStr;
break;
}
$cur->modify('+1 day');
$attempts++;
}
if (!$replacementDate) {
echo json_encode(['status' => 'error', 'message' => 'No available replacement weekday found within 20 days.']);
exit;
}
// Remove the replaced Saturday, insert the replacement date
$reindexed = [];
foreach ($validDates as $entry) {
if ($entry['Date'] === $Removed_Date) continue;
$reindexed[] = $entry;
}
$reindexed[] = ['Date' => $replacementDate, 'Type' => 'Class'];
// Sort by date to keep chronological order
usort($reindexed, function ($a, $b) {
return strcmp($a['Date'], $b['Date']);
});
$validDates = $reindexed;
unset($reindexed);
/////////////////////////////////////////////////////////
// Reorder courses by priority
if (!empty($priorityCourses)) {
usort($selectedCourses, function($a, $b) use ($priorityCourses) {
return ($priorityCourses[$a] ?? PHP_INT_MAX) <=> ($priorityCourses[$b] ?? PHP_INT_MAX);
});
}
$courseNames = [];
$res = $mysqli->query("SELECT Course_ID, Course_Name FROM Courses WHERE Program_ID = $Program_ID");
while ($row = $res->fetch_assoc()) {
$courseNames[$row['Course_ID']] = $row['Course_Name'];
}
$courseSessions = [];
foreach ($selectedCourses as $courseID) {
// Only use the parsed $Course_Sessions array!
$custom = $Course_Sessions[$courseID] ?? null;
$courseSessions[$courseID] = (is_numeric($custom) && $custom > 0) ? intval($custom) : 0;
}
/* // Use custom sessions from the parsed JSON array
$courseSessions = [];
foreach ($selectedCourses as $courseID) {
$custom = $Course_Sessions[$courseID] ?? null;
if (is_numeric($custom) && intval($custom) > 0) {
$courseSessions[$courseID] = intval($custom);
} else {
// If not set or invalid, you can fall back to suggested (optional)
$courseSessions[$courseID] = 0; // or use $suggestedSessions[$courseID] ?? 0;
}
} */
$remainingSessions = [];
foreach ($selectedCourses as $courseID) {
$remainingSessions[$courseID] = $courseSessions[$courseID] ?? 0;
}
/* file_put_contents(__DIR__.'/debug_final_sessions.log', print_r([
'selectedCourses' => $selectedCourses,
'Course_Sessions' => $Course_Sessions,
'courseSessions' => $courseSessions,
'remainingSessions' => $remainingSessions,
], true)); */
//// Build schedule
$html = "";
$html .= "
";
////$html = "";
$html .= "| Date | Slot | Time | Course | Action |
";
//$html = '';
//$html .= '| Date | Slot | Time | Course | Action |
';
$currentCourse = reset($selectedCourses);
$slotCount = count($slotLabels);
$slotIndex = 0;
$ajaxScheduleData=[];
foreach ($validDates as $entry) {
$date = $entry['Date'];
$dayName = (new DateTime($date))->format('l');
$type = $entry['Type'];
if ($type === 'Holiday') {
$html .= "
| ($dayName) $date |
- |
- |
HOLIDAY |
- |
";
continue;
}
if ($type === 'Retake') {
$html .= "
| ($dayName) $date |
- |
- |
RETAKE |
- |
";
continue;
}
if (!$currentCourse) break;
$slotLabel = format_time_slot_label($slotLabels[$slotIndex % $slotCount], $dayName);
$timeRange = format_time_slot_range($slotLabels[$slotIndex % $slotCount], $timeFrom[$slotIndex % $slotCount], $timeTo[$slotIndex % $slotCount], $dayName);
$examTag = ($remainingSessions[$currentCourse] == 1) ? ' (Exam Day)' : '';
$normalizedDate = (new DateTime($date))->format('Y-m-d');
if ($dayName === 'Saturday') {
$action = "";
} else {
$action = "-";
}
$slotDataCount = count($slotData);
if ($slotDataCount === 0) {
die("⌠Error: No slot data found for Group_ID = $Group_ID");
}
//$html .= "";
$currentSlot = $slotData[$slotIndex % count($slotData)];
$groupSlotID = $currentSlot['Group_Slot_ID'];
$slotLabel = $currentSlot['Time_Slot'];
$from = $currentSlot['Time_From'];
$to = $currentSlot['Time_To'];
$html .= "
";
$ajaxScheduleData[] = [
'program_id' => $Program_ID,
'course_id' => $currentCourse,
'course_name' => $courseNames[$currentCourse] ?? '',
'group_id' => $Group_ID,
'group_slot_id' => $groupSlotID,
'reserve_course' => 0,
'time_slot' => $slotLabel,
'start_date' => $date,
'end_date' => $date,
'start_time' => $from,
'end_time' => $to
];
$html .= "| ($dayName) $date | $slotLabel | $timeRange | {$courseNames[$currentCourse]}$examTag | $action | ";
$html .= "
";
$remainingSessions[$currentCourse]--;
if ($remainingSessions[$currentCourse] <= 0) {
$currentCourse = next($selectedCourses);
}
$slotIndex++;
}
//$html .= '
';
$html .= "
";
//$html = "
";
//$html .= "| Date | Slot | Time | Course | Action |
";
$html .= "| Date | Slot | Time | Course | Action |
";
//$html .= "
";
//$html .= "
//
//
";
/* $html .= "
";
echo "\n"; */
$html .= "";
echo json_encode([
'status' => 'success',
'html' => $html,
'ajaxScheduleData' => $ajaxScheduleData // <-- pass it always!
]);
exit;
}
function generateSchedule($mysqli, $Program_ID, $Group_ID, $Start_Date, $Removed_Date, $selectedCourses, $priorityCourses, $Course_Sessions){
//function generateSchedule($mysqli, $Program_ID, $Group_ID, $Start_Date, $Removed_Date, $selectedCourses, $priorityCourses) {
// Get group info
$group = get_group_info($mysqli, $Group_ID);
if (!$group) {
return 'Error: Group not found.
';
}
$classDays = explode(',', $group['class_days']);
$slotLabels = explode(',', $group['Time_Slot']);
$managerStart = new DateTime(trim($group['Time_From']));
$managerEnd = new DateTime(trim($group['Time_To']));
list($timeFrom, $timeTo) = fetch_slot_times($mysqli, $slotLabels, $managerStart, $managerEnd);
$sessionLength = calculate_session_length($timeFrom, $timeTo);
//$courseSessions = calculate_course_sessions($mysqli, $Program_ID, $sessionLength);
$courseSessions = [];
foreach ($selectedCourses as $courseID) {
$val = $Course_Sessions[$courseID] ?? 0;
$courseSessions[$courseID] = (is_numeric($val) && $val > 0) ? intval($val) : 0;
}
$holidayDates = get_holidays($mysqli, $Start_Date);
$retakeDates = get_retake_dates($mysqli, $Program_ID, $Group_ID);
$validDates = generate_valid_dates($Start_Date, null, $classDays, $holidayDates, $retakeDates);
$validDates = array_filter($validDates, function($date) use ($Removed_Date) {
return $date !== $Removed_Date;
});
$validDates = array_values($validDates);
if (!empty($priorityCourses)) {
usort($selectedCourses, function ($a, $b) use ($priorityCourses) {
return ($priorityCourses[$a] ?? PHP_INT_MAX) <=> ($priorityCourses[$b] ?? PHP_INT_MAX);
});
}
$remainingSessions = [];
foreach ($selectedCourses as $courseID) {
$remainingSessions[$courseID] = $courseSessions[$courseID] ?? 0;
}
$courseNames = [];
$res = $mysqli->query("SELECT Course_ID, Course_Name FROM Courses");
while ($row = $res->fetch_assoc()) {
$courseNames[$row['Course_ID']] = $row['Course_Name'];
}
$currentCourses = [null, null];
$htmlRows = [];
$examTag = ' (Exam Day)';
//$courseQueue = $selectedCourses; // copy for rotation
$ajaxScheduleData = [];
foreach ($validDates as $entry) {
$date = $entry['Date'];
$dayName = (new DateTime($date))->format('l');
$type = $entry['Type'];
if ($type === 'Holiday' || $type === 'Retake') {
$htmlRows[] = [
'Date' => $date,
'Day' => $dayName,
'Slot' => '',
'Time' => '',
'Course_Name' => strtoupper($type),
'IsExam' => false,
'Action' => '-'
];
continue;
}
$usedToday = [];
foreach (array_keys($slotLabels) as $slotIndex) {
$from = $timeFrom[$slotIndex] ?? null;
$to = $timeTo[$slotIndex] ?? null;
$slotLabel = $slotLabels[$slotIndex] ?? 'Unknown';
if (!$from || !$to) continue;
$courseID = getNextCourseForSlot($remainingSessions, $selectedCourses, $usedToday);
if (!$courseID) continue;
$isExam = ($remainingSessions[$courseID] === 1);
$usedToday[] = $courseID;
$remainingSessions[$courseID]--;
$action = ($dayName === 'Saturday' && !in_array($date, $deletedSaturdays))
? ""
: ($dayName === 'Saturday' ? '🗑Removed' : '-');
$htmlRows[] = [
'Date' => $date,
'Day' => $dayName,
'Slot' => $slotLabel,
'Time' => format_time_slot_range($slotLabel, $from, $to, $dayName),
'Course_Name' => $courseNames[$courseID] ?? "Course $courseID",
'IsExam' => $isExam,
'Action' => $action
];
$ajaxScheduleData[] = [
'program_id' => $Program_ID,
'course_id' => $courseID,
'course_name' => $courseNames[$courseID] ?? '',
'group_id' => $Group_ID,
'group_slot_id' => $slotIndex,
'reserve_course' => 0,
'time_slot' => $slotLabel,
'start_date' => $date, // or $normalizedDate if you format earlier
'end_date' => $date,
'start_time' => $from,
'end_time' => $to
];
if (array_sum($remainingSessions) <= 0) break 2; // Stop if everything is scheduled
}
}
$html = "";
$html .= "
";
$html .= "
";
//$html = "";
$html .= "| Date | Slot | Time | Course | Action |
";
foreach ($htmlRows as $row) {
// Ensure all required keys exist
$row['Slot'] = $row['Slot'] ?? '-';
$row['Time'] = $row['Time'] ?? '-';
$row['Course_Name'] = $row['Course_Name'] ?? '-';
$row['Action'] = $row['Action'] ?? '-';
$row['IsExam'] = $row['IsExam'] ?? false;
$examLabel = $row['IsExam'] ? ' (Exam Day)' : '';
$formattedDate = "({$row['Day']}) {$row['Date']}";
$html .= "";
$html .= "| {$formattedDate} | ";
$html .= "{$row['Slot']} | ";
$html .= "{$row['Time']} | ";
$html .= "{$row['Course_Name']}{$examLabel} | ";
$html .= "{$row['Action']} | ";
$html .= "
";
}
//foreach ($htmlRows as $row) {
// $examLabel = $row['IsExam'] ? ' (Exam Day)' : '';
// $formattedDate = "({$row['Day']}) {$row['Date']}";
//
// $html .= "";
// $html .= "| {$formattedDate} | ";
// $html .= "{$row['Slot']} | ";
// $html .= "{$row['Time']} | ";
// $html .= "{$row['Course_Name']}{$examLabel} | ";
// $html .= "{$row['Action']} | ";
// $html .= "
";
//}
//$html .= "
";
// Footer
$html .= "
| Date | Slot | Time | Course | Action |
|---|
";
$html .= "
";
//$html .= "
//
//
";
//$html .= "";
return $html;
}
// ⌠Fallback if not POST
http_response_code(405);
echo json_encode(['status' => 'error', 'message' => 'Invalid request method.']);
exit;
/*
function generateSchedule($mysqli, $Program_ID, $Group_ID, $Start_Date, $Removed_Date, $selectedCourses, $priorityCourses) {
// Get group info
$group = get_group_info($mysqli, $Group_ID);
if (!$group) {
return 'Error: Group not found.
';
}
$classDays = explode(',', $group['class_days']);
$slotLabels = explode(',', $group['Time_Slot']);
$managerStart = new DateTime(trim($group['Time_From']));
$managerEnd = new DateTime(trim($group['Time_To']));
list($timeFrom, $timeTo) = fetch_slot_times($mysqli, $slotLabels, $managerStart, $managerEnd);
$sessionLength = calculate_session_length($timeFrom, $timeTo);
// Courses & sessions
$courseSessions = calculate_course_sessions($mysqli, $Program_ID, $sessionLength);
// Load holidays & retakes
$holidayDates = get_holidays($mysqli, $Start_Date);
$retakeDates = get_retake_dates($mysqli, $Program_ID, $Group_ID);
// Generate valid dates
$validDates = generate_valid_dates($Start_Date, null, $classDays, $holidayDates, $retakeDates);
// Remove the Saturday we want to delete
$validDates = array_filter($validDates, function($date) use ($Removed_Date) {
return $date !== $Removed_Date;
});
$validDates = array_values($validDates); // Re-index after filtering
// Sort courses by priority
if (!empty($priorityCourses)) {
usort($selectedCourses, function ($a, $b) use ($priorityCourses) {
$priorityA = $priorityCourses[$a] ?? PHP_INT_MAX;
$priorityB = $priorityCourses[$b] ?? PHP_INT_MAX;
return $priorityA <=> $priorityB;
});
}
// Initialize scheduling
$schedule = [];
$remainingSessions = [];
foreach ($selectedCourses as $courseID) {
$remainingSessions[$courseID] = $courseSessions[$courseID] ?? 0;
}
// Course Names
$courseNames = [];
$res = $mysqli->query("SELECT Course_ID, Course_Name FROM Courses");
while ($row = $res->fetch_assoc()) {
$courseNames[$row['Course_ID']] = $row['Course_Name'];
}
// Main loop: assign courses
$courseQueue = $selectedCourses;
$currentCourses = [0 => null, 1 => null]; // Morning and Evening
foreach ([0, 1] as $slotIndex) {
foreach ($courseQueue as $courseID) {
if ($remainingSessions[$courseID] > 0) {
$currentCourses[$slotIndex] = $courseID;
break;
}
}
}
$examTag = ' (Exam Day)';
// Build schedule
$examDates = [];
foreach ($validDates as $date) {
$weekday = (new DateTime($date))->format('l');
foreach ([0, 1] as $slotIndex) {
$from = $timeFrom[$slotIndex] ?? null;
$to = $timeTo[$slotIndex] ?? null;
if (!$from || !$to || !$currentCourses[$slotIndex]) {
continue;
}
$courseID = $currentCourses[$slotIndex];
$isExam = false;
if (isset($remainingSessions[$courseID]) && $remainingSessions[$courseID] == 1) {
$isExam = true; // last session becomes exam
}
$schedule[] = [
'Date' => $date,
'Day' => $weekday,
'Slot' => $slotLabels[$slotIndex] ?? 'Unknown Slot',
'Time' => format_time_slot_range($slotLabels[$slotIndex], $from, $to, $weekday),
'Course_Name' => $courseNames[$courseID] ?? 'Unknown',
'IsExam' => $isExam
];
// Reduce sessions
$remainingSessions[$courseID]--;
if ($remainingSessions[$courseID] <= 0) {
$currentCourses[$slotIndex] = null;
while (!empty($courseQueue)) {
$nextCourseID = array_shift($courseQueue);
if ($remainingSessions[$nextCourseID] > 0) {
$currentCourses[$slotIndex] = $nextCourseID;
break;
}
}
}
}
if (!$currentCourses[0] && !$currentCourses[1]) {
break;
}
}
// Render HTML
$html = "";
$html .= "
";
$html .= "| Date | Slot | Time | Course | Action |
";
foreach ($schedule as $row) {
$formattedDate = "(" . $row['Day'] . ") " . $row['Date'];
$examLabel = $row['IsExam'] ? $examTag : '';
$action = (stripos($row['Day'], 'Saturday') !== false) ? "🧹 Replace" : "-";
$html .= "";
$html .= "| {$formattedDate} | ";
$html .= "{$row['Slot']} | ";
$html .= "{$row['Time']} | ";
$html .= "{$row['Course_Name']}{$examLabel} | ";
$html .= "{$action} | ";
$html .= "
";
}
$html .= "
";
return $html;
}
*/
?>