fork download
  1. <?php
  2.  
  3. class Alarm
  4. {
  5. const MONDAY = 1;
  6. const TUESDAY = 2;
  7. const WEDNESDAY = 3;
  8. const THURSDAY = 4;
  9. const FRIDAY = 5;
  10. const SATURDAY = 6;
  11. const SUNDAY = 7;
  12.  
  13. private const ALL_DAYS = [
  14. self::MONDAY,
  15. self::TUESDAY,
  16. self::WEDNESDAY,
  17. self::THURSDAY,
  18. self::FRIDAY,
  19. self::SATURDAY,
  20. self::SUNDAY
  21. ];
  22.  
  23. const TYPE_REPEATING = true;
  24. const TYPE_NON_REPEATING = false;
  25. const STATUS_ACTIVE = true;
  26. const STATUS_INACTIVE = false;
  27.  
  28. private $time;
  29. private $daysOfWeek;
  30. private $type;
  31. private $status;
  32.  
  33. public function __construct(int $hour, int $minute)
  34. {
  35. $this->setTime($hour, $minute);
  36. $this->setDaysOfWeek(self::ALL_DAYS);
  37. $this->setType(self::TYPE_REPEATING);
  38. $this->setStatus(self::STATUS_ACTIVE);
  39. }
  40.  
  41. public function setTime(int $hour, int $minute): void
  42. {
  43. if ($hour > 23 || $hour < 0 || $minute > 60 || $minute < 0) {
  44. throw new InvalidArgumentException('Неправильное время');
  45. }
  46.  
  47. if ($hour < 10) {
  48. $hour = 0..$hour;
  49. }
  50.  
  51. if ($minute < 10) {
  52. $minute = 0..$minute;
  53. }
  54.  
  55. $this->time = $hour.':'.$minute;
  56. }
  57.  
  58. public function setDaysOfWeek(array $daysOfWeek): void
  59. {
  60. foreach ($daysOfWeek as $dayOfWeek) {
  61. if ($dayOfWeek > 7 || $dayOfWeek < 1) {
  62. throw new InvalidArgumentException('Неправильное значение в массиве с днями недели');
  63. }
  64. }
  65.  
  66. $this->daysOfWeek = $daysOfWeek;
  67. }
  68.  
  69. public function setType(bool $type): void
  70. {
  71. if ($this->status == Alarm::STATUS_INACTIVE && $type == Alarm::TYPE_NON_REPEATING) {
  72. throw new InvalidArgumentException('Нельзя делать одноразовой неактивную тревогу');
  73. }
  74.  
  75. $this->type = $type;
  76. }
  77.  
  78. public function setStatus(bool $status): void
  79. {
  80. if ($status == self::STATUS_INACTIVE && $this->type == self::TYPE_NON_REPEATING) {
  81. throw new InvalidArgumentException('Нельзя изменять статус одноразовой тревоги');
  82. }
  83.  
  84. $this->status = $status;
  85. }
  86.  
  87. public function getTime(): string
  88. {
  89. return $this->time;
  90. }
  91.  
  92. public function getDaysOfWeek(): array
  93. {
  94. return $this->daysOfWeek;
  95. }
  96.  
  97. public function isRepeating(): bool
  98. {
  99. return $this->type;
  100. }
  101.  
  102. public function isActive(): bool
  103. {
  104. return $this->status;
  105. }
  106.  
  107. public function findNearestAlarmTime(DateTimeImmutable $currentTime): DateTimeImmutable
  108. {
  109. $spelling = [
  110. '', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'
  111. ];
  112.  
  113. foreach ($this->daysOfWeek as $dayOfWeek) {
  114.  
  115. if ($dayOfWeek > 7 || $dayOfWeek < 1) {
  116. throw new InvalidArgumentException('Неправильное значение в массиве с днями недели');
  117. }
  118.  
  119. $ordinal = ($currentTime->format('H:i') > $this->time) ? 'next' : '';
  120. $datesAndTimes[] = $currentTime->modify($ordinal.' '.$spelling[$dayOfWeek].' '.$this->time);
  121.  
  122. }
  123.  
  124. sort($datesAndTimes);
  125.  
  126. return $datesAndTimes[0];
  127. }
  128. }
  129.  
  130. class AlarmClock
  131. {
  132. private $alarms;
  133.  
  134. public function addAlarm(Alarm $alarm): void
  135. {
  136. $this->alarms[] = $alarm;
  137. }
  138.  
  139. public function setAlarm(int $id, Alarm $alarm): void
  140. {
  141. if (!$this->alarms) {
  142. throw new Exception('Нет тревог');
  143. }
  144. if (!$this->alarms[$id]) {
  145. throw new InvalidArgumentException('Несуществующая тревога');
  146. }
  147.  
  148. $this->alarms[$id] = $alarm;
  149. }
  150.  
  151. public function deleteAlarm(Alarm $alarm): void
  152. {
  153. if (!$this->alarms) {
  154. throw new Exception('Нет тревог');
  155. }
  156.  
  157. foreach ($this->alarms as $key => $object) {
  158. if ($object == $alarm) {
  159. unset($this->alarms[$key]);
  160. }
  161. }
  162. }
  163.  
  164. public function findNearestAlarm(DateTimeImmutable $currentTime): Alarm
  165. {
  166. if (!$this->alarms) {
  167. throw new Exception('Нет тревог');
  168. }
  169.  
  170. $alarms = [];
  171.  
  172. foreach ($this->alarms as $alarm) {
  173.  
  174. $alarmTime = $alarm->findNearestAlarmTime($currentTime);
  175. $alarms[] = [$alarmTime, $alarm];
  176.  
  177. }
  178.  
  179. sort($alarms);
  180.  
  181. return $alarms[0][1];
  182. }
  183.  
  184. public function findTriggeredAlarm(DateTimeImmutable $currentTime): ?Alarm
  185. {
  186. if (!$this->alarms) {
  187. throw new Exception('Нет тревог');
  188. }
  189.  
  190. foreach ($this->alarms as $alarm) {
  191. if ($this->isTriggeredAlarm($alarm, $currentTime)
  192. && $alarm->isActive() == Alarm::STATUS_ACTIVE) {
  193. return $alarm;
  194. }
  195. }
  196.  
  197. return null;
  198. }
  199.  
  200. public function deleteProcessedNonRepeatingAlarms(DateTimeImmutable $currentTime): void
  201. {
  202. if (!$this->alarms) {
  203. throw new Exception('Нет тревог');
  204. }
  205.  
  206. foreach ($this->alarms as $alarm) {
  207. if ($this->isTriggeredAlarm($alarm, $currentTime)
  208. && $alarm->isRepeating() == Alarm::TYPE_NON_REPEATING) {
  209. $this->deleteAlarm($alarm);
  210. }
  211. }
  212. }
  213.  
  214. private function isTriggeredAlarm(Alarm $alarm, DateTimeImmutable $currentTime): bool
  215. {
  216. $alarmTime = $alarm->findNearestAlarmTime($currentTime);
  217. return ($alarmTime->format('Y-m-d H:i') == $currentTime->format('Y-m-d H:i'));
  218. }
  219. }
Success #stdin #stdout 0s 82560KB
stdin
Standard input is empty
stdout
Standard output is empty