use crate::components::ElevatorPhase;
use crate::dispatch::ElevatorGroup;
use crate::events::{Event, EventBus};
use crate::metrics::Metrics;
use crate::tagged_metrics::MetricTags;
use crate::world::World;
use super::PhaseContext;
pub fn run(
world: &mut World,
events: &EventBus,
metrics: &mut Metrics,
ctx: &PhaseContext,
groups: &[ElevatorGroup],
) {
let mut tag_spawns: Vec<crate::entity::EntityId> = Vec::new();
let mut tag_boards: Vec<(crate::entity::EntityId, u64)> = Vec::new();
let mut tag_terminals: Vec<(crate::entity::EntityId, bool)> = Vec::new();
for event in events.peek() {
match event {
Event::RiderSpawned { rider, .. } => {
metrics.record_spawn();
tag_spawns.push(*rider);
}
Event::RiderBoarded { rider, tick, .. } => {
if let Some(rd) = world.rider(*rider) {
let wait_ticks = tick.saturating_sub(rd.spawn_tick);
metrics.record_board(wait_ticks);
tag_boards.push((*rider, wait_ticks));
}
}
Event::RiderExited { rider, tick, .. } => {
if let Some(rd) = world.rider(*rider) {
let ride_ticks = rd.board_tick.map_or(0, |bt| tick.saturating_sub(bt));
metrics.record_delivery(ride_ticks, *tick);
tag_terminals.push((*rider, true));
}
}
Event::RiderAbandoned { rider, .. } => {
metrics.record_abandonment();
tag_terminals.push((*rider, false));
}
#[cfg(feature = "energy")]
Event::EnergyConsumed {
consumed,
regenerated,
..
} => {
metrics.record_energy((*consumed).into(), (*regenerated).into());
}
_ => {}
}
}
if let Some(tags) = world.resource_mut::<MetricTags>() {
for rider in tag_spawns {
tags.record_spawn(rider);
}
for (rider, wait) in tag_boards {
tags.record_board(rider, wait);
}
for (rider, is_delivery) in tag_terminals {
if is_delivery {
tags.record_delivery(rider);
} else {
tags.record_abandonment(rider);
}
tags.remove_entity(rider);
}
}
let mut total_dist = 0.0;
for (eid, _pos, _car) in world.iter_elevators() {
if world.is_disabled(eid) {
continue;
}
if let Some(vel) = world.velocity(eid) {
total_dist += vel.value.abs() * ctx.dt;
}
}
if total_dist > 0.0 {
metrics.record_distance(total_dist);
}
for group in groups {
let mut total = 0u64;
let mut moving = 0u64;
for &eid in group.elevator_entities() {
if world.is_disabled(eid) {
continue;
}
if let Some(car) = world.elevator(eid) {
total += 1;
if matches!(car.phase, ElevatorPhase::MovingToStop(_)) {
moving += 1;
}
}
}
#[allow(clippy::cast_precision_loss)]
let util = if total > 0 {
moving as f64 / total as f64
} else {
0.0
};
metrics
.utilization_by_group
.insert(group.name().to_owned(), util);
}
metrics.update_throughput(ctx.tick);
}