<?php
class Alarm
{
const MONDAY = 1;
const TUESDAY = 2;
const WEDNESDAY = 3;
const THURSDAY = 4;
const FRIDAY = 5;
const SATURDAY = 6;
const SUNDAY = 7;
private const ALL_DAYS = [
self::MONDAY,
self::TUESDAY,
self::WEDNESDAY,
self::THURSDAY,
self::FRIDAY,
self::SATURDAY,
self::SUNDAY
];
const TYPE_REPEATING = true;
const TYPE_NON_REPEATING = false;
const STATUS_ACTIVE = true;
const STATUS_INACTIVE = false;
private $time;
private $daysOfWeek;
private $type;
private $status;
public function __construct(int $hour, int $minute)
{
$this->setTime($hour, $minute);
$this->setDaysOfWeek(self::ALL_DAYS);
$this->setType(self::TYPE_REPEATING); $this->setStatus(self::STATUS_ACTIVE);
}
public function setTime(int $hour, int $minute): void
{
if ($hour > 23 || $hour < 0 || $minute > 60 || $minute < 0) {
throw new InvalidArgumentException('Неправильное время');
}
if ($hour < 10) {
$hour = 0..$hour;
}
if ($minute < 10) {
$minute = 0..$minute;
}
$this->time = $hour.':'.$minute; }
public function setDaysOfWeek
(array $daysOfWeek): void
{
foreach ($daysOfWeek as $dayOfWeek) {
if ($dayOfWeek > 7 || $dayOfWeek < 1) {
throw new InvalidArgumentException('Неправильное значение в массиве с днями недели');
}
}
$this->daysOfWeek = $daysOfWeek;
}
public function setType(bool
$type): void
{
if ($this->status == Alarm::STATUS_INACTIVE && $type == Alarm::TYPE_NON_REPEATING) {
throw new InvalidArgumentException('Нельзя делать одноразовой неактивную тревогу');
}
$this->type = $type;
}
public function setStatus(bool $status): void
{
if ($status == self::STATUS_INACTIVE && $this->type == self::TYPE_NON_REPEATING) {
throw new InvalidArgumentException('Нельзя изменять статус одноразовой тревоги');
}
$this->status = $status;
}
public function getTime(): string
{
}
public function getDaysOfWeek
(): array {
return $this->daysOfWeek;
}
public function isRepeating(): bool
{
return $this->type;
}
public function isActive(): bool
{
return $this->status;
}
public function findNearestAlarmTime(DateTimeImmutable $currentTime): DateTimeImmutable
{
$spelling = [
'', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'
];
foreach ($this->daysOfWeek as $dayOfWeek) {
if ($dayOfWeek > 7 || $dayOfWeek < 1) {
throw new InvalidArgumentException('Неправильное значение в массиве с днями недели');
}
$ordinal = ($currentTime->format('H:i') > $this->time) ?
'next' : ''; $datesAndTimes[] = $currentTime->modify($ordinal.' '.$spelling[$dayOfWeek].' '.$this->time);
}
return $datesAndTimes[0];
}
}
class AlarmClock
{
private $alarms;
public function addAlarm(Alarm $alarm): void
{
$this->alarms[] = $alarm;
}
public function setAlarm(int $id, Alarm $alarm): void
{
if (!$this->alarms) {
throw new Exception('Нет тревог');
}
if (!$this->alarms[$id]) {
throw new InvalidArgumentException('Несуществующая тревога');
}
$this->alarms[$id] = $alarm;
}
public function deleteAlarm(Alarm $alarm): void
{
if (!$this->alarms) {
throw new Exception('Нет тревог');
}
foreach ($this->alarms as $key => $object) {
if ($object == $alarm) {
unset($this->alarms[$key]); }
}
}
public function findNearestAlarm(DateTimeImmutable $currentTime): Alarm
{
if (!$this->alarms) {
throw new Exception('Нет тревог');
}
$alarms = [];
foreach ($this->alarms as $alarm) {
$alarmTime = $alarm->findNearestAlarmTime($currentTime);
$alarms[] = [$alarmTime, $alarm];
}
return $alarms[0][1];
}
public function findTriggeredAlarm(DateTimeImmutable $currentTime): ?Alarm
{
if (!$this->alarms) {
throw new Exception('Нет тревог');
}
foreach ($this->alarms as $alarm) {
if ($this->isTriggeredAlarm($alarm, $currentTime)
&& $alarm->isActive() == Alarm::STATUS_ACTIVE) {
return $alarm;
}
}
return null;
}
public function deleteProcessedNonRepeatingAlarms(DateTimeImmutable $currentTime): void
{
if (!$this->alarms) {
throw new Exception('Нет тревог');
}
foreach ($this->alarms as $alarm) {
if ($this->isTriggeredAlarm($alarm, $currentTime)
&& $alarm->isRepeating() == Alarm::TYPE_NON_REPEATING) {
$this->deleteAlarm($alarm);
}
}
}
private function isTriggeredAlarm(Alarm $alarm, DateTimeImmutable $currentTime): bool
{
$alarmTime = $alarm->findNearestAlarmTime($currentTime);
return ($alarmTime->format('Y-m-d H:i') == $currentTime->format('Y-m-d H:i'));
}
}