use bacnet_types::enums::{LifeSafetyState, PropertyIdentifier, Reliability};
use bacnet_types::error::Error;
use bacnet_types::primitives::PropertyValue;
use crate::common;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub(super) struct DeviceValues {
reliability: Option<Reliability>,
tracking_value: Option<LifeSafetyState>,
}
pub(super) struct Simulation<'a> {
pub(super) out_of_service: &'a mut bool,
pub(super) reliability: &'a mut Reliability,
pub(super) tracking_value: &'a mut LifeSafetyState,
pub(super) device_values: &'a mut DeviceValues,
}
impl Simulation<'_> {
pub(super) fn write(
&mut self,
property: PropertyIdentifier,
value: &PropertyValue,
) -> Option<Result<(), Error>> {
if property == PropertyIdentifier::TRACKING_VALUE {
return Some(self.write_tracking_value(value));
}
if property == PropertyIdentifier::RELIABILITY {
return Some(self.write_reliability(value));
}
let was_out_of_service = *self.out_of_service;
let result = common::write_out_of_service_with_reliability_restore(
self.out_of_service,
self.reliability,
&mut self.device_values.reliability,
property,
value,
)?;
match (was_out_of_service, *self.out_of_service) {
(false, true) => self.device_values.tracking_value = Some(*self.tracking_value),
(true, false) => {
if let Some(state) = self.device_values.tracking_value.take() {
*self.tracking_value = state;
}
}
_ => {}
}
Some(result)
}
fn write_tracking_value(&mut self, value: &PropertyValue) -> Result<(), Error> {
if !*self.out_of_service {
return Err(common::write_access_denied_error());
}
*self.tracking_value = super::application::life_safety_state(value)?;
Ok(())
}
fn write_reliability(&mut self, value: &PropertyValue) -> Result<(), Error> {
if !*self.out_of_service {
return Err(common::write_access_denied_error());
}
let PropertyValue::Enumerated(raw) = value else {
return Err(common::invalid_data_type_error());
};
let reliability = Reliability::from_raw(*raw);
if !common::is_reliability_value_valid(reliability) {
return Err(common::value_out_of_range_error());
}
*self.reliability = reliability;
Ok(())
}
pub(super) fn track(&mut self, state: LifeSafetyState) {
if *self.out_of_service {
self.device_values.tracking_value = Some(state);
} else {
*self.tracking_value = state;
}
}
pub(super) fn set_reliability(&mut self, reliability: Reliability) -> Result<(), Error> {
if *self.out_of_service {
return Err(common::write_access_denied_error());
}
if !common::is_reliability_value_valid(reliability) {
return Err(common::value_out_of_range_error());
}
*self.reliability = reliability;
Ok(())
}
}