use crate::{
AggregateLogic, Causable, CausableCollectionAccessor, CausalityError, CausalityErrorEnum,
MonadicCausable, NumericalValue, StatefulMonadicCausable, monadic_collection_utils,
};
use deep_causality_core::{CausalEffect, PropagatingProcess};
use deep_causality_haft::LogAppend;
use std::fmt::Debug;
pub trait StatefulMonadicCausableCollection<I, O, S, C, T>:
CausableCollectionAccessor<I, O, T>
where
T: MonadicCausable<I, O> + StatefulMonadicCausable<I, O, S, C> + Causable,
I: Clone,
O: monadic_collection_utils::Aggregatable + Clone + Default + Send + Sync + 'static + Debug,
S: Clone + Default,
C: Clone,
{
fn evaluate_collection_stateful(
&self,
incoming: &PropagatingProcess<I, S, C>,
logic: &AggregateLogic,
threshold_value: Option<NumericalValue>,
) -> PropagatingProcess<O, S, C> {
let incoming_value = match incoming.outcome() {
Err(err) => {
return PropagatingProcess::new(
Err(err.clone()),
incoming.state().clone(),
incoming.context().clone(),
incoming.logs().clone(),
);
}
Ok(value) => value.clone(),
};
let items = self.get_all_items();
if items.is_empty() {
return PropagatingProcess::new(
Err(CausalityError(CausalityErrorEnum::Custom(
"Cannot evaluate an empty collection".to_string(),
))),
incoming.state().clone(),
incoming.context().clone(),
incoming.logs().clone(),
);
}
let mut acc_values: Vec<CausalEffect<O>> = Vec::with_capacity(items.len());
let mut acc_state: S = incoming.state().clone();
let mut acc_context: Option<C> = incoming.context().clone();
let mut acc_logs = incoming.logs().clone();
for item in items.into_iter() {
let item_in: PropagatingProcess<I, S, C> = PropagatingProcess::new(
Ok(incoming_value.clone()),
acc_state.clone(),
acc_context.clone(),
Default::default(),
);
let item_out = item.evaluate_stateful(&item_in);
let (item_outcome, item_state, item_context, item_logs) = item_out.into_parts();
let mut item_logs = item_logs;
acc_logs.append(&mut item_logs);
match item_outcome {
Err(err) => {
return PropagatingProcess::new(
Err(err),
acc_state,
acc_context,
acc_logs,
);
}
Ok(item_value) => {
acc_state = item_state;
acc_context = item_context;
acc_values.push(item_value);
}
}
}
match monadic_collection_utils::aggregate_effects(&acc_values, logic, threshold_value) {
Ok(aggregated_value) => {
PropagatingProcess::new(Ok(aggregated_value), acc_state, acc_context, acc_logs)
}
Err(e) => PropagatingProcess::new(Err(e), acc_state, acc_context, acc_logs),
}
}
}