1use crate::engine::{
2 agenda::{ActivationGroupManager, AgendaManager},
3 analytics::RuleAnalytics,
4 facts::Facts,
5 knowledge_base::KnowledgeBase,
6 plugin::{PluginConfig, PluginInfo, PluginManager, PluginStats},
7 workflow::WorkflowEngine,
8};
9use crate::errors::{Result, RuleEngineError};
10use crate::types::{ActionType, Operator, Value};
11use chrono::{DateTime, Utc};
12use log::info;
13use std::collections::HashMap;
14use std::time::{Duration, Instant};
15
16pub type CustomFunction = Box<dyn Fn(&[Value], &Facts) -> Result<Value> + Send + Sync>;
18
19pub type ActionHandler = Box<dyn Fn(&HashMap<String, Value>, &Facts) -> Result<()> + Send + Sync>;
21
22#[derive(Debug, Clone)]
24pub struct EngineConfig {
25 pub max_cycles: usize,
27 pub timeout: Option<Duration>,
29 pub enable_stats: bool,
31 pub debug_mode: bool,
33}
34
35impl Default for EngineConfig {
36 fn default() -> Self {
37 Self {
38 max_cycles: 100,
39 timeout: Some(Duration::from_secs(30)),
40 enable_stats: true,
41 debug_mode: false,
42 }
43 }
44}
45
46#[derive(Debug, Clone)]
48pub struct GruleExecutionResult {
49 pub cycle_count: usize,
51 pub rules_evaluated: usize,
53 pub rules_fired: usize,
55 pub execution_time: Duration,
57}
58
59pub struct RustRuleEngine {
61 knowledge_base: KnowledgeBase,
62 config: EngineConfig,
63 custom_functions: HashMap<String, CustomFunction>,
64 action_handlers: HashMap<String, ActionHandler>,
65 analytics: Option<RuleAnalytics>,
66 agenda_manager: AgendaManager,
67 activation_group_manager: ActivationGroupManager,
68 fired_rules_global: std::collections::HashSet<String>,
70 workflow_engine: WorkflowEngine,
72 plugin_manager: PluginManager,
74}
75
76#[allow(dead_code)]
77impl RustRuleEngine {
78 pub fn execute_with_callback<F>(
80 &mut self,
81 facts: &Facts,
82 mut on_rule_fired: F,
83 ) -> Result<GruleExecutionResult>
84 where
85 F: FnMut(&str, &Facts),
86 {
87 use chrono::Utc;
88 let timestamp = Utc::now();
89 let start_time = std::time::Instant::now();
90 let mut cycle_count = 0;
91 let mut rules_evaluated = 0;
92 let mut rules_fired = 0;
93
94 self.sync_workflow_agenda_activations();
95
96 for cycle in 0..self.config.max_cycles {
97 cycle_count = cycle + 1;
98 let mut any_rule_fired = false;
99 let mut fired_rules_in_cycle = std::collections::HashSet::new();
100 self.activation_group_manager.reset_cycle();
101
102 if let Some(timeout) = self.config.timeout {
103 if start_time.elapsed() > timeout {
104 return Err(crate::errors::RuleEngineError::EvaluationError {
105 message: "Execution timeout exceeded".to_string(),
106 });
107 }
108 }
109
110 let mut rules = self.knowledge_base.get_rules().clone();
111 rules.sort_by(|a, b| b.salience.cmp(&a.salience));
112 let rules: Vec<_> = rules
113 .iter()
114 .filter(|rule| self.agenda_manager.should_evaluate_rule(rule))
115 .collect();
116
117 for rule in &rules {
118 if !rule.enabled {
119 continue;
120 }
121 if !rule.is_active_at(timestamp) {
122 continue;
123 }
124 if !self.agenda_manager.can_fire_rule(rule) {
125 continue;
126 }
127 if !self.activation_group_manager.can_fire(rule) {
128 continue;
129 }
130 if rule.no_loop && self.fired_rules_global.contains(&rule.name) {
131 continue;
132 }
133 rules_evaluated += 1;
134 let condition_result = self.evaluate_conditions(&rule.conditions, facts)?;
135 if condition_result {
136 for action in &rule.actions {
137 self.execute_action(action, facts)?;
138 }
139 rules_fired += 1;
140 any_rule_fired = true;
141 fired_rules_in_cycle.insert(rule.name.clone());
142 if rule.no_loop {
143 self.fired_rules_global.insert(rule.name.clone());
144 }
145 self.agenda_manager.mark_rule_fired(rule);
146 self.activation_group_manager.mark_fired(rule);
147 on_rule_fired(&rule.name, facts);
149 }
150 }
151 if !any_rule_fired {
152 break;
153 }
154 self.sync_workflow_agenda_activations();
155 }
156 let execution_time = start_time.elapsed();
157 Ok(crate::engine::GruleExecutionResult {
158 cycle_count,
159 rules_evaluated,
160 rules_fired,
161 execution_time,
162 })
163 }
164 pub fn new(knowledge_base: KnowledgeBase) -> Self {
166 Self {
167 knowledge_base,
168 config: EngineConfig::default(),
169 custom_functions: HashMap::new(),
170 action_handlers: HashMap::new(),
171 analytics: None,
172 agenda_manager: AgendaManager::new(),
173 activation_group_manager: ActivationGroupManager::new(),
174 fired_rules_global: std::collections::HashSet::new(),
175 workflow_engine: WorkflowEngine::new(),
176 plugin_manager: PluginManager::with_default_config(),
177 }
178 }
179
180 pub fn with_config(knowledge_base: KnowledgeBase, config: EngineConfig) -> Self {
182 Self {
183 knowledge_base,
184 config,
185 custom_functions: HashMap::new(),
186 action_handlers: HashMap::new(),
187 analytics: None,
188 agenda_manager: AgendaManager::new(),
189 activation_group_manager: ActivationGroupManager::new(),
190 fired_rules_global: std::collections::HashSet::new(),
191 workflow_engine: WorkflowEngine::new(),
192 plugin_manager: PluginManager::with_default_config(),
193 }
194 }
195
196 pub fn register_function<F>(&mut self, name: &str, func: F)
198 where
199 F: Fn(&[Value], &Facts) -> Result<Value> + Send + Sync + 'static,
200 {
201 self.custom_functions
202 .insert(name.to_string(), Box::new(func));
203 }
204
205 pub fn register_action_handler<F>(&mut self, action_type: &str, handler: F)
207 where
208 F: Fn(&HashMap<String, Value>, &Facts) -> Result<()> + Send + Sync + 'static,
209 {
210 self.action_handlers
211 .insert(action_type.to_string(), Box::new(handler));
212 }
213
214 pub fn enable_analytics(&mut self, analytics: RuleAnalytics) {
216 self.analytics = Some(analytics);
217 }
218
219 pub fn reset_no_loop_tracking(&mut self) {
221 self.fired_rules_global.clear();
222 }
223
224 pub fn disable_analytics(&mut self) {
226 self.analytics = None;
227 }
228
229 pub fn analytics(&self) -> Option<&RuleAnalytics> {
231 self.analytics.as_ref()
232 }
233
234 pub fn set_debug_mode(&mut self, enabled: bool) {
236 self.config.debug_mode = enabled;
237 }
238
239 pub fn has_function(&self, name: &str) -> bool {
241 self.custom_functions.contains_key(name)
242 }
243
244 pub fn has_action_handler(&self, action_type: &str) -> bool {
246 self.action_handlers.contains_key(action_type)
247 }
248
249 pub fn get_ready_tasks(&mut self) -> Vec<crate::engine::workflow::ScheduledTask> {
251 self.workflow_engine.get_ready_tasks()
252 }
253
254 pub fn execute_scheduled_tasks(&mut self, facts: &Facts) -> Result<()> {
256 let ready_tasks = self.get_ready_tasks();
257 for task in ready_tasks {
258 if let Some(rule) = self
259 .knowledge_base
260 .get_rules()
261 .iter()
262 .find(|r| r.name == task.rule_name)
263 {
264 if self.config.debug_mode {
265 println!("⚡ Executing scheduled task: {}", task.rule_name);
266 }
267
268 if self.evaluate_conditions(&rule.conditions, facts)? {
270 for action in &rule.actions {
271 self.execute_action(action, facts)?;
272 }
273 }
274 }
275 }
276 Ok(())
277 }
278
279 pub fn activate_agenda_group(&mut self, group: String) {
281 self.workflow_engine.activate_agenda_group(group.clone());
282 self.agenda_manager.set_focus(&group);
283 }
284
285 pub fn knowledge_base(&self) -> &KnowledgeBase {
287 &self.knowledge_base
288 }
289
290 pub fn knowledge_base_mut(&mut self) -> &mut KnowledgeBase {
292 &mut self.knowledge_base
293 }
294
295 fn sync_workflow_agenda_activations(&mut self) {
297 while let Some(agenda_group) = self.workflow_engine.get_next_pending_agenda_activation() {
299 if self.config.debug_mode {
300 println!("🔄 Syncing workflow agenda activation: {}", agenda_group);
301 }
302 self.agenda_manager.set_focus(&agenda_group);
303 }
304 }
305
306 pub fn set_agenda_focus(&mut self, group: &str) {
308 self.agenda_manager.set_focus(group);
309 }
310
311 pub fn get_active_agenda_group(&self) -> &str {
313 self.agenda_manager.get_active_group()
314 }
315
316 pub fn pop_agenda_focus(&mut self) -> Option<String> {
318 self.agenda_manager.pop_focus()
319 }
320
321 pub fn clear_agenda_focus(&mut self) {
323 self.agenda_manager.clear_focus();
324 }
325
326 pub fn get_agenda_groups(&self) -> Vec<String> {
328 self.agenda_manager
329 .get_agenda_groups(&self.knowledge_base.get_rules())
330 }
331
332 pub fn get_activation_groups(&self) -> Vec<String> {
334 self.activation_group_manager
335 .get_activation_groups(&self.knowledge_base.get_rules())
336 }
337
338 pub fn start_workflow(&mut self, workflow_name: Option<String>) -> String {
342 self.workflow_engine.start_workflow(workflow_name)
343 }
344
345 pub fn get_workflow_stats(&self) -> crate::engine::workflow::WorkflowStats {
347 self.workflow_engine.get_workflow_stats()
348 }
349
350 pub fn get_workflow(
352 &self,
353 workflow_id: &str,
354 ) -> Option<&crate::engine::workflow::WorkflowState> {
355 self.workflow_engine.get_workflow(workflow_id)
356 }
357
358 pub fn cleanup_completed_workflows(&mut self, older_than: Duration) {
360 self.workflow_engine.cleanup_completed_workflows(older_than);
361 }
362
363 pub fn execute_workflow_step(
365 &mut self,
366 agenda_group: &str,
367 facts: &Facts,
368 ) -> Result<GruleExecutionResult> {
369 self.set_agenda_focus(agenda_group);
371
372 let result = self.execute(facts)?;
374
375 self.process_workflow_actions(facts)?;
377
378 Ok(result)
379 }
380
381 pub fn execute_workflow(
383 &mut self,
384 agenda_groups: Vec<&str>,
385 facts: &Facts,
386 ) -> Result<crate::engine::workflow::WorkflowResult> {
387 let start_time = Instant::now();
388 let mut total_steps = 0;
389
390 if self.config.debug_mode {
391 println!(
392 "🔄 Starting workflow execution with {} steps",
393 agenda_groups.len()
394 );
395 }
396
397 for (i, group) in agenda_groups.iter().enumerate() {
398 if self.config.debug_mode {
399 println!("📋 Executing workflow step {}: {}", i + 1, group);
400 }
401
402 let step_result = self.execute_workflow_step(group, facts)?;
403 total_steps += 1;
404
405 if step_result.rules_fired == 0 {
406 if self.config.debug_mode {
407 println!("⏸️ No rules fired in step '{}', stopping workflow", group);
408 }
409 break;
410 }
411 }
412
413 let execution_time = start_time.elapsed();
414
415 Ok(crate::engine::workflow::WorkflowResult::success(
416 total_steps,
417 execution_time,
418 ))
419 }
420
421 fn process_workflow_actions(&mut self, facts: &Facts) -> Result<()> {
423 while let Some(group) = self.workflow_engine.get_next_agenda_group() {
425 self.set_agenda_focus(&group);
426 }
427
428 let ready_tasks = self.workflow_engine.get_ready_tasks();
430 for task in ready_tasks {
431 if self.config.debug_mode {
432 println!("⚡ Executing scheduled task: {}", task.rule_name);
433 }
434
435 if let Some(rule) = self
437 .knowledge_base
438 .get_rules()
439 .iter()
440 .find(|r| r.name == task.rule_name)
441 {
442 if self.evaluate_conditions(&rule.conditions, facts)? {
444 for action in &rule.actions {
445 self.execute_action(action, facts)?;
446 }
447 }
448 }
449 }
450
451 Ok(())
452 }
453
454 pub fn execute(&mut self, facts: &Facts) -> Result<GruleExecutionResult> {
456 self.execute_at_time(facts, Utc::now())
457 }
458
459 pub fn execute_at_time(
461 &mut self,
462 facts: &Facts,
463 timestamp: DateTime<Utc>,
464 ) -> Result<GruleExecutionResult> {
465 let start_time = Instant::now();
466 let mut cycle_count = 0;
467 let mut rules_evaluated = 0;
468 let mut rules_fired = 0;
469
470 self.sync_workflow_agenda_activations();
472
473 if self.config.debug_mode {
474 println!(
475 "🚀 Starting rule execution with {} rules (agenda group: {})",
476 self.knowledge_base.get_rules().len(),
477 self.agenda_manager.get_active_group()
478 );
479 }
480
481 for cycle in 0..self.config.max_cycles {
482 cycle_count = cycle + 1;
483 let mut any_rule_fired = false;
484 let mut fired_rules_in_cycle = std::collections::HashSet::new();
485
486 self.activation_group_manager.reset_cycle();
488
489 if let Some(timeout) = self.config.timeout {
491 if start_time.elapsed() > timeout {
492 return Err(RuleEngineError::EvaluationError {
493 message: "Execution timeout exceeded".to_string(),
494 });
495 }
496 }
497
498 let mut rules = self.knowledge_base.get_rules().clone();
500 rules.sort_by(|a, b| b.salience.cmp(&a.salience));
501
502 let rules: Vec<_> = rules
504 .iter()
505 .filter(|rule| self.agenda_manager.should_evaluate_rule(rule))
506 .collect();
507
508 for rule in &rules {
509 if !rule.enabled {
510 continue;
511 }
512
513 if !rule.is_active_at(timestamp) {
515 continue;
516 }
517
518 if !self.agenda_manager.can_fire_rule(rule) {
520 continue;
521 }
522
523 if !self.activation_group_manager.can_fire(rule) {
525 continue;
526 }
527
528 if rule.no_loop && self.fired_rules_global.contains(&rule.name) {
530 if self.config.debug_mode {
531 println!("⛔ Skipping '{}' due to no_loop (already fired)", rule.name);
532 }
533 continue;
534 }
535
536 rules_evaluated += 1;
537 let rule_start = Instant::now();
538
539 if self.config.debug_mode {
540 println!(
541 "📝 Evaluating rule: {} (no_loop={})",
542 rule.name, rule.no_loop
543 );
544 }
545
546 let condition_result = self.evaluate_conditions(&rule.conditions, facts)?;
548 if self.config.debug_mode {
549 println!(
550 " 🔍 Condition result for '{}': {}",
551 rule.name, condition_result
552 );
553 }
554
555 if condition_result {
556 if self.config.debug_mode {
557 println!(
558 "🔥 Rule '{}' fired (salience: {})",
559 rule.name, rule.salience
560 );
561 }
562
563 for action in &rule.actions {
565 self.execute_action(action, facts)?;
566 }
567
568 let rule_duration = rule_start.elapsed();
569
570 if let Some(analytics) = &mut self.analytics {
572 analytics.record_execution(&rule.name, rule_duration, true, true, None, 0);
573 }
574
575 rules_fired += 1;
576 any_rule_fired = true;
577
578 fired_rules_in_cycle.insert(rule.name.clone());
580
581 if rule.no_loop {
583 self.fired_rules_global.insert(rule.name.clone());
584 if self.config.debug_mode {
585 println!(" 🔒 Marked '{}' as fired (no_loop tracking)", rule.name);
586 }
587 }
588
589 self.agenda_manager.mark_rule_fired(rule);
591 self.activation_group_manager.mark_fired(rule);
592 } else {
593 let rule_duration = rule_start.elapsed();
594
595 if let Some(analytics) = &mut self.analytics {
597 analytics.record_execution(
598 &rule.name,
599 rule_duration,
600 false,
601 false,
602 None,
603 0,
604 );
605 }
606 }
607 }
608
609 if !any_rule_fired {
611 break;
612 }
613
614 self.sync_workflow_agenda_activations();
616 }
617
618 let execution_time = start_time.elapsed();
619
620 Ok(GruleExecutionResult {
621 cycle_count,
622 rules_evaluated,
623 rules_fired,
624 execution_time,
625 })
626 }
627
628 fn evaluate_conditions(
630 &self,
631 conditions: &crate::engine::rule::ConditionGroup,
632 facts: &Facts,
633 ) -> Result<bool> {
634 use crate::engine::pattern_matcher::PatternMatcher;
635 use crate::engine::rule::ConditionGroup;
636
637 match conditions {
638 ConditionGroup::Single(condition) => self.evaluate_single_condition(condition, facts),
639 ConditionGroup::Compound {
640 left,
641 operator,
642 right,
643 } => {
644 let left_result = self.evaluate_conditions(left, facts)?;
645 let right_result = self.evaluate_conditions(right, facts)?;
646
647 match operator {
648 crate::types::LogicalOperator::And => Ok(left_result && right_result),
649 crate::types::LogicalOperator::Or => Ok(left_result || right_result),
650 crate::types::LogicalOperator::Not => Err(RuleEngineError::EvaluationError {
651 message: "NOT operator should not appear in compound conditions"
652 .to_string(),
653 }),
654 }
655 }
656 ConditionGroup::Not(condition) => {
657 let result = self.evaluate_conditions(condition, facts)?;
658 Ok(!result)
659 }
660 ConditionGroup::Exists(condition) => {
662 Ok(PatternMatcher::evaluate_exists(condition, facts))
663 }
664 ConditionGroup::Forall(condition) => {
665 Ok(PatternMatcher::evaluate_forall(condition, facts))
666 }
667 ConditionGroup::Accumulate {
668 result_var,
669 source_pattern,
670 extract_field,
671 source_conditions,
672 function,
673 function_arg,
674 } => {
675 self.evaluate_accumulate(
677 result_var,
678 source_pattern,
679 extract_field,
680 source_conditions,
681 function,
682 function_arg,
683 facts,
684 )?;
685 Ok(true)
687 }
688
689 #[cfg(feature = "streaming")]
690 ConditionGroup::StreamPattern { .. } => {
691 Ok(true)
694 }
695 }
696 }
697
698 #[allow(clippy::too_many_arguments)]
700 fn evaluate_accumulate(
701 &self,
702 _result_var: &str,
703 source_pattern: &str,
704 extract_field: &str,
705 source_conditions: &[String],
706 function: &str,
707 _function_arg: &str,
708 facts: &Facts,
709 ) -> Result<()> {
710 use crate::rete::accumulate::*;
711
712 let all_facts = facts.get_all_facts();
714 let mut matching_values = Vec::new();
715
716 let pattern_prefix = format!("{}.", source_pattern);
718
719 let mut instances: HashMap<String, HashMap<String, Value>> = HashMap::new();
721
722 for (key, value) in &all_facts {
723 if key.starts_with(&pattern_prefix) {
724 let parts: Vec<&str> = key
726 .strip_prefix(&pattern_prefix)
727 .unwrap()
728 .split('.')
729 .collect();
730
731 if parts.len() >= 2 {
732 let instance_id = parts[0];
734 let field_name = parts[1..].join(".");
735
736 instances
737 .entry(instance_id.to_string())
738 .or_default()
739 .insert(field_name, value.clone());
740 } else if parts.len() == 1 {
741 instances
743 .entry("default".to_string())
744 .or_default()
745 .insert(parts[0].to_string(), value.clone());
746 }
747 }
748 }
749
750 for (_instance_id, instance_facts) in instances {
752 let mut matches = true;
754
755 for condition_str in source_conditions {
756 if !self.evaluate_condition_string(condition_str, &instance_facts) {
758 matches = false;
759 break;
760 }
761 }
762
763 if matches {
764 if let Some(value) = instance_facts.get(extract_field) {
766 matching_values.push(value.clone());
767 }
768 }
769 }
770
771 let result = match function {
773 "sum" => {
774 let mut state = SumFunction.init();
775 for value in &matching_values {
776 state.accumulate(&self.value_to_fact_value(value));
777 }
778 self.fact_value_to_value(&state.get_result())
779 }
780 "count" => {
781 let mut state = CountFunction.init();
782 for value in &matching_values {
783 state.accumulate(&self.value_to_fact_value(value));
784 }
785 self.fact_value_to_value(&state.get_result())
786 }
787 "average" | "avg" => {
788 let mut state = AverageFunction.init();
789 for value in &matching_values {
790 state.accumulate(&self.value_to_fact_value(value));
791 }
792 self.fact_value_to_value(&state.get_result())
793 }
794 "min" => {
795 let mut state = MinFunction.init();
796 for value in &matching_values {
797 state.accumulate(&self.value_to_fact_value(value));
798 }
799 self.fact_value_to_value(&state.get_result())
800 }
801 "max" => {
802 let mut state = MaxFunction.init();
803 for value in &matching_values {
804 state.accumulate(&self.value_to_fact_value(value));
805 }
806 self.fact_value_to_value(&state.get_result())
807 }
808 _ => {
809 return Err(RuleEngineError::EvaluationError {
810 message: format!("Unknown accumulate function: {}", function),
811 });
812 }
813 };
814
815 let result_key = format!("{}.{}", source_pattern, function);
818
819 facts.set(&result_key, result);
820
821 if self.config.debug_mode {
822 println!(
823 " 🧮 Accumulate result: {} = {:?}",
824 result_key,
825 facts.get(&result_key)
826 );
827 }
828
829 Ok(())
830 }
831
832 fn value_to_fact_value(&self, value: &Value) -> crate::rete::facts::FactValue {
834 use crate::rete::facts::FactValue;
835 match value {
836 Value::Integer(i) => FactValue::Integer(*i),
837 Value::Number(n) => FactValue::Float(*n),
838 Value::String(s) => FactValue::String(s.clone()),
839 Value::Boolean(b) => FactValue::Boolean(*b),
840 _ => FactValue::String(value.to_string()),
841 }
842 }
843
844 fn fact_value_to_value(&self, fact_value: &crate::rete::facts::FactValue) -> Value {
846 use crate::rete::facts::FactValue;
847 match fact_value {
848 FactValue::Integer(i) => Value::Integer(*i),
849 FactValue::Float(f) => Value::Number(*f),
850 FactValue::String(s) => Value::String(s.clone()),
851 FactValue::Boolean(b) => Value::Boolean(*b),
852 FactValue::Array(_) => Value::String(format!("{:?}", fact_value)),
853 FactValue::Null => Value::String("null".to_string()),
854 }
855 }
856
857 fn evaluate_condition_string(&self, condition: &str, facts: &HashMap<String, Value>) -> bool {
859 let condition = condition.trim();
861
862 let operators = ["==", "!=", ">=", "<=", ">", "<"];
864
865 for op in &operators {
866 if let Some(pos) = condition.find(op) {
867 let field = condition[..pos].trim();
868 let value_str = condition[pos + op.len()..]
869 .trim()
870 .trim_matches('"')
871 .trim_matches('\'');
872
873 if let Some(field_value) = facts.get(field) {
874 return self.compare_values(field_value, op, value_str);
875 } else {
876 return false;
877 }
878 }
879 }
880
881 false
882 }
883
884 fn compare_values(&self, field_value: &Value, operator: &str, value_str: &str) -> bool {
886 match field_value {
887 Value::String(s) => match operator {
888 "==" => s == value_str,
889 "!=" => s != value_str,
890 _ => false,
891 },
892 Value::Integer(i) => {
893 if let Ok(num) = value_str.parse::<i64>() {
894 match operator {
895 "==" => *i == num,
896 "!=" => *i != num,
897 ">" => *i > num,
898 "<" => *i < num,
899 ">=" => *i >= num,
900 "<=" => *i <= num,
901 _ => false,
902 }
903 } else {
904 false
905 }
906 }
907 Value::Number(n) => {
908 if let Ok(num) = value_str.parse::<f64>() {
909 match operator {
910 "==" => (*n - num).abs() < f64::EPSILON,
911 "!=" => (*n - num).abs() >= f64::EPSILON,
912 ">" => *n > num,
913 "<" => *n < num,
914 ">=" => *n >= num,
915 "<=" => *n <= num,
916 _ => false,
917 }
918 } else {
919 false
920 }
921 }
922 Value::Boolean(b) => {
923 if let Ok(bool_val) = value_str.parse::<bool>() {
924 match operator {
925 "==" => *b == bool_val,
926 "!=" => *b != bool_val,
927 _ => false,
928 }
929 } else {
930 false
931 }
932 }
933 _ => false,
934 }
935 }
936
937 fn evaluate_rule_conditions(
939 &self,
940 rule: &crate::engine::rule::Rule,
941 facts: &Facts,
942 ) -> Result<bool> {
943 self.evaluate_conditions(&rule.conditions, facts)
944 }
945
946 fn is_retracted(&self, object_name: &str, facts: &Facts) -> bool {
948 let retract_key = format!("_retracted_{}", object_name);
949 matches!(facts.get(&retract_key), Some(Value::Boolean(true)))
950 }
951
952 fn evaluate_single_condition(
954 &self,
955 condition: &crate::engine::rule::Condition,
956 facts: &Facts,
957 ) -> Result<bool> {
958 use crate::engine::rule::ConditionExpression;
959
960 let result = match &condition.expression {
961 ConditionExpression::Field(field_name) => {
962 if let Some(object_name) = field_name.split('.').next() {
965 if self.is_retracted(object_name, facts) {
966 if self.config.debug_mode {
967 println!(" 🗑️ Skipping retracted fact: {}", object_name);
968 }
969 return Ok(false);
970 }
971 }
972
973 let field_value = facts
976 .get_nested(field_name)
977 .or_else(|| facts.get(field_name))
978 .unwrap_or(Value::Null);
979
980 if self.config.debug_mode {
981 println!(
982 " 🔎 Evaluating field condition: {} {} {:?}",
983 field_name,
984 format!("{:?}", condition.operator).to_lowercase(),
985 condition.value
986 );
987 println!(" Field value: {:?}", field_value);
988 }
989
990 let rhs = match &condition.value {
996 crate::types::Value::String(s) => {
997 facts
999 .get_nested(s)
1000 .or_else(|| facts.get(s))
1001 .unwrap_or(crate::types::Value::String(s.clone()))
1002 }
1003 crate::types::Value::Expression(expr) => {
1004 match crate::expression::evaluate_expression(expr, facts) {
1006 Ok(evaluated) => evaluated,
1007 Err(_) => {
1008 facts
1010 .get_nested(expr)
1011 .or_else(|| facts.get(expr))
1012 .unwrap_or(crate::types::Value::Expression(expr.clone()))
1013 }
1014 }
1015 }
1016 _ => condition.value.clone(),
1017 };
1018
1019 if self.config.debug_mode {
1020 println!(" Resolved RHS for comparison: {:?}", rhs);
1021 }
1022
1023 condition.operator.evaluate(&field_value, &rhs)
1024 }
1025 ConditionExpression::FunctionCall { name, args } => {
1026 if self.config.debug_mode {
1028 println!(
1029 " 🔎 Evaluating function condition: {}({:?}) {} {:?}",
1030 name,
1031 args,
1032 format!("{:?}", condition.operator).to_lowercase(),
1033 condition.value
1034 );
1035 }
1036
1037 if let Some(function) = self.custom_functions.get(name) {
1038 let arg_values: Vec<Value> = args
1040 .iter()
1041 .map(|arg| {
1042 facts
1043 .get_nested(arg)
1044 .or_else(|| facts.get(arg))
1045 .unwrap_or(Value::String(arg.clone()))
1046 })
1047 .collect();
1048
1049 match function(&arg_values, facts) {
1051 Ok(result_value) => {
1052 if self.config.debug_mode {
1053 println!(" Function result: {:?}", result_value);
1054 }
1055 condition.operator.evaluate(&result_value, &condition.value)
1056 }
1057 Err(e) => {
1058 if self.config.debug_mode {
1059 println!(" Function error: {}", e);
1060 }
1061 false
1062 }
1063 }
1064 } else {
1065 if self.config.debug_mode {
1066 println!(" Function '{}' not found", name);
1067 }
1068 false
1069 }
1070 }
1071 ConditionExpression::Test { name, args } => {
1072 if self.config.debug_mode {
1074 println!(" 🧪 Evaluating test CE: test({}({:?}))", name, args);
1075 }
1076
1077 if let Some(function) = self.custom_functions.get(name) {
1079 let arg_values: Vec<Value> = args
1081 .iter()
1082 .map(|arg| {
1083 let resolved = facts
1084 .get_nested(arg)
1085 .or_else(|| facts.get(arg))
1086 .unwrap_or(Value::String(arg.clone()));
1087 if self.config.debug_mode {
1088 println!(" Resolving arg '{}' -> {:?}", arg, resolved);
1089 }
1090 resolved
1091 })
1092 .collect();
1093
1094 match function(&arg_values, facts) {
1096 Ok(result_value) => {
1097 if self.config.debug_mode {
1098 println!(" Test result: {:?}", result_value);
1099 }
1100 match result_value {
1102 Value::Boolean(b) => b,
1103 Value::Integer(i) => i != 0,
1104 Value::Number(f) => f != 0.0,
1105 Value::String(s) => !s.is_empty(),
1106 _ => false,
1107 }
1108 }
1109 Err(e) => {
1110 if self.config.debug_mode {
1111 println!(" Test function error: {}", e);
1112 }
1113 false
1114 }
1115 }
1116 } else {
1117 if self.config.debug_mode {
1120 println!(
1121 " Trying to evaluate '{}' as arithmetic expression",
1122 name
1123 );
1124 }
1125
1126 match self.evaluate_arithmetic_condition(name, facts) {
1128 Ok(result) => {
1129 if self.config.debug_mode {
1130 println!(" Arithmetic expression result: {}", result);
1131 }
1132 result
1133 }
1134 Err(e) => {
1135 if self.config.debug_mode {
1136 println!(" Failed to evaluate expression: {}", e);
1137 println!(" Test function '{}' not found", name);
1138 }
1139 false
1140 }
1141 }
1142 }
1143 }
1144 ConditionExpression::MultiField {
1145 field,
1146 operation,
1147 variable: _,
1148 } => {
1149 if self.config.debug_mode {
1151 println!(" 📦 Evaluating multi-field: {}.{}", field, operation);
1152 }
1153
1154 let field_value = facts.get_nested(field).or_else(|| facts.get(field));
1156
1157 if let Some(value) = field_value {
1158 match operation.as_str() {
1159 "empty" => {
1160 matches!(value, Value::Array(arr) if arr.is_empty())
1161 }
1162 "not_empty" => {
1163 matches!(value, Value::Array(arr) if !arr.is_empty())
1164 }
1165 "count" => {
1166 if let Value::Array(arr) = value {
1167 let count = Value::Integer(arr.len() as i64);
1168 condition.operator.evaluate(&count, &condition.value)
1169 } else {
1170 false
1171 }
1172 }
1173 "contains" => {
1174 condition.operator.evaluate(&value, &condition.value)
1176 }
1177 _ => {
1178 if self.config.debug_mode {
1181 println!(
1182 " ⚠️ Operation '{}' not fully implemented yet",
1183 operation
1184 );
1185 }
1186 true
1187 }
1188 }
1189 } else {
1190 false
1191 }
1192 }
1193 };
1194
1195 if self.config.debug_mode {
1196 println!(" Result: {}", result);
1197 }
1198
1199 Ok(result)
1200 }
1201
1202 fn execute_action(&mut self, action: &ActionType, facts: &Facts) -> Result<()> {
1204 match action {
1205 ActionType::Set { field, value } => {
1206 let evaluated_value = match value {
1208 Value::Expression(expr) => {
1209 crate::expression::evaluate_expression(expr, facts)?
1211 }
1212 _ => value.clone(),
1213 };
1214
1215 if facts.set_nested(field, evaluated_value.clone()).is_err() {
1217 facts.set(field, evaluated_value.clone());
1219 }
1220 if self.config.debug_mode {
1221 println!(" ✅ Set {field} = {evaluated_value:?}");
1222 }
1223 }
1224 ActionType::Log { message } => {
1225 println!("📋 LOG: {}", message);
1226 }
1227 ActionType::MethodCall {
1228 object,
1229 method,
1230 args,
1231 } => {
1232 let result = self.execute_method_call(object, method, args, facts)?;
1233 if self.config.debug_mode {
1234 println!(" 🔧 Called {object}.{method}({args:?}) -> {result}");
1235 }
1236 }
1237 ActionType::Retract { object } => {
1238 if self.config.debug_mode {
1239 println!(" 🗑️ Retracted {object}");
1240 }
1241 facts.set(&format!("_retracted_{}", object), Value::Boolean(true));
1243 }
1244 ActionType::Custom {
1245 action_type,
1246 params,
1247 } => {
1248 if let Some(handler) = self.action_handlers.get(action_type) {
1249 if self.config.debug_mode {
1250 println!(
1251 " 🎯 Executing custom action: {action_type} with params: {params:?}"
1252 );
1253 }
1254
1255 let resolved_params = self.resolve_action_parameters(params, facts)?;
1257
1258 handler(&resolved_params, facts)?;
1260 } else {
1261 if self.config.debug_mode {
1262 println!(" ⚠️ No handler registered for custom action: {action_type}");
1263 println!(
1264 " Available handlers: {:?}",
1265 self.action_handlers.keys().collect::<Vec<_>>()
1266 );
1267 }
1268
1269 return Err(RuleEngineError::EvaluationError {
1271 message: format!(
1272 "No action handler registered for '{action_type}'. Use engine.register_action_handler() to add custom action handlers."
1273 ),
1274 });
1275 }
1276 }
1277 ActionType::ActivateAgendaGroup { group } => {
1279 if self.config.debug_mode {
1280 println!(" 🎯 Activating agenda group: {}", group);
1281 }
1282 self.workflow_engine.activate_agenda_group(group.clone());
1284 self.agenda_manager.set_focus(group);
1285 }
1286 ActionType::ScheduleRule {
1287 rule_name,
1288 delay_ms,
1289 } => {
1290 if self.config.debug_mode {
1291 println!(
1292 " ⏰ Scheduling rule '{}' to execute in {}ms",
1293 rule_name, delay_ms
1294 );
1295 }
1296 self.workflow_engine
1297 .schedule_rule(rule_name.clone(), *delay_ms, None);
1298 }
1299 ActionType::CompleteWorkflow { workflow_name } => {
1300 if self.config.debug_mode {
1301 println!(" ✅ Completing workflow: {}", workflow_name);
1302 }
1303 self.workflow_engine
1304 .complete_workflow(workflow_name.clone());
1305 }
1306 ActionType::SetWorkflowData { key, value } => {
1307 if self.config.debug_mode {
1308 println!(" 💾 Setting workflow data: {} = {:?}", key, value);
1309 }
1310 let workflow_id = "default_workflow";
1313 self.workflow_engine
1314 .set_workflow_data(workflow_id, key.clone(), value.clone());
1315 }
1316 }
1317 Ok(())
1318 }
1319
1320 fn evaluate_arithmetic_condition(&self, expr: &str, facts: &Facts) -> Result<bool> {
1322 let operators = [">=", "<=", "==", "!=", ">", "<"];
1326 let mut split_pos = None;
1327 let mut found_op = "";
1328
1329 for op in &operators {
1330 if let Some(pos) = expr.rfind(op) {
1331 split_pos = Some(pos);
1332 found_op = op;
1333 break;
1334 }
1335 }
1336
1337 if split_pos.is_none() {
1338 return Err(RuleEngineError::EvaluationError {
1339 message: format!("No comparison operator found in expression: {}", expr),
1340 });
1341 }
1342
1343 let pos = split_pos.unwrap();
1344 let left_expr = expr[..pos].trim();
1345 let right_value = expr[pos + found_op.len()..].trim();
1346
1347 let left_result = crate::expression::evaluate_expression(left_expr, facts)?;
1349
1350 let right_val = if let Ok(i) = right_value.parse::<i64>() {
1352 Value::Integer(i)
1353 } else if let Ok(f) = right_value.parse::<f64>() {
1354 Value::Number(f)
1355 } else {
1356 match crate::expression::evaluate_expression(right_value, facts) {
1358 Ok(v) => v,
1359 Err(_) => Value::String(right_value.to_string()),
1360 }
1361 };
1362
1363 let operator =
1365 Operator::from_str(found_op).ok_or_else(|| RuleEngineError::InvalidOperator {
1366 operator: found_op.to_string(),
1367 })?;
1368
1369 Ok(operator.evaluate(&left_result, &right_val))
1370 }
1371
1372 fn execute_function_call(
1374 &self,
1375 function: &str,
1376 args: &[Value],
1377 facts: &Facts,
1378 ) -> Result<String> {
1379 let function_lower = function.to_lowercase();
1380
1381 match function_lower.as_str() {
1383 "log" | "print" | "println" => self.handle_log_function(args),
1384 "update" | "refresh" => self.handle_update_function(args),
1385 "now" | "timestamp" => self.handle_timestamp_function(),
1386 "random" => self.handle_random_function(args),
1387 "format" | "sprintf" => self.handle_format_function(args),
1388 "length" | "size" | "count" => self.handle_length_function(args),
1389 "sum" | "add" => self.handle_sum_function(args),
1390 "max" | "maximum" => self.handle_max_function(args),
1391 "min" | "minimum" => self.handle_min_function(args),
1392 "avg" | "average" => self.handle_average_function(args),
1393 "round" => self.handle_round_function(args),
1394 "floor" => self.handle_floor_function(args),
1395 "ceil" | "ceiling" => self.handle_ceil_function(args),
1396 "abs" | "absolute" => self.handle_abs_function(args),
1397 "contains" | "includes" => self.handle_contains_function(args),
1398 "startswith" | "begins_with" => self.handle_starts_with_function(args),
1399 "endswith" | "ends_with" => self.handle_ends_with_function(args),
1400 "lowercase" | "tolower" => self.handle_lowercase_function(args),
1401 "uppercase" | "toupper" => self.handle_uppercase_function(args),
1402 "trim" | "strip" => self.handle_trim_function(args),
1403 "split" => self.handle_split_function(args),
1404 "join" => self.handle_join_function(args),
1405 _ => {
1406 self.handle_custom_function(function, args, facts)
1408 }
1409 }
1410 }
1411
1412 fn handle_log_function(&self, args: &[Value]) -> Result<String> {
1414 let message = if args.is_empty() {
1415 "".to_string()
1416 } else if args.len() == 1 {
1417 args[0].to_string()
1418 } else {
1419 args.iter()
1420 .map(|v| v.to_string())
1421 .collect::<Vec<_>>()
1422 .join(" ")
1423 };
1424
1425 info!("📋 {}", message);
1426 Ok(message)
1427 }
1428
1429 fn handle_update_function(&self, args: &[Value]) -> Result<String> {
1431 if let Some(arg) = args.first() {
1432 Ok(format!("Updated: {}", arg.to_string()))
1433 } else {
1434 Ok("Updated".to_string())
1435 }
1436 }
1437
1438 fn handle_timestamp_function(&self) -> Result<String> {
1440 use std::time::{SystemTime, UNIX_EPOCH};
1441 let timestamp = SystemTime::now()
1442 .duration_since(UNIX_EPOCH)
1443 .map_err(|e| RuleEngineError::EvaluationError {
1444 message: format!("Failed to get timestamp: {}", e),
1445 })?
1446 .as_secs();
1447 Ok(timestamp.to_string())
1448 }
1449
1450 fn handle_random_function(&self, args: &[Value]) -> Result<String> {
1452 use std::collections::hash_map::DefaultHasher;
1453 use std::hash::{Hash, Hasher};
1454
1455 let mut hasher = DefaultHasher::new();
1457 std::time::SystemTime::now().hash(&mut hasher);
1458 let random_value = hasher.finish();
1459
1460 if args.is_empty() {
1461 Ok((random_value % 100).to_string()) } else if let Some(Value::Number(max)) = args.first() {
1463 let max_val = *max as u64;
1464 Ok((random_value % max_val).to_string())
1465 } else {
1466 Ok(random_value.to_string())
1467 }
1468 }
1469
1470 fn handle_format_function(&self, args: &[Value]) -> Result<String> {
1472 if args.is_empty() {
1473 return Ok("".to_string());
1474 }
1475
1476 let template = args[0].to_string();
1477 let values: Vec<String> = args[1..].iter().map(|v| v.to_string()).collect();
1478
1479 let mut result = template;
1481 for (i, value) in values.iter().enumerate() {
1482 result = result.replace(&format!("{{{}}}", i), value);
1483 }
1484
1485 Ok(result)
1486 }
1487
1488 fn handle_length_function(&self, args: &[Value]) -> Result<String> {
1490 if let Some(arg) = args.first() {
1491 match arg {
1492 Value::String(s) => Ok(s.len().to_string()),
1493 Value::Array(arr) => Ok(arr.len().to_string()),
1494 Value::Object(obj) => Ok(obj.len().to_string()),
1495 _ => Ok("1".to_string()), }
1497 } else {
1498 Ok("0".to_string())
1499 }
1500 }
1501
1502 fn handle_sum_function(&self, args: &[Value]) -> Result<String> {
1504 let sum = args.iter().fold(0.0, |acc, val| match val {
1505 Value::Number(n) => acc + n,
1506 Value::Integer(i) => acc + (*i as f64),
1507 _ => acc,
1508 });
1509 Ok(sum.to_string())
1510 }
1511
1512 fn handle_max_function(&self, args: &[Value]) -> Result<String> {
1514 let max = args.iter().fold(f64::NEG_INFINITY, |acc, val| match val {
1515 Value::Number(n) => acc.max(*n),
1516 Value::Integer(i) => acc.max(*i as f64),
1517 _ => acc,
1518 });
1519 Ok(max.to_string())
1520 }
1521
1522 fn handle_min_function(&self, args: &[Value]) -> Result<String> {
1524 let min = args.iter().fold(f64::INFINITY, |acc, val| match val {
1525 Value::Number(n) => acc.min(*n),
1526 Value::Integer(i) => acc.min(*i as f64),
1527 _ => acc,
1528 });
1529 Ok(min.to_string())
1530 }
1531
1532 fn handle_average_function(&self, args: &[Value]) -> Result<String> {
1534 if args.is_empty() {
1535 return Ok("0".to_string());
1536 }
1537
1538 let (sum, count) = args.iter().fold((0.0, 0), |(sum, count), val| match val {
1539 Value::Number(n) => (sum + n, count + 1),
1540 Value::Integer(i) => (sum + (*i as f64), count + 1),
1541 _ => (sum, count),
1542 });
1543
1544 if count > 0 {
1545 Ok((sum / count as f64).to_string())
1546 } else {
1547 Ok("0".to_string())
1548 }
1549 }
1550
1551 fn handle_round_function(&self, args: &[Value]) -> Result<String> {
1553 if let Some(Value::Number(n)) = args.first() {
1554 Ok(n.round().to_string())
1555 } else if let Some(Value::Integer(i)) = args.first() {
1556 Ok(i.to_string())
1557 } else {
1558 Err(RuleEngineError::EvaluationError {
1559 message: "round() requires a numeric argument".to_string(),
1560 })
1561 }
1562 }
1563
1564 fn handle_floor_function(&self, args: &[Value]) -> Result<String> {
1565 if let Some(Value::Number(n)) = args.first() {
1566 Ok(n.floor().to_string())
1567 } else if let Some(Value::Integer(i)) = args.first() {
1568 Ok(i.to_string())
1569 } else {
1570 Err(RuleEngineError::EvaluationError {
1571 message: "floor() requires a numeric argument".to_string(),
1572 })
1573 }
1574 }
1575
1576 fn handle_ceil_function(&self, args: &[Value]) -> Result<String> {
1577 if let Some(Value::Number(n)) = args.first() {
1578 Ok(n.ceil().to_string())
1579 } else if let Some(Value::Integer(i)) = args.first() {
1580 Ok(i.to_string())
1581 } else {
1582 Err(RuleEngineError::EvaluationError {
1583 message: "ceil() requires a numeric argument".to_string(),
1584 })
1585 }
1586 }
1587
1588 fn handle_abs_function(&self, args: &[Value]) -> Result<String> {
1589 if let Some(Value::Number(n)) = args.first() {
1590 Ok(n.abs().to_string())
1591 } else if let Some(Value::Integer(i)) = args.first() {
1592 Ok(i.abs().to_string())
1593 } else {
1594 Err(RuleEngineError::EvaluationError {
1595 message: "abs() requires a numeric argument".to_string(),
1596 })
1597 }
1598 }
1599
1600 fn handle_contains_function(&self, args: &[Value]) -> Result<String> {
1602 if args.len() >= 2 {
1603 let haystack = args[0].to_string();
1604 let needle = args[1].to_string();
1605 Ok(haystack.contains(&needle).to_string())
1606 } else {
1607 Err(RuleEngineError::EvaluationError {
1608 message: "contains() requires 2 arguments".to_string(),
1609 })
1610 }
1611 }
1612
1613 fn handle_starts_with_function(&self, args: &[Value]) -> Result<String> {
1614 if args.len() >= 2 {
1615 let text = args[0].to_string();
1616 let prefix = args[1].to_string();
1617 Ok(text.starts_with(&prefix).to_string())
1618 } else {
1619 Err(RuleEngineError::EvaluationError {
1620 message: "startswith() requires 2 arguments".to_string(),
1621 })
1622 }
1623 }
1624
1625 fn handle_ends_with_function(&self, args: &[Value]) -> Result<String> {
1626 if args.len() >= 2 {
1627 let text = args[0].to_string();
1628 let suffix = args[1].to_string();
1629 Ok(text.ends_with(&suffix).to_string())
1630 } else {
1631 Err(RuleEngineError::EvaluationError {
1632 message: "endswith() requires 2 arguments".to_string(),
1633 })
1634 }
1635 }
1636
1637 fn handle_lowercase_function(&self, args: &[Value]) -> Result<String> {
1638 if let Some(arg) = args.first() {
1639 Ok(arg.to_string().to_lowercase())
1640 } else {
1641 Err(RuleEngineError::EvaluationError {
1642 message: "lowercase() requires 1 argument".to_string(),
1643 })
1644 }
1645 }
1646
1647 fn handle_uppercase_function(&self, args: &[Value]) -> Result<String> {
1648 if let Some(arg) = args.first() {
1649 Ok(arg.to_string().to_uppercase())
1650 } else {
1651 Err(RuleEngineError::EvaluationError {
1652 message: "uppercase() requires 1 argument".to_string(),
1653 })
1654 }
1655 }
1656
1657 fn handle_trim_function(&self, args: &[Value]) -> Result<String> {
1658 if let Some(arg) = args.first() {
1659 Ok(arg.to_string().trim().to_string())
1660 } else {
1661 Err(RuleEngineError::EvaluationError {
1662 message: "trim() requires 1 argument".to_string(),
1663 })
1664 }
1665 }
1666
1667 fn handle_split_function(&self, args: &[Value]) -> Result<String> {
1668 if args.len() >= 2 {
1669 let text = args[0].to_string();
1670 let delimiter = args[1].to_string();
1671 let parts: Vec<String> = text.split(&delimiter).map(|s| s.to_string()).collect();
1672 Ok(format!("{:?}", parts)) } else {
1674 Err(RuleEngineError::EvaluationError {
1675 message: "split() requires 2 arguments".to_string(),
1676 })
1677 }
1678 }
1679
1680 fn handle_join_function(&self, args: &[Value]) -> Result<String> {
1681 if args.len() >= 2 {
1682 let delimiter = args[0].to_string();
1683 let parts: Vec<String> = args[1..].iter().map(|v| v.to_string()).collect();
1684 Ok(parts.join(&delimiter))
1685 } else {
1686 Err(RuleEngineError::EvaluationError {
1687 message: "join() requires at least 2 arguments".to_string(),
1688 })
1689 }
1690 }
1691
1692 fn handle_custom_function(
1694 &self,
1695 function: &str,
1696 args: &[Value],
1697 facts: &Facts,
1698 ) -> Result<String> {
1699 if let Some(custom_func) = self.custom_functions.get(function) {
1701 if self.config.debug_mode {
1702 println!("🎯 Calling registered function: {}({:?})", function, args);
1703 }
1704
1705 match custom_func(args, facts) {
1706 Ok(result) => Ok(result.to_string()),
1707 Err(e) => Err(e),
1708 }
1709 } else {
1710 if self.config.debug_mode {
1712 println!("⚠️ Custom function '{}' not registered", function);
1713 }
1714
1715 Err(RuleEngineError::EvaluationError {
1716 message: format!("Function '{}' is not registered. Use engine.register_function() to add custom functions.", function),
1717 })
1718 }
1719 }
1720
1721 fn execute_method_call(
1723 &self,
1724 object_name: &str,
1725 method: &str,
1726 args: &[Value],
1727 facts: &Facts,
1728 ) -> Result<String> {
1729 let Some(object_value) = facts.get(object_name) else {
1731 return Err(RuleEngineError::EvaluationError {
1732 message: format!("Object '{}' not found in facts", object_name),
1733 });
1734 };
1735
1736 let method_lower = method.to_lowercase();
1737
1738 if method_lower.starts_with("set") && args.len() == 1 {
1740 return self.handle_setter_method(object_name, method, &args[0], object_value, facts);
1741 }
1742
1743 if method_lower.starts_with("get") && args.is_empty() {
1745 return self.handle_getter_method(object_name, method, &object_value);
1746 }
1747
1748 match method_lower.as_str() {
1750 "tostring" => Ok(object_value.to_string()),
1751 "update" => {
1752 facts.add_value(object_name, object_value)?;
1753 Ok(format!("Updated {}", object_name))
1754 }
1755 "reset" => self.handle_reset_method(object_name, object_value, facts),
1756 _ => self.handle_property_access_or_fallback(
1757 object_name,
1758 method,
1759 args.len(),
1760 &object_value,
1761 ),
1762 }
1763 }
1764
1765 fn handle_setter_method(
1767 &self,
1768 object_name: &str,
1769 method: &str,
1770 new_value: &Value,
1771 mut object_value: Value,
1772 facts: &Facts,
1773 ) -> Result<String> {
1774 let property_name = Self::extract_property_name_from_setter(method);
1775
1776 match object_value {
1777 Value::Object(ref mut obj) => {
1778 obj.insert(property_name.clone(), new_value.clone());
1779 facts.add_value(object_name, object_value)?;
1780 Ok(format!(
1781 "Set {} to {}",
1782 property_name,
1783 new_value.to_string()
1784 ))
1785 }
1786 _ => Err(RuleEngineError::EvaluationError {
1787 message: format!("Cannot call setter on non-object type: {}", object_name),
1788 }),
1789 }
1790 }
1791
1792 fn handle_getter_method(
1794 &self,
1795 object_name: &str,
1796 method: &str,
1797 object_value: &Value,
1798 ) -> Result<String> {
1799 let property_name = Self::extract_property_name_from_getter(method);
1800
1801 match object_value {
1802 Value::Object(obj) => {
1803 if let Some(value) = obj.get(&property_name) {
1804 Ok(value.to_string())
1805 } else {
1806 Err(RuleEngineError::EvaluationError {
1807 message: format!(
1808 "Property '{}' not found on object '{}'",
1809 property_name, object_name
1810 ),
1811 })
1812 }
1813 }
1814 _ => Err(RuleEngineError::EvaluationError {
1815 message: format!("Cannot call getter on non-object type: {}", object_name),
1816 }),
1817 }
1818 }
1819
1820 fn handle_reset_method(
1822 &self,
1823 object_name: &str,
1824 mut object_value: Value,
1825 facts: &Facts,
1826 ) -> Result<String> {
1827 match object_value {
1828 Value::Object(ref mut obj) => {
1829 obj.clear();
1830 facts.add_value(object_name, object_value)?;
1831 Ok(format!("Reset {}", object_name))
1832 }
1833 _ => Err(RuleEngineError::EvaluationError {
1834 message: format!("Cannot reset non-object type: {}", object_name),
1835 }),
1836 }
1837 }
1838
1839 fn handle_property_access_or_fallback(
1841 &self,
1842 object_name: &str,
1843 method: &str,
1844 arg_count: usize,
1845 object_value: &Value,
1846 ) -> Result<String> {
1847 if let Value::Object(obj) = object_value {
1848 if let Some(value) = obj.get(method) {
1850 return Ok(value.to_string());
1851 }
1852
1853 let capitalized_method = Self::capitalize_first_letter(method);
1855 if let Some(value) = obj.get(&capitalized_method) {
1856 return Ok(value.to_string());
1857 }
1858 }
1859
1860 Ok(format!(
1862 "Called {}.{} with {} args",
1863 object_name, method, arg_count
1864 ))
1865 }
1866
1867 fn extract_property_name_from_setter(method: &str) -> String {
1869 let property_name = &method[3..]; Self::capitalize_first_letter(property_name)
1871 }
1872
1873 fn extract_property_name_from_getter(method: &str) -> String {
1875 let property_name = &method[3..]; Self::capitalize_first_letter(property_name)
1877 }
1878
1879 fn capitalize_first_letter(s: &str) -> String {
1881 if s.is_empty() {
1882 return String::new();
1883 }
1884 let mut chars = s.chars();
1885 match chars.next() {
1886 None => String::new(),
1887 Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
1888 }
1889 }
1890
1891 fn resolve_action_parameters(
1893 &self,
1894 params: &HashMap<String, Value>,
1895 facts: &Facts,
1896 ) -> Result<HashMap<String, Value>> {
1897 let mut resolved = HashMap::new();
1898
1899 for (key, value) in params {
1900 let resolved_value = match value {
1901 Value::String(s) => {
1902 if s.contains('.') {
1904 if let Some(fact_value) = facts.get_nested(s) {
1906 fact_value
1907 } else {
1908 value.clone()
1910 }
1911 } else {
1912 value.clone()
1913 }
1914 }
1915 _ => value.clone(),
1916 };
1917 resolved.insert(key.clone(), resolved_value);
1918 }
1919
1920 Ok(resolved)
1921 }
1922
1923 pub fn load_plugin(
1927 &mut self,
1928 plugin: std::sync::Arc<dyn crate::engine::plugin::RulePlugin>,
1929 ) -> Result<()> {
1930 plugin.register_actions(self)?;
1932 plugin.register_functions(self)?;
1933
1934 self.plugin_manager.load_plugin(plugin)
1936 }
1937
1938 pub fn unload_plugin(&mut self, name: &str) -> Result<()> {
1940 self.plugin_manager.unload_plugin(name)
1941 }
1942
1943 pub fn hot_reload_plugin(
1945 &mut self,
1946 name: &str,
1947 new_plugin: std::sync::Arc<dyn crate::engine::plugin::RulePlugin>,
1948 ) -> Result<()> {
1949 self.plugin_manager.unload_plugin(name)?;
1951
1952 new_plugin.register_actions(self)?;
1954 new_plugin.register_functions(self)?;
1955
1956 self.plugin_manager.load_plugin(new_plugin)
1958 }
1959
1960 pub fn get_plugin_info(&self, name: &str) -> Option<&crate::engine::plugin::PluginMetadata> {
1962 self.plugin_manager.get_plugin_info(name)
1963 }
1964
1965 pub fn list_plugins(&self) -> Vec<PluginInfo> {
1967 self.plugin_manager.list_plugins()
1968 }
1969
1970 pub fn get_plugin_stats(&self) -> PluginStats {
1972 self.plugin_manager.get_stats()
1973 }
1974
1975 pub fn plugin_health_check(&mut self) -> HashMap<String, crate::engine::plugin::PluginHealth> {
1977 self.plugin_manager.plugin_health_check()
1978 }
1979
1980 pub fn configure_plugins(&mut self, config: PluginConfig) {
1982 self.plugin_manager = PluginManager::new(config);
1983 }
1984}