repo = new RsvTimetableRepository(); } public function get_all(?int $limit = null, int $skip = 0): array { return $this->repo->get_all($limit, $skip); } public function count_all(): int { return $this->repo->count_all(); } public function get(int $id): ?RsvTimetable { return $this->repo->get($id); } public function create(RsvTimetable $timetable): int { return $this->repo->create($timetable); } public function update(int $id, RsvTimetable $timetable): int { return $this->repo->update($id, $timetable); } public function get_all_maintainer_emails(): array { return $this->repo->get_all_maintainer_emails(); } public function set_google_calendar_id(int $id, ?string $calendar_id): void { $this->repo->set_google_calendar_id($id, $calendar_id); } public function delete(int $id): int { Logger::info('Deleting timetable: ' . $id); return $this->repo->delete($id); } private function datetime_to_minutes(DateTime $dt): int { $d = $dt->setTimezone(wp_timezone()); return (int) $d->format('G') * 60 + (int) $d->format('i'); } /** * @return array Availability on date */ public function get_availability_on_date(int $timetable_id, int $block_length, DateTime $date) : array { /** * Get available seats for the given date * Keeps two stacks: capacities & reservations * * Goes from left to right in reservations and pushes to stack */ $capacities = (new RsvTimetableCapacityRepository())->get_capacities_for_date($timetable_id, $date); $reservations = (new RsvTimetableReservationService())->get_reservations_on_date($timetable_id, $date); $capacity_stack = []; $reservation_stack = []; $capacity_index = 0; $reservation_index = 0; $blocks_count = 24 * 60 / $block_length; $blocks = array_fill(0, $blocks_count, 0); $availabilities = []; $availability_idx = 0; for($i = 0; $i < $blocks_count; $i++) { $reservation_stack = array_filter($reservation_stack, fn($reservation) => $this->datetime_to_minutes($reservation->end_utc) > $i * $block_length ); $capacity_stack = array_filter($capacity_stack, fn($capacity) => $capacity->end_time > $i * $block_length ); while($reservation_index < count($reservations) && $this->datetime_to_minutes($reservations[$reservation_index]->start_utc) <= $i * $block_length) { $reservation_stack[] = $reservations[$reservation_index]; $reservation_index++; } while($capacity_index < count($capacities) && $capacities[$capacity_index]->start_time <= $i * $block_length) { $capacity_stack[] = $capacities[$capacity_index]; $capacity_index++; } $total_capacity = array_sum(array_map(fn($x) => $x->capacity, $capacity_stack)); if ($total_capacity > 0) { if(count($availabilities) === $availability_idx) { $availabilities[] = new RsvTimetableAvailability($i * $block_length, ($i + 1) * $block_length, $block_length, []); } $availabilities[$availability_idx]->push_block($total_capacity - count($reservation_stack)); } else if($total_capacity === 0 && count($availabilities) !== $availability_idx) { $availability_idx++; } } return $availabilities; } }