<?php
class Scheduler
{
public static function updateSchedule($locationid, $options, $openingTimes)
{
if ($openingTimes == '') {
self::deleteSchedule($locationid);
return false;
}
$nextexec = self::calculateNext($options, $openingTimes);
$json_options = json_encode($options);
if ($nextexec !== false) {
self::upsert($locationid, $nextexec['action'], $nextexec['time'], $json_options);
} else {
// All times are getting ignored because they are within 5 minutes of each other, delete possible db entries.
self::deleteSchedule($locationid);
}
return true;
}
public static function deleteSchedule($locationid)
{
Database::exec("DELETE FROM `reboot_scheduler`
WHERE locationid = :lid", ['lid' => $locationid]);
}
private static function calculateNext($options, $openingTimes)
{
$openingTimes = json_decode($openingTimes, true);
$now = time();
$openTimes = [];
$closeTimes = [];
foreach ($openingTimes as $row) {
if (!$options['wol'] && !$options['sd'])
continue;
if ($options['wol']) {
$open = explode(':', $row['openingtime']);
$openTime = $open[0] * 60 + $open[1] - $options['wol-offset'];
}
if ($options['sd']) {
$close = explode(':', $row['closingtime']);
$closeTime = $close[0] * 60 + $close[1] + $options['sd-offset'];
}
foreach ($row['days'] as $day) {
if ($options['wol']) {
$nextOpen = strtotime(date('Y-m-d H:i', strtotime($day . ' ' . $openTime . ' minutes')));
if ($nextOpen < $now) {
$openTimes[] = strtotime(date('Y-m-d H:i', strtotime('next ' . $day . ' ' . $openTime . ' minutes')));
} else {
$openTimes[] = $nextOpen;
}
}
if ($options['sd']) {
$nextClose = strtotime(date('Y-m-d H:i', strtotime($day . ' ' . $closeTime . ' minutes')));
if ($nextClose < $now) {
$closeTimes[] = strtotime(date('Y-m-d H:i', strtotime('next ' . $day . ' ' . $closeTime . ' minutes')));
} else {
$closeTimes[] = $nextClose;
}
}
}
}
sort($openTimes);
sort($closeTimes);
$res = [];
if ($options['wol'] && !$options['sd']) {
$res['action'] = 'wol';
$res['time'] = $openTimes[0];
return $res;
} else if ($options['sd'] && !$options['wol']) {
$res['action'] = 'sd';
$res['time'] = $closeTimes[0];
return $res;
}
for ($i = 0; $i <= sizeof($openTimes); $i++) {
if (abs($openTimes[$i] - $closeTimes[$i]) < 300) {
// If difference is < 5 min, ignore both events.
continue;
} elseif (abs($openTimes[$i] - $closeTimes[$i]) < 900) {
// If difference is < 15 min, reboot at the earlier time.
$res['action'] = 'rb';
$res['time'] = $openTimes[$i] < $closeTimes[$i] ? $openTimes[$i] : $closeTimes[$i];
} else {
// Use first event.
if ($openTimes[$i] < $closeTimes[$i]) {
$res['action'] = 'wol';
$res['time'] = $openTimes[$i];
} else {
$res['action'] = 'sd';
$res['time'] = $closeTimes[$i];
}
}
return $res;
}
return false;
}
private static function upsert($locationid, $action, $nextexec, $options)
{
$schedule = Database::queryFirst("SELECT locationid
FROM `reboot_scheduler`
WHERE locationid = :lid", [
'lid' => $locationid
]);
if ($schedule === false) {
Database::exec("INSERT INTO `reboot_scheduler` (locationid, action, nextexecution, options)
VALUES (:lid, :act, :next, :opt)", [
'lid' => $locationid,
'act' => $action,
'next' => $nextexec,
'opt' => $options
]);
} else {
Database::exec("UPDATE `reboot_scheduler`
SET action = :act, nextexecution = :next, options = :opt
WHERE locationid = :lid", [
'act' => $action,
'next' => $nextexec,
'opt' => $options,
'lid' => $locationid
]);
}
return true;
}
}