use std::sync::Arc;
use bacnet_objects::clock::ClockFrame;
use bacnet_objects::database::ObjectDatabase;
use bacnet_types::enums::{ObjectType, PropertyIdentifier};
use tokio::sync::RwLock;
use tracing::{debug, warn};
pub(crate) fn current_time_components(frame: ClockFrame) -> Option<(u8, u8, u8)> {
let day_of_week = frame.local_date.day_of_week.checked_sub(1)?;
(day_of_week <= 6).then_some((day_of_week, frame.local_time.hour, frame.local_time.minute))
}
pub async fn tick_schedules(db: &Arc<RwLock<ObjectDatabase>>, _utc_offset_minutes: i16) {
let _ = tick_schedules_with_life_safety_cov(db, _utc_offset_minutes).await;
}
pub(crate) async fn tick_schedules_with_life_safety_cov(
db: &Arc<RwLock<ObjectDatabase>>,
_utc_offset_minutes: i16,
) -> Vec<crate::life_safety_cov::LifeSafetyCovChange> {
let frame = db.read().await.clock_frame();
let Some((day_of_week, hour, minute)) = frame.and_then(current_time_components) else {
debug!("Skipping Schedule evaluation without a valid Device clock");
return Vec::new();
};
let mut writes = Vec::new();
let changes = {
let mut db_w = db.write().await;
let schedule_oids = db_w.find_by_type(ObjectType::SCHEDULE);
for oid in schedule_oids {
if let Some(obj) = db_w.get_mut(&oid) {
if let Some((value, refs)) = obj.tick_schedule(day_of_week, hour, minute) {
debug!(
schedule = %oid,
refs = refs.len(),
"Schedule value changed, writing to controlled properties"
);
for (target_oid, prop_id) in refs {
writes.push((target_oid, prop_id, value.clone()));
}
}
}
}
let snapshots = crate::life_safety_cov::LifeSafetyCovSnapshots::capture_oids(
&db_w,
writes.iter().map(|(target_oid, _, _)| *target_oid),
);
let mut successful_oids = Vec::new();
for (target_oid, prop_id, value) in writes {
if let Some(target_obj) = db_w.get_mut(&target_oid) {
let prop = PropertyIdentifier::from_raw(prop_id);
if let Err(e) = target_obj.write_property(prop, None, value, None) {
warn!(
target = %target_oid,
property = prop_id,
error = %e,
"Schedule failed to write to controlled property"
);
} else if !successful_oids.contains(&target_oid) {
successful_oids.push(target_oid);
}
}
}
snapshots.changes(&db_w, &successful_oids)
};
changes
}