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 ActionType::Append { field, value } => {
1317 let evaluated_value = match value {
1319 Value::Expression(expr) => crate::expression::evaluate_expression(expr, facts)?,
1320 _ => value.clone(),
1321 };
1322
1323 let current_value = facts.get(field);
1325 let mut array = match current_value {
1326 Some(Value::Array(arr)) => arr.clone(),
1327 Some(_) => {
1328 if self.config.debug_mode {
1330 println!(" ⚠️ Field {} is not an array, creating new array", field);
1331 }
1332 Vec::new()
1333 }
1334 None => Vec::new(),
1335 };
1336
1337 array.push(evaluated_value.clone());
1339
1340 if facts
1342 .set_nested(field, Value::Array(array.clone()))
1343 .is_err()
1344 {
1345 facts.set(field, Value::Array(array.clone()));
1346 }
1347
1348 if self.config.debug_mode {
1349 println!(" ➕ Appended to {}: {:?}", field, evaluated_value);
1350 }
1351 }
1352 }
1353 Ok(())
1354 }
1355
1356 fn evaluate_arithmetic_condition(&self, expr: &str, facts: &Facts) -> Result<bool> {
1358 let operators = [">=", "<=", "==", "!=", ">", "<"];
1362 let mut split_pos = None;
1363 let mut found_op = "";
1364
1365 for op in &operators {
1366 if let Some(pos) = expr.rfind(op) {
1367 split_pos = Some(pos);
1368 found_op = op;
1369 break;
1370 }
1371 }
1372
1373 if split_pos.is_none() {
1374 return Err(RuleEngineError::EvaluationError {
1375 message: format!("No comparison operator found in expression: {}", expr),
1376 });
1377 }
1378
1379 let pos = split_pos.unwrap();
1380 let left_expr = expr[..pos].trim();
1381 let right_value = expr[pos + found_op.len()..].trim();
1382
1383 let left_result = crate::expression::evaluate_expression(left_expr, facts)?;
1385
1386 let right_val = if let Ok(i) = right_value.parse::<i64>() {
1388 Value::Integer(i)
1389 } else if let Ok(f) = right_value.parse::<f64>() {
1390 Value::Number(f)
1391 } else {
1392 match crate::expression::evaluate_expression(right_value, facts) {
1394 Ok(v) => v,
1395 Err(_) => Value::String(right_value.to_string()),
1396 }
1397 };
1398
1399 let operator =
1401 Operator::from_str(found_op).ok_or_else(|| RuleEngineError::InvalidOperator {
1402 operator: found_op.to_string(),
1403 })?;
1404
1405 Ok(operator.evaluate(&left_result, &right_val))
1406 }
1407
1408 fn execute_function_call(
1410 &self,
1411 function: &str,
1412 args: &[Value],
1413 facts: &Facts,
1414 ) -> Result<String> {
1415 let function_lower = function.to_lowercase();
1416
1417 match function_lower.as_str() {
1419 "log" | "print" | "println" => self.handle_log_function(args),
1420 "update" | "refresh" => self.handle_update_function(args),
1421 "now" | "timestamp" => self.handle_timestamp_function(),
1422 "random" => self.handle_random_function(args),
1423 "format" | "sprintf" => self.handle_format_function(args),
1424 "length" | "size" | "count" => self.handle_length_function(args),
1425 "sum" | "add" => self.handle_sum_function(args),
1426 "max" | "maximum" => self.handle_max_function(args),
1427 "min" | "minimum" => self.handle_min_function(args),
1428 "avg" | "average" => self.handle_average_function(args),
1429 "round" => self.handle_round_function(args),
1430 "floor" => self.handle_floor_function(args),
1431 "ceil" | "ceiling" => self.handle_ceil_function(args),
1432 "abs" | "absolute" => self.handle_abs_function(args),
1433 "contains" | "includes" => self.handle_contains_function(args),
1434 "startswith" | "begins_with" => self.handle_starts_with_function(args),
1435 "endswith" | "ends_with" => self.handle_ends_with_function(args),
1436 "lowercase" | "tolower" => self.handle_lowercase_function(args),
1437 "uppercase" | "toupper" => self.handle_uppercase_function(args),
1438 "trim" | "strip" => self.handle_trim_function(args),
1439 "split" => self.handle_split_function(args),
1440 "join" => self.handle_join_function(args),
1441 _ => {
1442 self.handle_custom_function(function, args, facts)
1444 }
1445 }
1446 }
1447
1448 fn handle_log_function(&self, args: &[Value]) -> Result<String> {
1450 let message = if args.is_empty() {
1451 "".to_string()
1452 } else if args.len() == 1 {
1453 args[0].to_string()
1454 } else {
1455 args.iter()
1456 .map(|v| v.to_string())
1457 .collect::<Vec<_>>()
1458 .join(" ")
1459 };
1460
1461 info!("📋 {}", message);
1462 Ok(message)
1463 }
1464
1465 fn handle_update_function(&self, args: &[Value]) -> Result<String> {
1467 if let Some(arg) = args.first() {
1468 Ok(format!("Updated: {}", arg.to_string()))
1469 } else {
1470 Ok("Updated".to_string())
1471 }
1472 }
1473
1474 fn handle_timestamp_function(&self) -> Result<String> {
1476 use std::time::{SystemTime, UNIX_EPOCH};
1477 let timestamp = SystemTime::now()
1478 .duration_since(UNIX_EPOCH)
1479 .map_err(|e| RuleEngineError::EvaluationError {
1480 message: format!("Failed to get timestamp: {}", e),
1481 })?
1482 .as_secs();
1483 Ok(timestamp.to_string())
1484 }
1485
1486 fn handle_random_function(&self, args: &[Value]) -> Result<String> {
1488 use std::collections::hash_map::DefaultHasher;
1489 use std::hash::{Hash, Hasher};
1490
1491 let mut hasher = DefaultHasher::new();
1493 std::time::SystemTime::now().hash(&mut hasher);
1494 let random_value = hasher.finish();
1495
1496 if args.is_empty() {
1497 Ok((random_value % 100).to_string()) } else if let Some(Value::Number(max)) = args.first() {
1499 let max_val = *max as u64;
1500 Ok((random_value % max_val).to_string())
1501 } else {
1502 Ok(random_value.to_string())
1503 }
1504 }
1505
1506 fn handle_format_function(&self, args: &[Value]) -> Result<String> {
1508 if args.is_empty() {
1509 return Ok("".to_string());
1510 }
1511
1512 let template = args[0].to_string();
1513 let values: Vec<String> = args[1..].iter().map(|v| v.to_string()).collect();
1514
1515 let mut result = template;
1517 for (i, value) in values.iter().enumerate() {
1518 result = result.replace(&format!("{{{}}}", i), value);
1519 }
1520
1521 Ok(result)
1522 }
1523
1524 fn handle_length_function(&self, args: &[Value]) -> Result<String> {
1526 if let Some(arg) = args.first() {
1527 match arg {
1528 Value::String(s) => Ok(s.len().to_string()),
1529 Value::Array(arr) => Ok(arr.len().to_string()),
1530 Value::Object(obj) => Ok(obj.len().to_string()),
1531 _ => Ok("1".to_string()), }
1533 } else {
1534 Ok("0".to_string())
1535 }
1536 }
1537
1538 fn handle_sum_function(&self, args: &[Value]) -> Result<String> {
1540 let sum = args.iter().fold(0.0, |acc, val| match val {
1541 Value::Number(n) => acc + n,
1542 Value::Integer(i) => acc + (*i as f64),
1543 _ => acc,
1544 });
1545 Ok(sum.to_string())
1546 }
1547
1548 fn handle_max_function(&self, args: &[Value]) -> Result<String> {
1550 let max = args.iter().fold(f64::NEG_INFINITY, |acc, val| match val {
1551 Value::Number(n) => acc.max(*n),
1552 Value::Integer(i) => acc.max(*i as f64),
1553 _ => acc,
1554 });
1555 Ok(max.to_string())
1556 }
1557
1558 fn handle_min_function(&self, args: &[Value]) -> Result<String> {
1560 let min = args.iter().fold(f64::INFINITY, |acc, val| match val {
1561 Value::Number(n) => acc.min(*n),
1562 Value::Integer(i) => acc.min(*i as f64),
1563 _ => acc,
1564 });
1565 Ok(min.to_string())
1566 }
1567
1568 fn handle_average_function(&self, args: &[Value]) -> Result<String> {
1570 if args.is_empty() {
1571 return Ok("0".to_string());
1572 }
1573
1574 let (sum, count) = args.iter().fold((0.0, 0), |(sum, count), val| match val {
1575 Value::Number(n) => (sum + n, count + 1),
1576 Value::Integer(i) => (sum + (*i as f64), count + 1),
1577 _ => (sum, count),
1578 });
1579
1580 if count > 0 {
1581 Ok((sum / count as f64).to_string())
1582 } else {
1583 Ok("0".to_string())
1584 }
1585 }
1586
1587 fn handle_round_function(&self, args: &[Value]) -> Result<String> {
1589 if let Some(Value::Number(n)) = args.first() {
1590 Ok(n.round().to_string())
1591 } else if let Some(Value::Integer(i)) = args.first() {
1592 Ok(i.to_string())
1593 } else {
1594 Err(RuleEngineError::EvaluationError {
1595 message: "round() requires a numeric argument".to_string(),
1596 })
1597 }
1598 }
1599
1600 fn handle_floor_function(&self, args: &[Value]) -> Result<String> {
1601 if let Some(Value::Number(n)) = args.first() {
1602 Ok(n.floor().to_string())
1603 } else if let Some(Value::Integer(i)) = args.first() {
1604 Ok(i.to_string())
1605 } else {
1606 Err(RuleEngineError::EvaluationError {
1607 message: "floor() requires a numeric argument".to_string(),
1608 })
1609 }
1610 }
1611
1612 fn handle_ceil_function(&self, args: &[Value]) -> Result<String> {
1613 if let Some(Value::Number(n)) = args.first() {
1614 Ok(n.ceil().to_string())
1615 } else if let Some(Value::Integer(i)) = args.first() {
1616 Ok(i.to_string())
1617 } else {
1618 Err(RuleEngineError::EvaluationError {
1619 message: "ceil() requires a numeric argument".to_string(),
1620 })
1621 }
1622 }
1623
1624 fn handle_abs_function(&self, args: &[Value]) -> Result<String> {
1625 if let Some(Value::Number(n)) = args.first() {
1626 Ok(n.abs().to_string())
1627 } else if let Some(Value::Integer(i)) = args.first() {
1628 Ok(i.abs().to_string())
1629 } else {
1630 Err(RuleEngineError::EvaluationError {
1631 message: "abs() requires a numeric argument".to_string(),
1632 })
1633 }
1634 }
1635
1636 fn handle_contains_function(&self, args: &[Value]) -> Result<String> {
1638 if args.len() >= 2 {
1639 let haystack = args[0].to_string();
1640 let needle = args[1].to_string();
1641 Ok(haystack.contains(&needle).to_string())
1642 } else {
1643 Err(RuleEngineError::EvaluationError {
1644 message: "contains() requires 2 arguments".to_string(),
1645 })
1646 }
1647 }
1648
1649 fn handle_starts_with_function(&self, args: &[Value]) -> Result<String> {
1650 if args.len() >= 2 {
1651 let text = args[0].to_string();
1652 let prefix = args[1].to_string();
1653 Ok(text.starts_with(&prefix).to_string())
1654 } else {
1655 Err(RuleEngineError::EvaluationError {
1656 message: "startswith() requires 2 arguments".to_string(),
1657 })
1658 }
1659 }
1660
1661 fn handle_ends_with_function(&self, args: &[Value]) -> Result<String> {
1662 if args.len() >= 2 {
1663 let text = args[0].to_string();
1664 let suffix = args[1].to_string();
1665 Ok(text.ends_with(&suffix).to_string())
1666 } else {
1667 Err(RuleEngineError::EvaluationError {
1668 message: "endswith() requires 2 arguments".to_string(),
1669 })
1670 }
1671 }
1672
1673 fn handle_lowercase_function(&self, args: &[Value]) -> Result<String> {
1674 if let Some(arg) = args.first() {
1675 Ok(arg.to_string().to_lowercase())
1676 } else {
1677 Err(RuleEngineError::EvaluationError {
1678 message: "lowercase() requires 1 argument".to_string(),
1679 })
1680 }
1681 }
1682
1683 fn handle_uppercase_function(&self, args: &[Value]) -> Result<String> {
1684 if let Some(arg) = args.first() {
1685 Ok(arg.to_string().to_uppercase())
1686 } else {
1687 Err(RuleEngineError::EvaluationError {
1688 message: "uppercase() requires 1 argument".to_string(),
1689 })
1690 }
1691 }
1692
1693 fn handle_trim_function(&self, args: &[Value]) -> Result<String> {
1694 if let Some(arg) = args.first() {
1695 Ok(arg.to_string().trim().to_string())
1696 } else {
1697 Err(RuleEngineError::EvaluationError {
1698 message: "trim() requires 1 argument".to_string(),
1699 })
1700 }
1701 }
1702
1703 fn handle_split_function(&self, args: &[Value]) -> Result<String> {
1704 if args.len() >= 2 {
1705 let text = args[0].to_string();
1706 let delimiter = args[1].to_string();
1707 let parts: Vec<String> = text.split(&delimiter).map(|s| s.to_string()).collect();
1708 Ok(format!("{:?}", parts)) } else {
1710 Err(RuleEngineError::EvaluationError {
1711 message: "split() requires 2 arguments".to_string(),
1712 })
1713 }
1714 }
1715
1716 fn handle_join_function(&self, args: &[Value]) -> Result<String> {
1717 if args.len() >= 2 {
1718 let delimiter = args[0].to_string();
1719 let parts: Vec<String> = args[1..].iter().map(|v| v.to_string()).collect();
1720 Ok(parts.join(&delimiter))
1721 } else {
1722 Err(RuleEngineError::EvaluationError {
1723 message: "join() requires at least 2 arguments".to_string(),
1724 })
1725 }
1726 }
1727
1728 fn handle_custom_function(
1730 &self,
1731 function: &str,
1732 args: &[Value],
1733 facts: &Facts,
1734 ) -> Result<String> {
1735 if let Some(custom_func) = self.custom_functions.get(function) {
1737 if self.config.debug_mode {
1738 println!("🎯 Calling registered function: {}({:?})", function, args);
1739 }
1740
1741 match custom_func(args, facts) {
1742 Ok(result) => Ok(result.to_string()),
1743 Err(e) => Err(e),
1744 }
1745 } else {
1746 if self.config.debug_mode {
1748 println!("⚠️ Custom function '{}' not registered", function);
1749 }
1750
1751 Err(RuleEngineError::EvaluationError {
1752 message: format!("Function '{}' is not registered. Use engine.register_function() to add custom functions.", function),
1753 })
1754 }
1755 }
1756
1757 fn execute_method_call(
1759 &self,
1760 object_name: &str,
1761 method: &str,
1762 args: &[Value],
1763 facts: &Facts,
1764 ) -> Result<String> {
1765 let Some(object_value) = facts.get(object_name) else {
1767 return Err(RuleEngineError::EvaluationError {
1768 message: format!("Object '{}' not found in facts", object_name),
1769 });
1770 };
1771
1772 let method_lower = method.to_lowercase();
1773
1774 if method_lower.starts_with("set") && args.len() == 1 {
1776 return self.handle_setter_method(object_name, method, &args[0], object_value, facts);
1777 }
1778
1779 if method_lower.starts_with("get") && args.is_empty() {
1781 return self.handle_getter_method(object_name, method, &object_value);
1782 }
1783
1784 match method_lower.as_str() {
1786 "tostring" => Ok(object_value.to_string()),
1787 "update" => {
1788 facts.add_value(object_name, object_value)?;
1789 Ok(format!("Updated {}", object_name))
1790 }
1791 "reset" => self.handle_reset_method(object_name, object_value, facts),
1792 _ => self.handle_property_access_or_fallback(
1793 object_name,
1794 method,
1795 args.len(),
1796 &object_value,
1797 ),
1798 }
1799 }
1800
1801 fn handle_setter_method(
1803 &self,
1804 object_name: &str,
1805 method: &str,
1806 new_value: &Value,
1807 mut object_value: Value,
1808 facts: &Facts,
1809 ) -> Result<String> {
1810 let property_name = Self::extract_property_name_from_setter(method);
1811
1812 match object_value {
1813 Value::Object(ref mut obj) => {
1814 obj.insert(property_name.clone(), new_value.clone());
1815 facts.add_value(object_name, object_value)?;
1816 Ok(format!(
1817 "Set {} to {}",
1818 property_name,
1819 new_value.to_string()
1820 ))
1821 }
1822 _ => Err(RuleEngineError::EvaluationError {
1823 message: format!("Cannot call setter on non-object type: {}", object_name),
1824 }),
1825 }
1826 }
1827
1828 fn handle_getter_method(
1830 &self,
1831 object_name: &str,
1832 method: &str,
1833 object_value: &Value,
1834 ) -> Result<String> {
1835 let property_name = Self::extract_property_name_from_getter(method);
1836
1837 match object_value {
1838 Value::Object(obj) => {
1839 if let Some(value) = obj.get(&property_name) {
1840 Ok(value.to_string())
1841 } else {
1842 Err(RuleEngineError::EvaluationError {
1843 message: format!(
1844 "Property '{}' not found on object '{}'",
1845 property_name, object_name
1846 ),
1847 })
1848 }
1849 }
1850 _ => Err(RuleEngineError::EvaluationError {
1851 message: format!("Cannot call getter on non-object type: {}", object_name),
1852 }),
1853 }
1854 }
1855
1856 fn handle_reset_method(
1858 &self,
1859 object_name: &str,
1860 mut object_value: Value,
1861 facts: &Facts,
1862 ) -> Result<String> {
1863 match object_value {
1864 Value::Object(ref mut obj) => {
1865 obj.clear();
1866 facts.add_value(object_name, object_value)?;
1867 Ok(format!("Reset {}", object_name))
1868 }
1869 _ => Err(RuleEngineError::EvaluationError {
1870 message: format!("Cannot reset non-object type: {}", object_name),
1871 }),
1872 }
1873 }
1874
1875 fn handle_property_access_or_fallback(
1877 &self,
1878 object_name: &str,
1879 method: &str,
1880 arg_count: usize,
1881 object_value: &Value,
1882 ) -> Result<String> {
1883 if let Value::Object(obj) = object_value {
1884 if let Some(value) = obj.get(method) {
1886 return Ok(value.to_string());
1887 }
1888
1889 let capitalized_method = Self::capitalize_first_letter(method);
1891 if let Some(value) = obj.get(&capitalized_method) {
1892 return Ok(value.to_string());
1893 }
1894 }
1895
1896 Ok(format!(
1898 "Called {}.{} with {} args",
1899 object_name, method, arg_count
1900 ))
1901 }
1902
1903 fn extract_property_name_from_setter(method: &str) -> String {
1905 let property_name = &method[3..]; Self::capitalize_first_letter(property_name)
1907 }
1908
1909 fn extract_property_name_from_getter(method: &str) -> String {
1911 let property_name = &method[3..]; Self::capitalize_first_letter(property_name)
1913 }
1914
1915 fn capitalize_first_letter(s: &str) -> String {
1917 if s.is_empty() {
1918 return String::new();
1919 }
1920 let mut chars = s.chars();
1921 match chars.next() {
1922 None => String::new(),
1923 Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
1924 }
1925 }
1926
1927 fn resolve_action_parameters(
1929 &self,
1930 params: &HashMap<String, Value>,
1931 facts: &Facts,
1932 ) -> Result<HashMap<String, Value>> {
1933 let mut resolved = HashMap::new();
1934
1935 for (key, value) in params {
1936 let resolved_value = match value {
1937 Value::String(s) => {
1938 if s.contains('.') {
1940 if let Some(fact_value) = facts.get_nested(s) {
1942 fact_value
1943 } else {
1944 value.clone()
1946 }
1947 } else {
1948 value.clone()
1949 }
1950 }
1951 _ => value.clone(),
1952 };
1953 resolved.insert(key.clone(), resolved_value);
1954 }
1955
1956 Ok(resolved)
1957 }
1958
1959 pub fn load_plugin(
1963 &mut self,
1964 plugin: std::sync::Arc<dyn crate::engine::plugin::RulePlugin>,
1965 ) -> Result<()> {
1966 plugin.register_actions(self)?;
1968 plugin.register_functions(self)?;
1969
1970 self.plugin_manager.load_plugin(plugin)
1972 }
1973
1974 pub fn unload_plugin(&mut self, name: &str) -> Result<()> {
1976 self.plugin_manager.unload_plugin(name)
1977 }
1978
1979 pub fn hot_reload_plugin(
1981 &mut self,
1982 name: &str,
1983 new_plugin: std::sync::Arc<dyn crate::engine::plugin::RulePlugin>,
1984 ) -> Result<()> {
1985 self.plugin_manager.unload_plugin(name)?;
1987
1988 new_plugin.register_actions(self)?;
1990 new_plugin.register_functions(self)?;
1991
1992 self.plugin_manager.load_plugin(new_plugin)
1994 }
1995
1996 pub fn get_plugin_info(&self, name: &str) -> Option<&crate::engine::plugin::PluginMetadata> {
1998 self.plugin_manager.get_plugin_info(name)
1999 }
2000
2001 pub fn list_plugins(&self) -> Vec<PluginInfo> {
2003 self.plugin_manager.list_plugins()
2004 }
2005
2006 pub fn get_plugin_stats(&self) -> PluginStats {
2008 self.plugin_manager.get_stats()
2009 }
2010
2011 pub fn plugin_health_check(&mut self) -> HashMap<String, crate::engine::plugin::PluginHealth> {
2013 self.plugin_manager.plugin_health_check()
2014 }
2015
2016 pub fn configure_plugins(&mut self, config: PluginConfig) {
2018 self.plugin_manager = PluginManager::new(config);
2019 }
2020}