use std::collections::BTreeMap;
use crate::components::{CallDirection, CarCall, HallCall, Weight};
use crate::entity::EntityId;
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct RiderInfo {
pub id: EntityId,
pub destination: Option<EntityId>,
pub weight: Weight,
pub wait_ticks: u64,
}
#[derive(Debug, Clone, Default)]
pub struct DispatchManifest {
pub(crate) waiting_at_stop: BTreeMap<EntityId, Vec<RiderInfo>>,
pub(crate) riding_to_stop: BTreeMap<EntityId, Vec<RiderInfo>>,
pub(crate) resident_count_at_stop: BTreeMap<EntityId, usize>,
pub(crate) hall_calls_at_stop: BTreeMap<EntityId, Vec<HallCall>>,
pub(crate) car_calls_by_car: BTreeMap<EntityId, Vec<CarCall>>,
pub(crate) arrivals_at_stop: BTreeMap<EntityId, u64>,
pub(crate) arrival_window_ticks: u64,
}
impl DispatchManifest {
#[must_use]
pub fn waiting_count_at(&self, stop: EntityId) -> usize {
self.waiting_at_stop.get(&stop).map_or(0, Vec::len)
}
#[must_use]
pub fn total_weight_at(&self, stop: EntityId) -> f64 {
self.waiting_at_stop
.get(&stop)
.map_or(0.0, |riders| riders.iter().map(|r| r.weight.value()).sum())
}
#[must_use]
pub fn riding_count_to(&self, stop: EntityId) -> usize {
self.riding_to_stop.get(&stop).map_or(0, Vec::len)
}
#[must_use]
pub fn has_demand(&self, stop: EntityId) -> bool {
self.waiting_count_at(stop) > 0
|| self.riding_count_to(stop) > 0
|| self
.hall_calls_at_stop
.get(&stop)
.is_some_and(|calls| calls.iter().any(|c| c.pending_riders.is_empty()))
}
#[must_use]
pub fn resident_count_at(&self, stop: EntityId) -> usize {
self.resident_count_at_stop.get(&stop).copied().unwrap_or(0)
}
#[must_use]
pub fn arrivals_at(&self, stop: EntityId) -> u64 {
self.arrivals_at_stop.get(&stop).copied().unwrap_or(0)
}
#[must_use]
pub const fn arrival_window_ticks(&self) -> u64 {
self.arrival_window_ticks
}
#[must_use]
pub fn hall_call_at(&self, stop: EntityId, direction: CallDirection) -> Option<&HallCall> {
self.hall_calls_at_stop
.get(&stop)?
.iter()
.find(|c| c.direction == direction)
}
pub fn iter_hall_calls(&self) -> impl Iterator<Item = &HallCall> {
self.hall_calls_at_stop.values().flatten()
}
#[must_use]
pub fn car_calls_for(&self, car: EntityId) -> &[CarCall] {
self.car_calls_by_car.get(&car).map_or(&[], Vec::as_slice)
}
#[must_use]
pub fn waiting_riders_at(&self, stop: EntityId) -> &[RiderInfo] {
self.waiting_at_stop.get(&stop).map_or(&[], Vec::as_slice)
}
pub fn iter_waiting_stops(&self) -> impl Iterator<Item = (&EntityId, &[RiderInfo])> {
self.waiting_at_stop
.iter()
.map(|(stop, riders)| (stop, riders.as_slice()))
}
#[must_use]
pub fn riding_riders_to(&self, stop: EntityId) -> &[RiderInfo] {
self.riding_to_stop.get(&stop).map_or(&[], Vec::as_slice)
}
pub fn iter_riding_stops(&self) -> impl Iterator<Item = (&EntityId, &[RiderInfo])> {
self.riding_to_stop
.iter()
.map(|(stop, riders)| (stop, riders.as_slice()))
}
pub fn iter_hall_call_stops(&self) -> impl Iterator<Item = (&EntityId, &[HallCall])> {
self.hall_calls_at_stop
.iter()
.map(|(stop, calls)| (stop, calls.as_slice()))
}
}