use crate::error::CrdfError;
use crate::graph::{RdfGraph, RdfOperation};
use crate::term::RdfTerm;
#[derive(Clone, Debug)]
enum ActionKind {
Add,
Remove,
}
#[derive(Clone, Debug)]
struct TripleAction {
kind: ActionKind,
subject: RdfTerm,
predicate: String,
object: RdfTerm,
}
impl TripleAction {
fn execute(&self, graph: &mut RdfGraph) -> Result<Option<RdfOperation>, CrdfError> {
match self.kind {
ActionKind::Add => {
if graph.contains_triple(&self.subject, &self.predicate, &self.object) {
return Ok(None);
}
let op = graph.add_triple(
self.subject.clone(),
self.predicate.clone(),
self.object.clone(),
)?;
Ok(Some(op))
}
ActionKind::Remove => {
if !graph.contains_triple(&self.subject, &self.predicate, &self.object) {
return Ok(None);
}
let op =
graph.remove_triple(&self.subject, &self.predicate, &self.object)?;
Ok(Some(op))
}
}
}
fn inverse(&self) -> Self {
Self {
kind: match self.kind {
ActionKind::Add => ActionKind::Remove,
ActionKind::Remove => ActionKind::Add,
},
subject: self.subject.clone(),
predicate: self.predicate.clone(),
object: self.object.clone(),
}
}
}
pub struct UndoManager {
undo_stack: Vec<TripleAction>,
redo_stack: Vec<TripleAction>,
}
impl Default for UndoManager {
fn default() -> Self {
Self::new()
}
}
impl UndoManager {
pub fn new() -> Self {
Self {
undo_stack: Vec::new(),
redo_stack: Vec::new(),
}
}
pub fn can_undo(&self) -> bool {
!self.undo_stack.is_empty()
}
pub fn can_redo(&self) -> bool {
!self.redo_stack.is_empty()
}
pub fn clear(&mut self) {
self.undo_stack.clear();
self.redo_stack.clear();
}
pub fn add_triple(
&mut self,
graph: &mut RdfGraph,
subject: RdfTerm,
predicate: impl Into<String>,
object: RdfTerm,
) -> Result<RdfOperation, CrdfError> {
let predicate = predicate.into();
let op = graph.add_triple(subject.clone(), predicate.clone(), object.clone())?;
self.undo_stack.push(TripleAction {
kind: ActionKind::Add,
subject,
predicate,
object,
});
self.redo_stack.clear();
Ok(op)
}
pub fn remove_triple(
&mut self,
graph: &mut RdfGraph,
subject: &RdfTerm,
predicate: &str,
object: &RdfTerm,
) -> Result<RdfOperation, CrdfError> {
let op = graph.remove_triple(subject, predicate, object)?;
self.undo_stack.push(TripleAction {
kind: ActionKind::Remove,
subject: subject.clone(),
predicate: predicate.to_owned(),
object: object.clone(),
});
self.redo_stack.clear();
Ok(op)
}
pub fn undo(
&mut self,
graph: &mut RdfGraph,
) -> Result<Option<RdfOperation>, CrdfError> {
let Some(action) = self.undo_stack.pop() else {
return Ok(None);
};
let inverse = action.inverse();
let result = inverse.execute(graph)?;
self.redo_stack.push(action);
Ok(result)
}
pub fn redo(
&mut self,
graph: &mut RdfGraph,
) -> Result<Option<RdfOperation>, CrdfError> {
let Some(action) = self.redo_stack.pop() else {
return Ok(None);
};
let result = action.execute(graph)?;
self.undo_stack.push(action);
Ok(result)
}
}