use crate::types::basic::{Double, OSString};
use crate::types::conditions::{ByEntityCondition, ByValueCondition};
use crate::types::enums::{ConditionEdge, TriggeringEntitiesRule};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Trigger {
#[serde(rename = "ConditionGroup", default)]
pub condition_groups: Vec<ConditionGroup>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ConditionGroup {
#[serde(rename = "Condition")]
pub conditions: Vec<Condition>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Condition {
#[serde(rename = "@name")]
pub name: OSString,
#[serde(rename = "@conditionEdge")]
pub condition_edge: ConditionEdge,
#[serde(rename = "@delay", skip_serializing_if = "Option::is_none")]
pub delay: Option<Double>,
#[serde(rename = "ByValueCondition", skip_serializing_if = "Option::is_none")]
pub by_value_condition: Option<ByValueCondition>,
#[serde(rename = "ByEntityCondition", skip_serializing_if = "Option::is_none")]
pub by_entity_condition: Option<ByEntityCondition>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(untagged)]
pub enum ConditionType {
ByEntity(ByEntityCondition),
ByValue(ByValueCondition),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct TriggeringEntities {
#[serde(rename = "@triggeringEntitiesRule")]
pub triggering_entities_rule: TriggeringEntitiesRule,
#[serde(rename = "EntityRef")]
pub entity_refs: Vec<EntityRef>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct EntityRef {
#[serde(rename = "@entityRef")]
pub entity_ref: OSString,
}
impl Default for Trigger {
fn default() -> Self {
Self {
condition_groups: vec![ConditionGroup::default()],
}
}
}
impl Default for ConditionGroup {
fn default() -> Self {
Self {
conditions: vec![Condition::default()],
}
}
}
impl Default for Condition {
fn default() -> Self {
Self {
name: OSString::literal("DefaultCondition".to_string()),
condition_edge: ConditionEdge::Rising,
delay: None,
by_value_condition: Some(ByValueCondition::default()),
by_entity_condition: None,
}
}
}
impl Default for ConditionType {
fn default() -> Self {
ConditionType::ByValue(ByValueCondition::default())
}
}
impl Default for TriggeringEntities {
fn default() -> Self {
Self {
triggering_entities_rule: TriggeringEntitiesRule::Any,
entity_refs: vec![EntityRef::default()],
}
}
}
impl Default for EntityRef {
fn default() -> Self {
Self {
entity_ref: OSString::literal("DefaultEntity".to_string()),
}
}
}
impl Trigger {
pub fn new(condition_group: ConditionGroup) -> Self {
Self {
condition_groups: vec![condition_group],
}
}
pub fn add_condition_group(&mut self, group: ConditionGroup) {
self.condition_groups.push(group);
}
pub fn has_conditions(&self) -> bool {
self.condition_groups
.iter()
.any(|g| !g.conditions.is_empty())
}
}
impl ConditionGroup {
pub fn new(condition: Condition) -> Self {
Self {
conditions: vec![condition],
}
}
pub fn add_condition(&mut self, condition: Condition) {
self.conditions.push(condition);
}
pub fn empty() -> Self {
Self {
conditions: Vec::new(),
}
}
}
impl Condition {
pub fn new(name: impl Into<String>, condition_type: ConditionType) -> Self {
let (by_value_condition, by_entity_condition) = match condition_type {
ConditionType::ByValue(cond) => (Some(cond), None),
ConditionType::ByEntity(cond) => (None, Some(cond)),
};
Self {
name: OSString::literal(name.into()),
condition_edge: ConditionEdge::Rising,
delay: None,
by_value_condition,
by_entity_condition,
}
}
pub fn with_edge(mut self, edge: ConditionEdge) -> Self {
self.condition_edge = edge;
self
}
pub fn with_delay(mut self, delay: Double) -> Self {
self.delay = Some(delay);
self
}
}
impl TriggeringEntities {
pub fn new(rule: TriggeringEntitiesRule, entity_refs: Vec<EntityRef>) -> Self {
Self {
triggering_entities_rule: rule,
entity_refs,
}
}
pub fn any(entity_refs: Vec<EntityRef>) -> Self {
Self::new(TriggeringEntitiesRule::Any, entity_refs)
}
pub fn all(entity_refs: Vec<EntityRef>) -> Self {
Self::new(TriggeringEntitiesRule::All, entity_refs)
}
}
impl EntityRef {
pub fn new(entity_name: impl Into<String>) -> Self {
Self {
entity_ref: OSString::literal(entity_name.into()),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::basic::Value;
use crate::types::enums::ConditionEdge;
#[test]
fn test_trigger_creation() {
let condition = Condition::new("TestCondition", ConditionType::default());
let group = ConditionGroup::new(condition);
let trigger = Trigger::new(group);
assert_eq!(trigger.condition_groups.len(), 1);
assert_eq!(trigger.condition_groups[0].conditions.len(), 1);
assert_eq!(
trigger.condition_groups[0].conditions[0]
.name
.as_literal()
.unwrap(),
"TestCondition"
);
assert!(trigger.has_conditions());
}
#[test]
fn test_condition_group_and_logic() {
let mut group = ConditionGroup::empty();
group.add_condition(Condition::new("Condition1", ConditionType::default()));
group.add_condition(Condition::new("Condition2", ConditionType::default()));
assert_eq!(group.conditions.len(), 2);
assert_eq!(group.conditions[0].name.as_literal().unwrap(), "Condition1");
assert_eq!(group.conditions[1].name.as_literal().unwrap(), "Condition2");
}
#[test]
fn test_trigger_or_logic() {
let mut trigger = Trigger::default();
let condition = Condition::new("SecondCondition", ConditionType::default());
let group = ConditionGroup::new(condition);
trigger.add_condition_group(group);
assert_eq!(trigger.condition_groups.len(), 2);
assert_eq!(
trigger.condition_groups[1].conditions[0]
.name
.as_literal()
.unwrap(),
"SecondCondition"
);
}
#[test]
fn test_condition_with_edge_and_delay() {
let condition = Condition::new("TimedCondition", ConditionType::default())
.with_edge(ConditionEdge::Falling)
.with_delay(Value::literal(2.5));
assert_eq!(condition.name.as_literal().unwrap(), "TimedCondition");
assert_eq!(condition.condition_edge, ConditionEdge::Falling);
assert_eq!(
condition.delay.as_ref().unwrap().as_literal().unwrap(),
&2.5
);
}
#[test]
fn test_triggering_entities() {
let entities = vec![EntityRef::new("Ego"), EntityRef::new("Target")];
let any_entities = TriggeringEntities::any(entities.clone());
let all_entities = TriggeringEntities::all(entities);
assert_eq!(
any_entities.triggering_entities_rule,
TriggeringEntitiesRule::Any
);
assert_eq!(
all_entities.triggering_entities_rule,
TriggeringEntitiesRule::All
);
assert_eq!(any_entities.entity_refs.len(), 2);
assert_eq!(
any_entities.entity_refs[0].entity_ref.as_literal().unwrap(),
"Ego"
);
assert_eq!(
any_entities.entity_refs[1].entity_ref.as_literal().unwrap(),
"Target"
);
}
#[test]
fn test_entity_ref() {
let entity_ref = EntityRef::new("TestEntity");
assert_eq!(entity_ref.entity_ref.as_literal().unwrap(), "TestEntity");
}
#[test]
fn test_trigger_serialization() {
let trigger = Trigger::default();
let serialized = quick_xml::se::to_string(&trigger).expect("Serialization should succeed");
assert!(serialized.contains("DefaultCondition"));
}
#[test]
fn test_complex_trigger_scenario() {
let mut group1 = ConditionGroup::new(
Condition::new("SpeedCondition", ConditionType::default())
.with_edge(ConditionEdge::Rising),
);
group1.add_condition(
Condition::new("TimeCondition", ConditionType::default())
.with_delay(Value::literal(1.0)),
);
let group2 = ConditionGroup::new(
Condition::new("CollisionCondition", ConditionType::default())
.with_edge(ConditionEdge::RisingOrFalling),
);
let mut trigger = Trigger::new(group1);
trigger.add_condition_group(group2);
assert_eq!(trigger.condition_groups.len(), 2);
assert_eq!(trigger.condition_groups[0].conditions.len(), 2); assert_eq!(trigger.condition_groups[1].conditions.len(), 1); assert!(trigger.has_conditions());
}
}