use solverforge_core::domain::{PlanningSolution, SolutionDescriptor};
use super::Director;
pub struct RecordingDirector<'a, S: PlanningSolution, D: Director<S>> {
inner: &'a mut D,
undo_stack: Vec<Box<dyn FnOnce(&mut S) + Send>>,
modified_entities: Vec<(usize, usize)>,
}
impl<'a, S: PlanningSolution, D: Director<S>> RecordingDirector<'a, S, D> {
pub fn new(inner: &'a mut D) -> Self {
Self {
inner,
undo_stack: Vec::with_capacity(16),
modified_entities: Vec::with_capacity(8),
}
}
pub fn undo_changes(&mut self) {
for &(descriptor_idx, entity_idx) in &self.modified_entities {
self.inner
.before_variable_changed(descriptor_idx, entity_idx);
}
while let Some(undo) = self.undo_stack.pop() {
undo(self.inner.working_solution_mut());
}
for (descriptor_idx, entity_idx) in self.modified_entities.drain(..) {
self.inner
.after_variable_changed(descriptor_idx, entity_idx);
}
}
pub fn reset(&mut self) {
self.undo_stack.clear();
self.modified_entities.clear();
}
pub fn change_count(&self) -> usize {
self.undo_stack.len()
}
pub fn is_empty(&self) -> bool {
self.undo_stack.is_empty()
}
}
impl<S: PlanningSolution, D: Director<S>> Director<S> for RecordingDirector<'_, S, D> {
fn working_solution(&self) -> &S {
self.inner.working_solution()
}
fn working_solution_mut(&mut self) -> &mut S {
self.inner.working_solution_mut()
}
fn calculate_score(&mut self) -> S::Score {
self.inner.calculate_score()
}
fn solution_descriptor(&self) -> &SolutionDescriptor {
self.inner.solution_descriptor()
}
fn clone_working_solution(&self) -> S {
self.inner.clone_working_solution()
}
fn before_variable_changed(&mut self, descriptor_index: usize, entity_index: usize) {
self.inner
.before_variable_changed(descriptor_index, entity_index);
}
fn after_variable_changed(&mut self, descriptor_index: usize, entity_index: usize) {
self.inner
.after_variable_changed(descriptor_index, entity_index);
let key = (descriptor_index, entity_index);
if !self.modified_entities.contains(&key) {
self.modified_entities.push(key);
}
}
fn entity_count(&self, descriptor_index: usize) -> Option<usize> {
self.inner.entity_count(descriptor_index)
}
fn total_entity_count(&self) -> Option<usize> {
self.inner.total_entity_count()
}
fn is_incremental(&self) -> bool {
self.inner.is_incremental()
}
fn reset(&mut self) {
self.inner.reset();
self.undo_stack.clear();
self.modified_entities.clear();
}
fn register_undo(&mut self, undo: Box<dyn FnOnce(&mut S) + Send>) {
self.undo_stack.push(undo);
}
}