use crate::{history_manager::HistoryManager, metrics, types::HistoryEntryWithMeta};
use mf_state::{state::State, Transaction};
use std::sync::Arc;
#[derive(Debug, Clone)]
pub struct HistoryOperationResult {
pub old_state: Arc<State>,
pub new_state: Arc<State>,
pub transactions: Vec<Arc<Transaction>>,
}
pub struct HistoryHelper;
impl HistoryHelper {
pub fn undo(
history_manager: &mut HistoryManager<HistoryEntryWithMeta>,
current_state: Arc<State>,
) -> Option<HistoryOperationResult> {
if !history_manager.can_undo() {
return None;
}
let old_entry = history_manager.get_present();
let old_state = current_state;
let transactions = old_entry.transactions.clone();
history_manager.jump(-1);
let new_entry = history_manager.get_present();
let new_state = new_entry.state.clone();
metrics::history_operation("undo");
Some(HistoryOperationResult { old_state, new_state, transactions })
}
pub fn redo(
history_manager: &mut HistoryManager<HistoryEntryWithMeta>,
current_state: Arc<State>,
) -> Option<HistoryOperationResult> {
if !history_manager.can_redo() {
return None;
}
let old_state = current_state;
history_manager.jump(1);
let new_entry = history_manager.get_present();
let new_state = new_entry.state.clone();
let transactions = new_entry.transactions.clone();
metrics::history_operation("redo");
Some(HistoryOperationResult { old_state, new_state, transactions })
}
pub fn jump(
history_manager: &mut HistoryManager<HistoryEntryWithMeta>,
current_state: Arc<State>,
steps: isize,
) -> Option<HistoryOperationResult> {
if steps == 0 {
return None;
}
let old_state = current_state;
let history = history_manager.get_history();
let current_index = history.past.len();
let mut transactions = Vec::new();
if steps < 0 {
let abs_steps = (-steps) as usize;
let start_index = current_index.saturating_sub(abs_steps);
for i in (start_index..current_index).rev() {
if let Some(entry) = history.past.get(i) {
transactions.extend(entry.transactions.clone());
}
}
} else {
let steps = steps as usize;
for i in 0..steps.min(history.future.len()) {
if let Some(entry) = history.future.get(i) {
transactions.extend(entry.transactions.clone());
}
}
}
history_manager.jump(steps);
let new_entry = history_manager.get_present();
let new_state = new_entry.state.clone();
metrics::history_operation("jump");
Some(HistoryOperationResult { old_state, new_state, transactions })
}
pub fn insert(
history_manager: &mut HistoryManager<HistoryEntryWithMeta>,
state: Arc<State>,
transactions: Vec<Arc<Transaction>>,
description: String,
meta: serde_json::Value,
) {
if transactions.is_empty() {
return;
}
let entry = if transactions.len() == 1 {
HistoryEntryWithMeta::new(
transactions[0].clone(),
state,
description,
meta,
)
} else {
HistoryEntryWithMeta::new_batch(
transactions,
state,
description,
meta,
)
};
history_manager.insert(entry);
}
}