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 rule_indices = self.knowledge_base.get_rules_by_salience();
500
501 for &rule_index in &rule_indices {
503 if let Some(rule) = self.knowledge_base.get_rule_by_index(rule_index) {
504 if !rule.enabled {
505 continue;
506 }
507
508 if !self.agenda_manager.should_evaluate_rule(&rule) {
509 continue;
510 }
511
512 if !rule.is_active_at(timestamp) {
514 continue;
515 }
516
517 if !self.agenda_manager.can_fire_rule(&rule) {
519 continue;
520 }
521
522 if !self.activation_group_manager.can_fire(&rule) {
524 continue;
525 }
526
527 if rule.no_loop && self.fired_rules_global.contains(&rule.name) {
529 println!("⛔ Skipping '{}' due to no_loop (already fired)", rule.name);
530 continue;
531 }
532
533 if self.config.debug_mode {
535 println!(
536 "🔍 Checking rule '{}' (no_loop: {})",
537 rule.name, rule.no_loop
538 );
539 }
540
541 let rule_start = std::time::Instant::now();
542
543 rules_evaluated += 1;
545
546 let condition_result = self.evaluate_conditions(&rule.conditions, facts)?;
548
549 if self.config.debug_mode {
550 println!(
551 " Rule '{}' condition result: {}",
552 rule.name, condition_result
553 );
554 }
555
556 if condition_result {
558 if self.config.debug_mode {
559 println!(
560 "🔥 Firing rule '{}' (salience: {})",
561 rule.name, rule.salience
562 );
563 }
564
565 for action in &rule.actions {
567 self.execute_action(action, facts)?;
568 }
569
570 let rule_duration = rule_start.elapsed();
571
572 if let Some(analytics) = &mut self.analytics {
574 analytics.record_execution(
575 &rule.name,
576 rule_duration,
577 true,
578 true,
579 None,
580 0,
581 );
582 }
583
584 rules_fired += 1;
585 any_rule_fired = true;
586
587 fired_rules_in_cycle.insert(rule.name.clone());
589
590 if rule.no_loop {
592 self.fired_rules_global.insert(rule.name.clone());
593 if self.config.debug_mode {
594 println!(" 🔒 Marked '{}' as fired (no_loop tracking)", rule.name);
595 }
596 }
597
598 self.agenda_manager.mark_rule_fired(&rule);
600 self.activation_group_manager.mark_fired(&rule);
601 } else {
602 let rule_duration = rule_start.elapsed();
603
604 if let Some(analytics) = &mut self.analytics {
606 analytics.record_execution(
607 &rule.name,
608 rule_duration,
609 false,
610 false,
611 None,
612 0,
613 );
614 }
615 }
616 } }
618
619 if !any_rule_fired {
621 break;
622 }
623
624 self.sync_workflow_agenda_activations();
626 }
627
628 let execution_time = start_time.elapsed();
629
630 Ok(GruleExecutionResult {
631 cycle_count,
632 rules_evaluated,
633 rules_fired,
634 execution_time,
635 })
636 }
637
638 fn evaluate_conditions(
640 &self,
641 conditions: &crate::engine::rule::ConditionGroup,
642 facts: &Facts,
643 ) -> Result<bool> {
644 use crate::engine::pattern_matcher::PatternMatcher;
645 use crate::engine::rule::ConditionGroup;
646
647 match conditions {
648 ConditionGroup::Single(condition) => self.evaluate_single_condition(condition, facts),
649 ConditionGroup::Compound {
650 left,
651 operator,
652 right,
653 } => {
654 let left_result = self.evaluate_conditions(left, facts)?;
655 let right_result = self.evaluate_conditions(right, facts)?;
656
657 match operator {
658 crate::types::LogicalOperator::And => Ok(left_result && right_result),
659 crate::types::LogicalOperator::Or => Ok(left_result || right_result),
660 crate::types::LogicalOperator::Not => Err(RuleEngineError::EvaluationError {
661 message: "NOT operator should not appear in compound conditions"
662 .to_string(),
663 }),
664 }
665 }
666 ConditionGroup::Not(condition) => {
667 let result = self.evaluate_conditions(condition, facts)?;
668 Ok(!result)
669 }
670 ConditionGroup::Exists(condition) => {
672 Ok(PatternMatcher::evaluate_exists(condition, facts))
673 }
674 ConditionGroup::Forall(condition) => {
675 Ok(PatternMatcher::evaluate_forall(condition, facts))
676 }
677 ConditionGroup::Accumulate {
678 result_var,
679 source_pattern,
680 extract_field,
681 source_conditions,
682 function,
683 function_arg,
684 } => {
685 self.evaluate_accumulate(
687 result_var,
688 source_pattern,
689 extract_field,
690 source_conditions,
691 function,
692 function_arg,
693 facts,
694 )?;
695 Ok(true)
697 }
698
699 #[cfg(feature = "streaming")]
700 ConditionGroup::StreamPattern { .. } => {
701 Ok(true)
704 }
705 }
706 }
707
708 #[allow(clippy::too_many_arguments)]
710 fn evaluate_accumulate(
711 &self,
712 _result_var: &str,
713 source_pattern: &str,
714 extract_field: &str,
715 source_conditions: &[String],
716 function: &str,
717 _function_arg: &str,
718 facts: &Facts,
719 ) -> Result<()> {
720 use crate::rete::accumulate::*;
721
722 let all_facts = facts.get_all_facts();
724 let mut matching_values = Vec::new();
725
726 let pattern_prefix = format!("{}.", source_pattern);
728
729 let mut instances: HashMap<String, HashMap<String, Value>> = HashMap::with_capacity(16);
731
732 for (key, value) in &all_facts {
733 if key.starts_with(&pattern_prefix) {
734 let parts: Vec<&str> = key
736 .strip_prefix(&pattern_prefix)
737 .unwrap()
738 .split('.')
739 .collect();
740
741 if parts.len() >= 2 {
742 let instance_id = parts[0];
744 let field_name = parts[1..].join(".");
745
746 instances
747 .entry(instance_id.to_string())
748 .or_default()
749 .insert(field_name, value.clone());
750 } else if parts.len() == 1 {
751 instances
753 .entry("default".to_string())
754 .or_default()
755 .insert(parts[0].to_string(), value.clone());
756 }
757 }
758 }
759
760 for (_instance_id, instance_facts) in instances {
762 let mut matches = true;
764
765 for condition_str in source_conditions {
766 if !self.evaluate_condition_string(condition_str, &instance_facts) {
768 matches = false;
769 break;
770 }
771 }
772
773 if matches {
774 if let Some(value) = instance_facts.get(extract_field) {
776 matching_values.push(value.clone());
777 }
778 }
779 }
780
781 let result = match function {
783 "sum" => {
784 let mut state = SumFunction.init();
785 for value in &matching_values {
786 state.accumulate(&self.value_to_fact_value(value));
787 }
788 self.fact_value_to_value(&state.get_result())
789 }
790 "count" => {
791 let mut state = CountFunction.init();
792 for value in &matching_values {
793 state.accumulate(&self.value_to_fact_value(value));
794 }
795 self.fact_value_to_value(&state.get_result())
796 }
797 "average" | "avg" => {
798 let mut state = AverageFunction.init();
799 for value in &matching_values {
800 state.accumulate(&self.value_to_fact_value(value));
801 }
802 self.fact_value_to_value(&state.get_result())
803 }
804 "min" => {
805 let mut state = MinFunction.init();
806 for value in &matching_values {
807 state.accumulate(&self.value_to_fact_value(value));
808 }
809 self.fact_value_to_value(&state.get_result())
810 }
811 "max" => {
812 let mut state = MaxFunction.init();
813 for value in &matching_values {
814 state.accumulate(&self.value_to_fact_value(value));
815 }
816 self.fact_value_to_value(&state.get_result())
817 }
818 _ => {
819 return Err(RuleEngineError::EvaluationError {
820 message: format!("Unknown accumulate function: {}", function),
821 });
822 }
823 };
824
825 let result_key = format!("{}.{}", source_pattern, function);
828
829 facts.set(&result_key, result);
830
831 if self.config.debug_mode {
832 println!(
833 " 🧮 Accumulate result: {} = {:?}",
834 result_key,
835 facts.get(&result_key)
836 );
837 }
838
839 Ok(())
840 }
841
842 fn value_to_fact_value(&self, value: &Value) -> crate::rete::facts::FactValue {
844 use crate::rete::facts::FactValue;
845 match value {
846 Value::Integer(i) => FactValue::Integer(*i),
847 Value::Number(n) => FactValue::Float(*n),
848 Value::String(s) => FactValue::String(s.clone()),
849 Value::Boolean(b) => FactValue::Boolean(*b),
850 _ => FactValue::String(value.to_string()),
851 }
852 }
853
854 fn fact_value_to_value(&self, fact_value: &crate::rete::facts::FactValue) -> Value {
856 use crate::rete::facts::FactValue;
857 match fact_value {
858 FactValue::Integer(i) => Value::Integer(*i),
859 FactValue::Float(f) => Value::Number(*f),
860 FactValue::String(s) => Value::String(s.clone()),
861 FactValue::Boolean(b) => Value::Boolean(*b),
862 FactValue::Array(_) => Value::String(format!("{:?}", fact_value)),
863 FactValue::Null => Value::String("null".to_string()),
864 }
865 }
866
867 fn evaluate_condition_string(&self, condition: &str, facts: &HashMap<String, Value>) -> bool {
869 let condition = condition.trim();
871
872 let operators = ["==", "!=", ">=", "<=", ">", "<"];
874
875 for op in &operators {
876 if let Some(pos) = condition.find(op) {
877 let field = condition[..pos].trim();
878 let value_str = condition[pos + op.len()..]
879 .trim()
880 .trim_matches('"')
881 .trim_matches('\'');
882
883 if let Some(field_value) = facts.get(field) {
884 return self.compare_values(field_value, op, value_str);
885 } else {
886 return false;
887 }
888 }
889 }
890
891 false
892 }
893
894 fn compare_values(&self, field_value: &Value, operator: &str, value_str: &str) -> bool {
896 match field_value {
897 Value::String(s) => match operator {
898 "==" => s == value_str,
899 "!=" => s != value_str,
900 _ => false,
901 },
902 Value::Integer(i) => {
903 if let Ok(num) = value_str.parse::<i64>() {
904 match operator {
905 "==" => *i == num,
906 "!=" => *i != num,
907 ">" => *i > num,
908 "<" => *i < num,
909 ">=" => *i >= num,
910 "<=" => *i <= num,
911 _ => false,
912 }
913 } else {
914 false
915 }
916 }
917 Value::Number(n) => {
918 if let Ok(num) = value_str.parse::<f64>() {
919 match operator {
920 "==" => (*n - num).abs() < f64::EPSILON,
921 "!=" => (*n - num).abs() >= f64::EPSILON,
922 ">" => *n > num,
923 "<" => *n < num,
924 ">=" => *n >= num,
925 "<=" => *n <= num,
926 _ => false,
927 }
928 } else {
929 false
930 }
931 }
932 Value::Boolean(b) => {
933 if let Ok(bool_val) = value_str.parse::<bool>() {
934 match operator {
935 "==" => *b == bool_val,
936 "!=" => *b != bool_val,
937 _ => false,
938 }
939 } else {
940 false
941 }
942 }
943 _ => false,
944 }
945 }
946
947 fn evaluate_rule_conditions(
949 &self,
950 rule: &crate::engine::rule::Rule,
951 facts: &Facts,
952 ) -> Result<bool> {
953 self.evaluate_conditions(&rule.conditions, facts)
954 }
955
956 fn is_retracted(&self, object_name: &str, facts: &Facts) -> bool {
958 let retract_key = format!("_retracted_{}", object_name);
959 matches!(facts.get(&retract_key), Some(Value::Boolean(true)))
960 }
961
962 fn evaluate_single_condition(
964 &self,
965 condition: &crate::engine::rule::Condition,
966 facts: &Facts,
967 ) -> Result<bool> {
968 use crate::engine::rule::ConditionExpression;
969
970 let result = match &condition.expression {
971 ConditionExpression::Field(field_name) => {
972 if let Some(object_name) = field_name.split('.').next() {
975 if self.is_retracted(object_name, facts) {
976 if self.config.debug_mode {
977 println!(" 🗑️ Skipping retracted fact: {}", object_name);
978 }
979 return Ok(false);
980 }
981 }
982
983 let field_value = facts
986 .get_nested(field_name)
987 .or_else(|| facts.get(field_name))
988 .unwrap_or(Value::Null);
989
990 if self.config.debug_mode {
991 println!(
992 " 🔎 Evaluating field condition: {} {} {:?}",
993 field_name,
994 format!("{:?}", condition.operator).to_lowercase(),
995 condition.value
996 );
997 println!(" Field value: {:?}", field_value);
998 }
999
1000 let rhs = match &condition.value {
1006 crate::types::Value::String(s) => {
1007 facts
1009 .get_nested(s)
1010 .or_else(|| facts.get(s))
1011 .unwrap_or(crate::types::Value::String(s.clone()))
1012 }
1013 crate::types::Value::Expression(expr) => {
1014 match crate::expression::evaluate_expression(expr, facts) {
1016 Ok(evaluated) => evaluated,
1017 Err(_) => {
1018 facts
1020 .get_nested(expr)
1021 .or_else(|| facts.get(expr))
1022 .unwrap_or(crate::types::Value::Expression(expr.clone()))
1023 }
1024 }
1025 }
1026 _ => condition.value.clone(),
1027 };
1028
1029 if self.config.debug_mode {
1030 println!(" Resolved RHS for comparison: {:?}", rhs);
1031 }
1032
1033 condition.operator.evaluate(&field_value, &rhs)
1034 }
1035 ConditionExpression::FunctionCall { name, args } => {
1036 if self.config.debug_mode {
1038 println!(
1039 " 🔎 Evaluating function condition: {}({:?}) {} {:?}",
1040 name,
1041 args,
1042 format!("{:?}", condition.operator).to_lowercase(),
1043 condition.value
1044 );
1045 }
1046
1047 if let Some(function) = self.custom_functions.get(name) {
1048 let arg_values: Vec<Value> = args
1050 .iter()
1051 .map(|arg| {
1052 facts
1053 .get_nested(arg)
1054 .or_else(|| facts.get(arg))
1055 .unwrap_or(Value::String(arg.clone()))
1056 })
1057 .collect();
1058
1059 match function(&arg_values, facts) {
1061 Ok(result_value) => {
1062 if self.config.debug_mode {
1063 println!(" Function result: {:?}", result_value);
1064 }
1065 condition.operator.evaluate(&result_value, &condition.value)
1066 }
1067 Err(e) => {
1068 if self.config.debug_mode {
1069 println!(" Function error: {}", e);
1070 }
1071 false
1072 }
1073 }
1074 } else {
1075 if self.config.debug_mode {
1076 println!(" Function '{}' not found", name);
1077 }
1078 false
1079 }
1080 }
1081 ConditionExpression::Test { name, args } => {
1082 if self.config.debug_mode {
1084 println!(" 🧪 Evaluating test CE: test({}({:?}))", name, args);
1085 }
1086
1087 if let Some(function) = self.custom_functions.get(name) {
1089 let arg_values: Vec<Value> = args
1091 .iter()
1092 .map(|arg| {
1093 let resolved = facts
1094 .get_nested(arg)
1095 .or_else(|| facts.get(arg))
1096 .unwrap_or(Value::String(arg.clone()));
1097 if self.config.debug_mode {
1098 println!(" Resolving arg '{}' -> {:?}", arg, resolved);
1099 }
1100 resolved
1101 })
1102 .collect();
1103
1104 match function(&arg_values, facts) {
1106 Ok(result_value) => {
1107 if self.config.debug_mode {
1108 println!(" Test result: {:?}", result_value);
1109 }
1110 match result_value {
1112 Value::Boolean(b) => b,
1113 Value::Integer(i) => i != 0,
1114 Value::Number(f) => f != 0.0,
1115 Value::String(s) => !s.is_empty(),
1116 _ => false,
1117 }
1118 }
1119 Err(e) => {
1120 if self.config.debug_mode {
1121 println!(" Test function error: {}", e);
1122 }
1123 false
1124 }
1125 }
1126 } else {
1127 if self.config.debug_mode {
1130 println!(
1131 " Trying to evaluate '{}' as arithmetic expression",
1132 name
1133 );
1134 }
1135
1136 match self.evaluate_arithmetic_condition(name, facts) {
1138 Ok(result) => {
1139 if self.config.debug_mode {
1140 println!(" Arithmetic expression result: {}", result);
1141 }
1142 result
1143 }
1144 Err(e) => {
1145 if self.config.debug_mode {
1146 println!(" Failed to evaluate expression: {}", e);
1147 println!(" Test function '{}' not found", name);
1148 }
1149 false
1150 }
1151 }
1152 }
1153 }
1154 ConditionExpression::MultiField {
1155 field,
1156 operation,
1157 variable: _,
1158 } => {
1159 if self.config.debug_mode {
1161 println!(" 📦 Evaluating multi-field: {}.{}", field, operation);
1162 }
1163
1164 let field_value = facts.get_nested(field).or_else(|| facts.get(field));
1166
1167 if let Some(value) = field_value {
1168 match operation.as_str() {
1169 "empty" => {
1170 matches!(value, Value::Array(arr) if arr.is_empty())
1171 }
1172 "not_empty" => {
1173 matches!(value, Value::Array(arr) if !arr.is_empty())
1174 }
1175 "count" => {
1176 if let Value::Array(arr) = value {
1177 let count = Value::Integer(arr.len() as i64);
1178 condition.operator.evaluate(&count, &condition.value)
1179 } else {
1180 false
1181 }
1182 }
1183 "contains" => {
1184 condition.operator.evaluate(&value, &condition.value)
1186 }
1187 _ => {
1188 if self.config.debug_mode {
1191 println!(
1192 " ⚠️ Operation '{}' not fully implemented yet",
1193 operation
1194 );
1195 }
1196 true
1197 }
1198 }
1199 } else {
1200 false
1201 }
1202 }
1203 };
1204
1205 if self.config.debug_mode {
1206 println!(" Result: {}", result);
1207 }
1208
1209 Ok(result)
1210 }
1211
1212 fn execute_action(&mut self, action: &ActionType, facts: &Facts) -> Result<()> {
1214 match action {
1215 ActionType::Set { field, value } => {
1216 let evaluated_value = match value {
1218 Value::Expression(expr) => {
1219 crate::expression::evaluate_expression(expr, facts)?
1221 }
1222 _ => value.clone(),
1223 };
1224
1225 if facts.set_nested(field, evaluated_value.clone()).is_err() {
1227 facts.set(field, evaluated_value.clone());
1229 }
1230 if self.config.debug_mode {
1231 println!(" ✅ Set {field} = {evaluated_value:?}");
1232 }
1233 }
1234 ActionType::Log { message } => {
1235 println!("📋 LOG: {}", message);
1236 }
1237 ActionType::MethodCall {
1238 object,
1239 method,
1240 args,
1241 } => {
1242 let result = self.execute_method_call(object, method, args, facts)?;
1243 if self.config.debug_mode {
1244 println!(" 🔧 Called {object}.{method}({args:?}) -> {result}");
1245 }
1246 }
1247 ActionType::Retract { object } => {
1248 if self.config.debug_mode {
1249 println!(" 🗑️ Retracted {object}");
1250 }
1251 facts.set(&format!("_retracted_{}", object), Value::Boolean(true));
1253 }
1254 ActionType::Custom {
1255 action_type,
1256 params,
1257 } => {
1258 if let Some(handler) = self.action_handlers.get(action_type) {
1259 if self.config.debug_mode {
1260 println!(
1261 " 🎯 Executing custom action: {action_type} with params: {params:?}"
1262 );
1263 }
1264
1265 let resolved_params = self.resolve_action_parameters(params, facts)?;
1267
1268 handler(&resolved_params, facts)?;
1270 } else {
1271 if self.config.debug_mode {
1272 println!(" ⚠️ No handler registered for custom action: {action_type}");
1273 println!(
1274 " Available handlers: {:?}",
1275 self.action_handlers.keys().collect::<Vec<_>>()
1276 );
1277 }
1278
1279 return Err(RuleEngineError::EvaluationError {
1281 message: format!(
1282 "No action handler registered for '{action_type}'. Use engine.register_action_handler() to add custom action handlers."
1283 ),
1284 });
1285 }
1286 }
1287 ActionType::ActivateAgendaGroup { group } => {
1289 if self.config.debug_mode {
1290 println!(" 🎯 Activating agenda group: {}", group);
1291 }
1292 self.workflow_engine.activate_agenda_group(group.clone());
1294 self.agenda_manager.set_focus(group);
1295 }
1296 ActionType::ScheduleRule {
1297 rule_name,
1298 delay_ms,
1299 } => {
1300 if self.config.debug_mode {
1301 println!(
1302 " ⏰ Scheduling rule '{}' to execute in {}ms",
1303 rule_name, delay_ms
1304 );
1305 }
1306 self.workflow_engine
1307 .schedule_rule(rule_name.clone(), *delay_ms, None);
1308 }
1309 ActionType::CompleteWorkflow { workflow_name } => {
1310 if self.config.debug_mode {
1311 println!(" ✅ Completing workflow: {}", workflow_name);
1312 }
1313 self.workflow_engine
1314 .complete_workflow(workflow_name.clone());
1315 }
1316 ActionType::SetWorkflowData { key, value } => {
1317 if self.config.debug_mode {
1318 println!(" 💾 Setting workflow data: {} = {:?}", key, value);
1319 }
1320 let workflow_id = "default_workflow";
1323 self.workflow_engine
1324 .set_workflow_data(workflow_id, key.clone(), value.clone());
1325 }
1326 ActionType::Append { field, value } => {
1327 let evaluated_value = match value {
1329 Value::Expression(expr) => crate::expression::evaluate_expression(expr, facts)?,
1330 _ => value.clone(),
1331 };
1332
1333 let current_value = facts.get(field);
1335 let mut array = match current_value {
1336 Some(Value::Array(arr)) => arr.clone(),
1337 Some(_) => {
1338 if self.config.debug_mode {
1340 println!(" ⚠️ Field {} is not an array, creating new array", field);
1341 }
1342 Vec::new()
1343 }
1344 None => Vec::new(),
1345 };
1346
1347 array.push(evaluated_value.clone());
1349
1350 if facts
1352 .set_nested(field, Value::Array(array.clone()))
1353 .is_err()
1354 {
1355 facts.set(field, Value::Array(array.clone()));
1356 }
1357
1358 if self.config.debug_mode {
1359 println!(" ➕ Appended to {}: {:?}", field, evaluated_value);
1360 }
1361 }
1362 }
1363 Ok(())
1364 }
1365
1366 fn evaluate_arithmetic_condition(&self, expr: &str, facts: &Facts) -> Result<bool> {
1368 let operators = [">=", "<=", "==", "!=", ">", "<"];
1372 let mut split_pos = None;
1373 let mut found_op = "";
1374
1375 for op in &operators {
1376 if let Some(pos) = expr.rfind(op) {
1377 split_pos = Some(pos);
1378 found_op = op;
1379 break;
1380 }
1381 }
1382
1383 if split_pos.is_none() {
1384 return Err(RuleEngineError::EvaluationError {
1385 message: format!("No comparison operator found in expression: {}", expr),
1386 });
1387 }
1388
1389 let pos = split_pos.unwrap();
1390 let left_expr = expr[..pos].trim();
1391 let right_value = expr[pos + found_op.len()..].trim();
1392
1393 let left_result = crate::expression::evaluate_expression(left_expr, facts)?;
1395
1396 let right_val = if let Ok(i) = right_value.parse::<i64>() {
1398 Value::Integer(i)
1399 } else if let Ok(f) = right_value.parse::<f64>() {
1400 Value::Number(f)
1401 } else {
1402 match crate::expression::evaluate_expression(right_value, facts) {
1404 Ok(v) => v,
1405 Err(_) => Value::String(right_value.to_string()),
1406 }
1407 };
1408
1409 let operator =
1411 Operator::from_str(found_op).ok_or_else(|| RuleEngineError::InvalidOperator {
1412 operator: found_op.to_string(),
1413 })?;
1414
1415 Ok(operator.evaluate(&left_result, &right_val))
1416 }
1417
1418 fn execute_function_call(
1420 &self,
1421 function: &str,
1422 args: &[Value],
1423 facts: &Facts,
1424 ) -> Result<String> {
1425 let function_lower = function.to_lowercase();
1426
1427 match function_lower.as_str() {
1429 "log" | "print" | "println" => self.handle_log_function(args),
1430 "update" | "refresh" => self.handle_update_function(args),
1431 "now" | "timestamp" => self.handle_timestamp_function(),
1432 "random" => self.handle_random_function(args),
1433 "format" | "sprintf" => self.handle_format_function(args),
1434 "length" | "size" | "count" => self.handle_length_function(args),
1435 "sum" | "add" => self.handle_sum_function(args),
1436 "max" | "maximum" => self.handle_max_function(args),
1437 "min" | "minimum" => self.handle_min_function(args),
1438 "avg" | "average" => self.handle_average_function(args),
1439 "round" => self.handle_round_function(args),
1440 "floor" => self.handle_floor_function(args),
1441 "ceil" | "ceiling" => self.handle_ceil_function(args),
1442 "abs" | "absolute" => self.handle_abs_function(args),
1443 "contains" | "includes" => self.handle_contains_function(args),
1444 "startswith" | "begins_with" => self.handle_starts_with_function(args),
1445 "endswith" | "ends_with" => self.handle_ends_with_function(args),
1446 "lowercase" | "tolower" => self.handle_lowercase_function(args),
1447 "uppercase" | "toupper" => self.handle_uppercase_function(args),
1448 "trim" | "strip" => self.handle_trim_function(args),
1449 "split" => self.handle_split_function(args),
1450 "join" => self.handle_join_function(args),
1451 _ => {
1452 self.handle_custom_function(function, args, facts)
1454 }
1455 }
1456 }
1457
1458 fn handle_log_function(&self, args: &[Value]) -> Result<String> {
1460 let message = if args.is_empty() {
1461 "".to_string()
1462 } else if args.len() == 1 {
1463 args[0].to_string()
1464 } else {
1465 args.iter()
1466 .map(|v| v.to_string())
1467 .collect::<Vec<_>>()
1468 .join(" ")
1469 };
1470
1471 info!("📋 {}", message);
1472 Ok(message)
1473 }
1474
1475 fn handle_update_function(&self, args: &[Value]) -> Result<String> {
1477 if let Some(arg) = args.first() {
1478 Ok(format!("Updated: {}", arg.to_string()))
1479 } else {
1480 Ok("Updated".to_string())
1481 }
1482 }
1483
1484 fn handle_timestamp_function(&self) -> Result<String> {
1486 use std::time::{SystemTime, UNIX_EPOCH};
1487 let timestamp = SystemTime::now()
1488 .duration_since(UNIX_EPOCH)
1489 .map_err(|e| RuleEngineError::EvaluationError {
1490 message: format!("Failed to get timestamp: {}", e),
1491 })?
1492 .as_secs();
1493 Ok(timestamp.to_string())
1494 }
1495
1496 fn handle_random_function(&self, args: &[Value]) -> Result<String> {
1498 use std::collections::hash_map::DefaultHasher;
1499 use std::hash::{Hash, Hasher};
1500
1501 let mut hasher = DefaultHasher::new();
1503 std::time::SystemTime::now().hash(&mut hasher);
1504 let random_value = hasher.finish();
1505
1506 if args.is_empty() {
1507 Ok((random_value % 100).to_string()) } else if let Some(Value::Number(max)) = args.first() {
1509 let max_val = *max as u64;
1510 Ok((random_value % max_val).to_string())
1511 } else {
1512 Ok(random_value.to_string())
1513 }
1514 }
1515
1516 fn handle_format_function(&self, args: &[Value]) -> Result<String> {
1518 if args.is_empty() {
1519 return Ok("".to_string());
1520 }
1521
1522 let template = args[0].to_string();
1523 let values: Vec<String> = args[1..].iter().map(|v| v.to_string()).collect();
1524
1525 let mut result = template;
1527 for (i, value) in values.iter().enumerate() {
1528 result = result.replace(&format!("{{{}}}", i), value);
1529 }
1530
1531 Ok(result)
1532 }
1533
1534 fn handle_length_function(&self, args: &[Value]) -> Result<String> {
1536 if let Some(arg) = args.first() {
1537 match arg {
1538 Value::String(s) => Ok(s.len().to_string()),
1539 Value::Array(arr) => Ok(arr.len().to_string()),
1540 Value::Object(obj) => Ok(obj.len().to_string()),
1541 _ => Ok("1".to_string()), }
1543 } else {
1544 Ok("0".to_string())
1545 }
1546 }
1547
1548 fn handle_sum_function(&self, args: &[Value]) -> Result<String> {
1550 let sum = args.iter().fold(0.0, |acc, val| match val {
1551 Value::Number(n) => acc + n,
1552 Value::Integer(i) => acc + (*i as f64),
1553 _ => acc,
1554 });
1555 Ok(sum.to_string())
1556 }
1557
1558 fn handle_max_function(&self, args: &[Value]) -> Result<String> {
1560 let max = args.iter().fold(f64::NEG_INFINITY, |acc, val| match val {
1561 Value::Number(n) => acc.max(*n),
1562 Value::Integer(i) => acc.max(*i as f64),
1563 _ => acc,
1564 });
1565 Ok(max.to_string())
1566 }
1567
1568 fn handle_min_function(&self, args: &[Value]) -> Result<String> {
1570 let min = args.iter().fold(f64::INFINITY, |acc, val| match val {
1571 Value::Number(n) => acc.min(*n),
1572 Value::Integer(i) => acc.min(*i as f64),
1573 _ => acc,
1574 });
1575 Ok(min.to_string())
1576 }
1577
1578 fn handle_average_function(&self, args: &[Value]) -> Result<String> {
1580 if args.is_empty() {
1581 return Ok("0".to_string());
1582 }
1583
1584 let (sum, count) = args.iter().fold((0.0, 0), |(sum, count), val| match val {
1585 Value::Number(n) => (sum + n, count + 1),
1586 Value::Integer(i) => (sum + (*i as f64), count + 1),
1587 _ => (sum, count),
1588 });
1589
1590 if count > 0 {
1591 Ok((sum / count as f64).to_string())
1592 } else {
1593 Ok("0".to_string())
1594 }
1595 }
1596
1597 fn handle_round_function(&self, args: &[Value]) -> Result<String> {
1599 if let Some(Value::Number(n)) = args.first() {
1600 Ok(n.round().to_string())
1601 } else if let Some(Value::Integer(i)) = args.first() {
1602 Ok(i.to_string())
1603 } else {
1604 Err(RuleEngineError::EvaluationError {
1605 message: "round() requires a numeric argument".to_string(),
1606 })
1607 }
1608 }
1609
1610 fn handle_floor_function(&self, args: &[Value]) -> Result<String> {
1611 if let Some(Value::Number(n)) = args.first() {
1612 Ok(n.floor().to_string())
1613 } else if let Some(Value::Integer(i)) = args.first() {
1614 Ok(i.to_string())
1615 } else {
1616 Err(RuleEngineError::EvaluationError {
1617 message: "floor() requires a numeric argument".to_string(),
1618 })
1619 }
1620 }
1621
1622 fn handle_ceil_function(&self, args: &[Value]) -> Result<String> {
1623 if let Some(Value::Number(n)) = args.first() {
1624 Ok(n.ceil().to_string())
1625 } else if let Some(Value::Integer(i)) = args.first() {
1626 Ok(i.to_string())
1627 } else {
1628 Err(RuleEngineError::EvaluationError {
1629 message: "ceil() requires a numeric argument".to_string(),
1630 })
1631 }
1632 }
1633
1634 fn handle_abs_function(&self, args: &[Value]) -> Result<String> {
1635 if let Some(Value::Number(n)) = args.first() {
1636 Ok(n.abs().to_string())
1637 } else if let Some(Value::Integer(i)) = args.first() {
1638 Ok(i.abs().to_string())
1639 } else {
1640 Err(RuleEngineError::EvaluationError {
1641 message: "abs() requires a numeric argument".to_string(),
1642 })
1643 }
1644 }
1645
1646 fn handle_contains_function(&self, args: &[Value]) -> Result<String> {
1648 if args.len() >= 2 {
1649 let haystack = args[0].to_string();
1650 let needle = args[1].to_string();
1651 Ok(haystack.contains(&needle).to_string())
1652 } else {
1653 Err(RuleEngineError::EvaluationError {
1654 message: "contains() requires 2 arguments".to_string(),
1655 })
1656 }
1657 }
1658
1659 fn handle_starts_with_function(&self, args: &[Value]) -> Result<String> {
1660 if args.len() >= 2 {
1661 let text = args[0].to_string();
1662 let prefix = args[1].to_string();
1663 Ok(text.starts_with(&prefix).to_string())
1664 } else {
1665 Err(RuleEngineError::EvaluationError {
1666 message: "startswith() requires 2 arguments".to_string(),
1667 })
1668 }
1669 }
1670
1671 fn handle_ends_with_function(&self, args: &[Value]) -> Result<String> {
1672 if args.len() >= 2 {
1673 let text = args[0].to_string();
1674 let suffix = args[1].to_string();
1675 Ok(text.ends_with(&suffix).to_string())
1676 } else {
1677 Err(RuleEngineError::EvaluationError {
1678 message: "endswith() requires 2 arguments".to_string(),
1679 })
1680 }
1681 }
1682
1683 fn handle_lowercase_function(&self, args: &[Value]) -> Result<String> {
1684 if let Some(arg) = args.first() {
1685 Ok(arg.to_string().to_lowercase())
1686 } else {
1687 Err(RuleEngineError::EvaluationError {
1688 message: "lowercase() requires 1 argument".to_string(),
1689 })
1690 }
1691 }
1692
1693 fn handle_uppercase_function(&self, args: &[Value]) -> Result<String> {
1694 if let Some(arg) = args.first() {
1695 Ok(arg.to_string().to_uppercase())
1696 } else {
1697 Err(RuleEngineError::EvaluationError {
1698 message: "uppercase() requires 1 argument".to_string(),
1699 })
1700 }
1701 }
1702
1703 fn handle_trim_function(&self, args: &[Value]) -> Result<String> {
1704 if let Some(arg) = args.first() {
1705 Ok(arg.to_string().trim().to_string())
1706 } else {
1707 Err(RuleEngineError::EvaluationError {
1708 message: "trim() requires 1 argument".to_string(),
1709 })
1710 }
1711 }
1712
1713 fn handle_split_function(&self, args: &[Value]) -> Result<String> {
1714 if args.len() >= 2 {
1715 let text = args[0].to_string();
1716 let delimiter = args[1].to_string();
1717 let parts: Vec<String> = text.split(&delimiter).map(|s| s.to_string()).collect();
1718 Ok(format!("{:?}", parts)) } else {
1720 Err(RuleEngineError::EvaluationError {
1721 message: "split() requires 2 arguments".to_string(),
1722 })
1723 }
1724 }
1725
1726 fn handle_join_function(&self, args: &[Value]) -> Result<String> {
1727 if args.len() >= 2 {
1728 let delimiter = args[0].to_string();
1729 let parts: Vec<String> = args[1..].iter().map(|v| v.to_string()).collect();
1730 Ok(parts.join(&delimiter))
1731 } else {
1732 Err(RuleEngineError::EvaluationError {
1733 message: "join() requires at least 2 arguments".to_string(),
1734 })
1735 }
1736 }
1737
1738 fn handle_custom_function(
1740 &self,
1741 function: &str,
1742 args: &[Value],
1743 facts: &Facts,
1744 ) -> Result<String> {
1745 if let Some(custom_func) = self.custom_functions.get(function) {
1747 if self.config.debug_mode {
1748 println!("🎯 Calling registered function: {}({:?})", function, args);
1749 }
1750
1751 match custom_func(args, facts) {
1752 Ok(result) => Ok(result.to_string()),
1753 Err(e) => Err(e),
1754 }
1755 } else {
1756 if self.config.debug_mode {
1758 println!("⚠️ Custom function '{}' not registered", function);
1759 }
1760
1761 Err(RuleEngineError::EvaluationError {
1762 message: format!("Function '{}' is not registered. Use engine.register_function() to add custom functions.", function),
1763 })
1764 }
1765 }
1766
1767 fn execute_method_call(
1769 &self,
1770 object_name: &str,
1771 method: &str,
1772 args: &[Value],
1773 facts: &Facts,
1774 ) -> Result<String> {
1775 let Some(object_value) = facts.get(object_name) else {
1777 return Err(RuleEngineError::EvaluationError {
1778 message: format!("Object '{}' not found in facts", object_name),
1779 });
1780 };
1781
1782 let method_lower = method.to_lowercase();
1783
1784 if method_lower.starts_with("set") && args.len() == 1 {
1786 return self.handle_setter_method(object_name, method, &args[0], object_value, facts);
1787 }
1788
1789 if method_lower.starts_with("get") && args.is_empty() {
1791 return self.handle_getter_method(object_name, method, &object_value);
1792 }
1793
1794 match method_lower.as_str() {
1796 "tostring" => Ok(object_value.to_string()),
1797 "update" => {
1798 facts.add_value(object_name, object_value)?;
1799 Ok(format!("Updated {}", object_name))
1800 }
1801 "reset" => self.handle_reset_method(object_name, object_value, facts),
1802 _ => self.handle_property_access_or_fallback(
1803 object_name,
1804 method,
1805 args.len(),
1806 &object_value,
1807 ),
1808 }
1809 }
1810
1811 fn handle_setter_method(
1813 &self,
1814 object_name: &str,
1815 method: &str,
1816 new_value: &Value,
1817 mut object_value: Value,
1818 facts: &Facts,
1819 ) -> Result<String> {
1820 let property_name = Self::extract_property_name_from_setter(method);
1821
1822 match object_value {
1823 Value::Object(ref mut obj) => {
1824 obj.insert(property_name.clone(), new_value.clone());
1825 facts.add_value(object_name, object_value)?;
1826 Ok(format!(
1827 "Set {} to {}",
1828 property_name,
1829 new_value.to_string()
1830 ))
1831 }
1832 _ => Err(RuleEngineError::EvaluationError {
1833 message: format!("Cannot call setter on non-object type: {}", object_name),
1834 }),
1835 }
1836 }
1837
1838 fn handle_getter_method(
1840 &self,
1841 object_name: &str,
1842 method: &str,
1843 object_value: &Value,
1844 ) -> Result<String> {
1845 let property_name = Self::extract_property_name_from_getter(method);
1846
1847 match object_value {
1848 Value::Object(obj) => {
1849 if let Some(value) = obj.get(&property_name) {
1850 Ok(value.to_string())
1851 } else {
1852 Err(RuleEngineError::EvaluationError {
1853 message: format!(
1854 "Property '{}' not found on object '{}'",
1855 property_name, object_name
1856 ),
1857 })
1858 }
1859 }
1860 _ => Err(RuleEngineError::EvaluationError {
1861 message: format!("Cannot call getter on non-object type: {}", object_name),
1862 }),
1863 }
1864 }
1865
1866 fn handle_reset_method(
1868 &self,
1869 object_name: &str,
1870 mut object_value: Value,
1871 facts: &Facts,
1872 ) -> Result<String> {
1873 match object_value {
1874 Value::Object(ref mut obj) => {
1875 obj.clear();
1876 facts.add_value(object_name, object_value)?;
1877 Ok(format!("Reset {}", object_name))
1878 }
1879 _ => Err(RuleEngineError::EvaluationError {
1880 message: format!("Cannot reset non-object type: {}", object_name),
1881 }),
1882 }
1883 }
1884
1885 fn handle_property_access_or_fallback(
1887 &self,
1888 object_name: &str,
1889 method: &str,
1890 arg_count: usize,
1891 object_value: &Value,
1892 ) -> Result<String> {
1893 if let Value::Object(obj) = object_value {
1894 if let Some(value) = obj.get(method) {
1896 return Ok(value.to_string());
1897 }
1898
1899 let capitalized_method = Self::capitalize_first_letter(method);
1901 if let Some(value) = obj.get(&capitalized_method) {
1902 return Ok(value.to_string());
1903 }
1904 }
1905
1906 Ok(format!(
1908 "Called {}.{} with {} args",
1909 object_name, method, arg_count
1910 ))
1911 }
1912
1913 fn extract_property_name_from_setter(method: &str) -> String {
1915 let property_name = &method[3..]; Self::capitalize_first_letter(property_name)
1917 }
1918
1919 fn extract_property_name_from_getter(method: &str) -> String {
1921 let property_name = &method[3..]; Self::capitalize_first_letter(property_name)
1923 }
1924
1925 fn capitalize_first_letter(s: &str) -> String {
1927 if s.is_empty() {
1928 return String::new();
1929 }
1930 let mut chars = s.chars();
1931 match chars.next() {
1932 None => String::new(),
1933 Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
1934 }
1935 }
1936
1937 fn resolve_action_parameters(
1939 &self,
1940 params: &HashMap<String, Value>,
1941 facts: &Facts,
1942 ) -> Result<HashMap<String, Value>> {
1943 let mut resolved = HashMap::new();
1944
1945 for (key, value) in params {
1946 let resolved_value = match value {
1947 Value::String(s) => {
1948 if s.contains('.') {
1950 if let Some(fact_value) = facts.get_nested(s) {
1952 fact_value
1953 } else {
1954 value.clone()
1956 }
1957 } else {
1958 value.clone()
1959 }
1960 }
1961 _ => value.clone(),
1962 };
1963 resolved.insert(key.clone(), resolved_value);
1964 }
1965
1966 Ok(resolved)
1967 }
1968
1969 pub fn load_plugin(
1973 &mut self,
1974 plugin: std::sync::Arc<dyn crate::engine::plugin::RulePlugin>,
1975 ) -> Result<()> {
1976 plugin.register_actions(self)?;
1978 plugin.register_functions(self)?;
1979
1980 self.plugin_manager.load_plugin(plugin)
1982 }
1983
1984 pub fn unload_plugin(&mut self, name: &str) -> Result<()> {
1986 self.plugin_manager.unload_plugin(name)
1987 }
1988
1989 pub fn hot_reload_plugin(
1991 &mut self,
1992 name: &str,
1993 new_plugin: std::sync::Arc<dyn crate::engine::plugin::RulePlugin>,
1994 ) -> Result<()> {
1995 self.plugin_manager.unload_plugin(name)?;
1997
1998 new_plugin.register_actions(self)?;
2000 new_plugin.register_functions(self)?;
2001
2002 self.plugin_manager.load_plugin(new_plugin)
2004 }
2005
2006 pub fn get_plugin_info(&self, name: &str) -> Option<&crate::engine::plugin::PluginMetadata> {
2008 self.plugin_manager.get_plugin_info(name)
2009 }
2010
2011 pub fn list_plugins(&self) -> Vec<PluginInfo> {
2013 self.plugin_manager.list_plugins()
2014 }
2015
2016 pub fn get_plugin_stats(&self) -> PluginStats {
2018 self.plugin_manager.get_stats()
2019 }
2020
2021 pub fn plugin_health_check(&mut self) -> HashMap<String, crate::engine::plugin::PluginHealth> {
2023 self.plugin_manager.plugin_health_check()
2024 }
2025
2026 pub fn configure_plugins(&mut self, config: PluginConfig) {
2028 self.plugin_manager = PluginManager::new(config);
2029 }
2030}