use std::sync::Arc;
use im::HashMap;
use serde_json::Value;
use moduforge_model::{
error::PoolError,
mark::Mark,
node::Node,
node_pool::{NodePool, NodePoolInner},
types::NodeId,
};
use crate::step::StepResult;
use super::patch::Patch;
#[derive(Debug, Clone)]
pub struct Draft {
pub base: Arc<NodePool>,
pub inner: NodePoolInner,
pub patches: im::Vector<Patch>,
pub current_path: im::Vector<String>,
pub skip_record: bool,
pub begin: bool,
}
impl Draft {
pub fn new(base: Arc<NodePool>) -> Self {
Draft {
inner: base.inner.as_ref().clone(),
base,
patches: im::Vector::new(),
current_path: im::Vector::new(),
skip_record: false,
begin: false,
}
}
pub fn enter_map(
&mut self,
key: &str,
) -> &mut Self {
self.current_path.push_back(key.to_string());
self
}
pub fn enter_list(
&mut self,
index: usize,
) -> &mut Self {
self.current_path.push_back(index.to_string());
self
}
pub fn exit(&mut self) -> &mut Self {
if !self.current_path.is_empty() {
self.current_path =
self.current_path.take(self.current_path.len() - 1);
}
self
}
pub fn update_attr(
&mut self,
id: &NodeId,
new_values: HashMap<String, Value>,
) -> Result<(), PoolError> {
let node =
self.get_node(id).ok_or(PoolError::NodeNotFound(id.clone()))?;
let old_values = node.attrs.clone();
let mut new_node = node.as_ref().clone();
new_node.attrs = new_values.clone();
self.inner.nodes =
self.inner.nodes.update(id.clone(), Arc::new(new_node));
self.record_patch(Patch::UpdateAttr {
path: self.current_path.iter().cloned().collect(),
id: id.clone(),
old: old_values.into_iter().collect(),
new: new_values.into_iter().collect(),
});
Ok(())
}
pub fn remove_mark(
&mut self,
id: &NodeId,
mark: Mark,
) -> Result<(), PoolError> {
let mut node = self
.get_node(id)
.ok_or(PoolError::NodeNotFound(id.clone()))?
.as_ref()
.clone();
node.marks =
node.marks.iter().filter(|&m| !m.eq(&mark)).cloned().collect();
self.inner.nodes.insert(id.clone(), Arc::new(node));
self.record_patch(Patch::RemoveMark {
path: self.current_path.iter().cloned().collect(),
parent_id: id.clone(),
marks: vec![mark],
});
Ok(())
}
pub fn add_mark(
&mut self,
id: &NodeId,
marks: &Vec<Mark>,
) -> Result<(), PoolError> {
let mut node = self
.get_node(id)
.ok_or(PoolError::NodeNotFound(id.clone()))?
.as_ref()
.clone();
node.marks.extend(marks.clone());
self.inner.nodes.insert(id.clone(), Arc::new(node));
self.record_patch(Patch::AddMark {
path: self.current_path.iter().cloned().collect(),
node_id: id.clone(),
marks: marks.clone(),
});
Ok(())
}
pub fn sort_children<
F: FnMut(
&(NodeId, &Arc<Node>),
&(NodeId, &Arc<Node>),
) -> std::cmp::Ordering,
>(
&mut self,
parent_id: &NodeId,
compare: F,
) -> Result<(), PoolError> {
let parent = self
.get_node(parent_id)
.ok_or(PoolError::ParentNotFound(parent_id.clone()))?;
let children_ids = parent.content.clone();
if children_ids.is_empty() {
return Ok(()); }
let mut children: Vec<(NodeId, &Arc<Node>)> = Vec::new();
for child_id in &children_ids {
if let Some(node) = self.get_node(child_id) {
children.push((child_id.clone(), node));
}
}
children.sort_by(compare);
let sorted_children: im::Vector<NodeId> =
children.into_iter().map(|(id, _)| id).collect();
let mut new_parent = parent.as_ref().clone();
new_parent.content = sorted_children.clone();
self.record_patch(Patch::SortChildren {
path: self.current_path.iter().cloned().collect(),
parent_id: parent_id.clone(),
old_children: children_ids.iter().cloned().collect(),
new_children: sorted_children.iter().cloned().collect(),
});
self.inner.nodes.insert(parent_id.clone(), Arc::new(new_parent));
Ok(())
}
pub fn add_node(
&mut self,
parent_id: &NodeId,
nodes: &Vec<Node>,
) -> Result<(), PoolError> {
let parent = self
.get_node(parent_id)
.ok_or(PoolError::ParentNotFound(parent_id.clone()))?;
let mut new_parent = parent.as_ref().clone();
new_parent.content.push_back(nodes[0].id.clone());
self.inner.nodes.insert(parent_id.clone(), Arc::new(new_parent));
self.inner.parent_map.insert(nodes[0].id.clone(), parent_id.clone());
let mut new_nodes = vec![];
for node in nodes.into_iter() {
new_nodes.push(node.clone());
for child_id in &node.content {
self.inner.parent_map.insert(child_id.clone(), node.id.clone());
}
self.inner.nodes.insert(node.id.clone(), Arc::new(node.clone()));
}
self.record_patch(Patch::AddNode {
path: self.current_path.iter().cloned().collect(),
parent_id: parent_id.clone(),
nodes: new_nodes,
});
Ok(())
}
pub fn replace_node(
&mut self,
node_id: NodeId,
nodes: &Vec<Node>,
) -> Result<(), PoolError> {
let old_node = self
.get_node(&node_id)
.ok_or(PoolError::NodeNotFound(node_id.clone()))?;
if nodes[0].id != node_id {
return Err(PoolError::InvalidNodeId {
nodeid: node_id,
new_node_id: nodes[0].id.clone(),
});
}
let _ = self.remove_node(
&node_id,
old_node.content.iter().map(|id| id.clone()).collect(),
)?;
let _ = self.add_node(&node_id, nodes)?;
Ok(())
}
pub fn move_node(
&mut self,
source_parent_id: &NodeId,
target_parent_id: &NodeId,
node_id: &NodeId,
position: Option<usize>,
) -> Result<(), PoolError> {
let source_parent = self
.get_node(source_parent_id)
.ok_or(PoolError::ParentNotFound(source_parent_id.clone()))?;
let target_parent = self
.get_node(target_parent_id)
.ok_or(PoolError::ParentNotFound(target_parent_id.clone()))?;
let _node = self
.get_node(node_id)
.ok_or(PoolError::NodeNotFound(node_id.clone()))?;
if !source_parent.content.contains(node_id) {
return Err(PoolError::InvalidParenting {
child: node_id.clone(),
alleged_parent: source_parent_id.clone(),
});
}
let mut new_source_parent = source_parent.as_ref().clone();
new_source_parent.content = new_source_parent
.content
.iter()
.filter(|&id| id != node_id)
.cloned()
.collect();
let mut new_target_parent = target_parent.as_ref().clone();
if let Some(pos) = position {
if pos <= new_target_parent.content.len() {
let mut new_content = im::Vector::new();
for (i, child_id) in
new_target_parent.content.iter().enumerate()
{
if i == pos {
new_content.push_back(node_id.clone());
}
new_content.push_back(child_id.clone());
}
if pos == new_target_parent.content.len() {
new_content.push_back(node_id.clone());
}
new_target_parent.content = new_content;
} else {
new_target_parent.content.push_back(node_id.clone());
}
} else {
new_target_parent.content.push_back(node_id.clone());
}
self.inner
.nodes
.insert(source_parent_id.clone(), Arc::new(new_source_parent));
self.inner
.nodes
.insert(target_parent_id.clone(), Arc::new(new_target_parent));
self.inner.parent_map.insert(node_id.clone(), target_parent_id.clone());
self.record_patch(Patch::MoveNode {
path: self.current_path.iter().cloned().collect(),
node_id: node_id.clone(),
source_parent_id: source_parent_id.clone(),
target_parent_id: target_parent_id.clone(),
position,
});
Ok(())
}
pub fn get_node(
&self,
id: &NodeId,
) -> Option<&Arc<Node>> {
self.inner.nodes.get(id)
}
pub fn children(
&self,
parent_id: &NodeId,
) -> Option<&im::Vector<NodeId>> {
self.get_node(parent_id).map(|n| &n.content)
}
pub fn remove_node(
&mut self,
parent_id: &NodeId,
nodes: Vec<NodeId>,
) -> Result<(), PoolError> {
let parent = self
.get_node(parent_id)
.ok_or(PoolError::ParentNotFound(parent_id.clone()))?;
if nodes.contains(&self.inner.root_id) {
return Err(PoolError::CannotRemoveRoot);
}
for node_id in &nodes {
if !parent.content.contains(node_id) {
return Err(PoolError::InvalidParenting {
child: node_id.clone(),
alleged_parent: parent_id.clone(),
});
}
}
let nodes_to_remove: std::collections::HashSet<_> =
nodes.iter().collect();
let filtered_children: im::Vector<NodeId> = parent
.as_ref()
.content
.iter()
.filter(|&id| !nodes_to_remove.contains(id))
.cloned()
.collect();
let mut parent_node = parent.as_ref().clone();
parent_node.content = filtered_children;
self.inner.nodes.insert(parent_id.clone(), Arc::new(parent_node));
let mut remove_nodes = Vec::new();
for node_id in nodes {
self.remove_subtree(&node_id, &mut remove_nodes)?;
}
self.record_patch(Patch::RemoveNode {
path: self.current_path.iter().cloned().collect(),
parent_id: parent_id.clone(),
nodes: remove_nodes,
});
Ok(())
}
fn remove_subtree(
&mut self,
node_id: &NodeId,
remove_nodes: &mut Vec<Node>,
) -> Result<(), PoolError> {
if node_id == &self.inner.root_id {
return Err(PoolError::CannotRemoveRoot);
}
let _ = self
.get_node(node_id)
.ok_or(PoolError::NodeNotFound(node_id.clone()))?;
if let Some(children) = self.children(node_id).cloned() {
for child_id in children {
self.remove_subtree(&child_id, remove_nodes)?;
}
}
self.inner.parent_map.remove(node_id);
if let Some(remove_node) = self.inner.nodes.remove(node_id) {
remove_nodes.push(remove_node.as_ref().clone());
}
Ok(())
}
pub fn apply_patches(
&mut self,
patches: &Vec<Patch>,
) -> Result<(), PoolError> {
self.skip_record = true;
for patch in patches {
match patch {
Patch::UpdateAttr { path: _, id, old: _, new } => {
self.update_attr(id, new.clone().into())?;
},
Patch::AddNode { path: _, parent_id, nodes } => {
self.add_node(parent_id, nodes)?;
},
Patch::AddMark { path: _, node_id, marks } => {
self.add_mark(node_id, marks)?;
},
Patch::RemoveNode { path: _, parent_id, nodes } => {
self.remove_node(
parent_id,
nodes.iter().map(|n| n.id.clone()).collect(),
)?;
},
Patch::RemoveMark { path: _, parent_id, marks } => {
for mark in marks {
self.remove_mark(&parent_id, mark.clone())?;
}
},
Patch::MoveNode {
path: _,
node_id,
source_parent_id,
target_parent_id,
position,
} => {
self.move_node(
source_parent_id,
target_parent_id,
node_id,
position.clone(),
)?;
},
Patch::SortChildren {
path: _,
parent_id,
old_children: _,
new_children,
} => {
let parent = self
.get_node(parent_id)
.ok_or(PoolError::ParentNotFound(parent_id.clone()))?;
let mut new_parent = parent.as_ref().clone();
new_parent.content = new_children.iter().cloned().collect();
self.inner
.nodes
.insert(parent_id.clone(), Arc::new(new_parent));
},
}
}
self.skip_record = false;
Ok(())
}
pub fn reverse_patches(
&mut self,
patches: Vec<Patch>,
) -> Result<(), PoolError> {
self.skip_record = true;
for patch in patches {
match patch {
Patch::UpdateAttr { path: _, id, old, new: _ } => {
self.update_attr(&id, old.clone().into())?;
},
Patch::AddNode { path: _, parent_id, nodes } => {
self.remove_node(
&parent_id,
nodes.iter().map(|f| f.id.clone()).collect(),
)?;
},
Patch::AddMark { path: _, node_id, marks } => {
self.remove_mark(&node_id, marks[0].clone())?;
},
Patch::RemoveNode { path: _, parent_id, nodes } => {
self.add_node(&parent_id, &nodes)?;
},
Patch::RemoveMark { path: _, parent_id, marks } => {
self.add_mark(&parent_id, &marks)?;
},
Patch::MoveNode {
path: _,
node_id,
source_parent_id,
target_parent_id,
position,
} => {
self.move_node(
&target_parent_id,
&source_parent_id,
&node_id,
position.clone(),
)?;
},
Patch::SortChildren {
path: _,
parent_id,
old_children,
new_children: _,
} => {
let parent = self
.get_node(&parent_id)
.ok_or(PoolError::ParentNotFound(parent_id.clone()))?;
let mut new_parent = parent.as_ref().clone();
new_parent.content = old_children.iter().cloned().collect();
self.inner
.nodes
.insert(parent_id.clone(), Arc::new(new_parent));
},
}
}
self.skip_record = false;
Ok(())
}
fn record_patch(
&mut self,
patch: Patch,
) {
if !self.skip_record {
self.patches.push_back(patch);
}
}
pub fn commit(&self) -> StepResult {
match self.begin {
true => StepResult {
doc: None,
failed: Some("事务操作".to_string()),
patches: Vec::new(),
},
false => {
let new_pool = NodePool { inner: Arc::new(self.inner.clone()) };
StepResult::ok(
Arc::new(new_pool),
self.patches.iter().cloned().collect(),
)
},
}
}
}