1use std::sync::Arc;
2
3use moduforge_model::{
4    node_type::NodeEnum, schema::Schema, tree::Tree, types::NodeId,
5};
6
7use crate::transform_error;
8
9use super::{
10    step::{Step, StepResult},
11    TransformResult,
12};
13use serde::{Deserialize, Serialize};
14#[derive(Debug, Serialize, Deserialize, Clone)]
16pub struct AddNodeStep {
17    parent_id: NodeId,
18    nodes: Vec<NodeEnum>,
19}
20impl AddNodeStep {
21    pub fn new(parent_id: NodeId, nodes: Vec<NodeEnum>) -> Self {
22        AddNodeStep { parent_id, nodes }
23    }
24}
25impl Step for AddNodeStep {
26    fn name(&self) -> String {
27        "add_node_step".to_string()
28    }
29    fn apply(
30        &self,
31        dart: &mut Tree,
32        schema: Arc<Schema>,
33    ) -> TransformResult<StepResult> {
34        let _ = schema;
35        let result = dart.add(&self.parent_id, self.nodes.clone());
36        match result {
37            Ok(_) => Ok(StepResult::ok()),
38            Err(e) => Err(transform_error(e.to_string())),
39        }
40    }
41    fn serialize(&self) -> Option<Vec<u8>> {
42        serde_json::to_vec(self).ok()
43    }
44
45    fn invert(
46        &self,
47        _: &Arc<Tree>,
48    ) -> Option<Arc<dyn Step>> {
49        fn collect_node_ids(node_enum: &NodeEnum) -> Vec<NodeId> {
51            let mut ids: Vec<String> = vec![node_enum.0.id.clone()];
52            for child in &node_enum.1 {
53                ids.extend(collect_node_ids(child));
54            }
55            ids
56        }
57        
58        let mut all_node_ids = Vec::new();
60        for node_enum in &self.nodes {
61            all_node_ids.extend(collect_node_ids(node_enum));
62        }
63        
64        if !all_node_ids.is_empty() {
65            return Some(Arc::new(RemoveNodeStep::new(
66                self.parent_id.clone(),
67                all_node_ids,
68            )));
69        }
70        None
71    }
72}
73#[derive(Debug, Serialize, Deserialize, Clone)]
75pub struct RemoveNodeStep {
76    parent_id: NodeId,
77    node_ids: Vec<NodeId>,
78}
79impl RemoveNodeStep {
80    pub fn new(
81        parent_id: NodeId,
82        node_ids: Vec<NodeId>,
83    ) -> Self {
84        RemoveNodeStep { parent_id, node_ids }
85    }
86}
87impl Step for RemoveNodeStep {
88    fn name(&self) -> String {
89        "remove_node_step".to_string()
90    }
91    fn apply(
92        &self,
93        dart: &mut Tree,
94        schema: Arc<Schema>,
95    ) -> TransformResult<StepResult> {
96        let _ = schema;
97        let result = dart.remove_node(&self.parent_id, self.node_ids.clone());
98        match result {
99            Ok(_) => Ok(StepResult::ok()),
100            Err(e) => Err(transform_error(e.to_string())), }
102    }
103    fn serialize(&self) -> Option<Vec<u8>> {
104        serde_json::to_vec(self).ok()
105    }
106
107    fn invert(
108        &self,
109        dart: &Arc<Tree>,
110    ) -> Option<Arc<dyn Step>> {
111        let mut nodes_to_restore = Vec::new();
113        
114        for node_id in &self.node_ids {
115            if let Some(node_enum) = dart.all_children(node_id, None) {
116                nodes_to_restore.push(node_enum);
117            }
118        }
119        
120        if !nodes_to_restore.is_empty() {
121            Some(Arc::new(AddNodeStep::new(
122                self.parent_id.clone(),
123                nodes_to_restore
124            )))
125        } else {
126            None
127        }
128    }
129}
130
131#[derive(Debug, Serialize, Deserialize, Clone)]
132pub struct MoveNodeStep {
133    source_parent_id: NodeId,
134    target_parent_id: NodeId,
135    node_id: NodeId,
136    position: Option<usize>, }
138
139impl MoveNodeStep {
140    pub fn new(
141        source_parent_id: NodeId,
142        target_parent_id: NodeId,
143        node_id: NodeId,
144        position: Option<usize>,
145    ) -> Self {
146        MoveNodeStep { source_parent_id, target_parent_id, node_id, position }
147    }
148}
149
150impl Step for MoveNodeStep {
151    fn name(&self) -> String {
152        "move_node_step".to_string()
153    }
154    fn apply(
155        &self,
156        dart: &mut Tree,
157        schema: Arc<Schema>,
158    ) -> TransformResult<StepResult> {
159        let _ = schema;
160
161        match dart.move_node(
162            &self.source_parent_id,
163            &self.target_parent_id,
164            &self.node_id,
165            self.position,
166        ) {
167            Ok(()) => Ok(StepResult::ok()),
168            Err(err) => Err(transform_error(err.to_string())),
169        }
170    }
171    fn serialize(&self) -> Option<Vec<u8>> {
172        serde_json::to_vec(self).ok()
173    }
174
175    fn invert(
176        &self,
177        dart: &Arc<Tree>,
178    ) -> Option<Arc<dyn Step>> {
179        match dart.get_node(&self.node_id) {
180            Some(_) => Some(Arc::new(MoveNodeStep::new(
181                self.target_parent_id.clone(),
182                self.source_parent_id.clone(),
183                self.node_id.clone(),
184                self.position,
185            ))),
186            None => None,
187        }
188    }
189}
190
191
192#[cfg(test)]
193mod tests {
194    use super::*;
195    use moduforge_model::{
196        node::Node,
197        node_type::{NodeEnum, NodeType, NodeSpec},
198        schema::{Schema, SchemaSpec, AttributeSpec},
199        tree::Tree,
200        attrs::Attrs,
201        mark::Mark,
202    };
203    use std::collections::HashMap;
204    use std::sync::Arc;
205
206    fn create_test_node(id: &str) -> Node {
207        Node::new(
208            id,
209            "test".to_string(),
210            Attrs::default(),
211            vec![],
212            vec![],
213        )
214    }
215
216    fn create_test_schema() -> Arc<Schema> {
217        let mut nodes = HashMap::new();
218        nodes.insert("test".to_string(), NodeSpec {
219            content: None,
220            marks: None,
221            group: None,
222            desc: Some("Test node".to_string()),
223            attrs: None,
224        });
225
226        let spec = SchemaSpec {
227            nodes,
228            marks: HashMap::new(),
229            top_node: Some("test".to_string()),
230        };
231
232        Arc::new(Schema::compile(spec).unwrap())
233    }
234
235    fn create_test_tree() -> Tree {
236        let root = create_test_node("root");
237        Tree::new(root)
238    }
239
240    #[test]
241    fn test_add_node_step() {
242        let mut tree = create_test_tree();
243        let schema = create_test_schema();
244        
245        let node = create_test_node("root");
247        let test = create_test_node("test");
248        let node_enum = NodeEnum(node, vec![NodeEnum(test, vec![])]);
249        let step = AddNodeStep::new("root".to_string(), vec![node_enum.clone()]);
250        let result = step.apply(&mut tree, schema.clone());
251        assert!(result.is_ok());
252        
253        assert!(tree.get_node(&"test".to_string()).is_some());
255        
256        let inverted = step.invert(&Arc::new(tree.clone()));
258        assert!(inverted.is_some());
259        
260        if let Some(inverted_step) = inverted {
262            let result = inverted_step.apply(&mut tree, schema);
263            assert!(result.is_ok());
264            assert!(tree.get_node(&"test".to_string()).is_none());
266        }
267    }
268
269    #[test]
270    fn test_remove_node_step() {
271        let mut tree = create_test_tree();
272        let schema = create_test_schema();
273        
274        let node = create_test_node("test");
276        tree.add_node(&"root".to_string(), &vec![node]).unwrap();
277        
278        let step = RemoveNodeStep::new("root".to_string(), vec!["test".to_string()]);
279        let result = step.apply(&mut tree, schema.clone());
280        assert!(result.is_ok());
281        
282        assert!(tree.get_node(&"test".to_string()).is_none());
284        
285        let inverted = step.invert(&Arc::new(tree.clone()));
287        assert!(inverted.is_some());
288    }
289
290    #[test]
291    fn test_move_node_step() {
292        let mut tree = create_test_tree();
293        let schema = create_test_schema();
294        
295        let source = create_test_node("source");
297        let target = create_test_node("target");
298        let node = create_test_node("node");
299        
300        tree.add_node(&"root".to_string(), &vec![source]).unwrap();
301        tree.add_node(&"root".to_string(), &vec![target]).unwrap();
302        tree.add_node(&"source".to_string(), &vec![node]).unwrap();
303        
304        let step = MoveNodeStep::new(
305            "source".to_string(),
306            "target".to_string(),
307            "node".to_string(),
308            None,
309        );
310        
311        let result = step.apply(&mut tree, schema.clone());
312        assert!(result.is_ok());
313        
314        let target_node = tree.get_node(&"target".to_string()).unwrap();
316        assert!(target_node.content.contains(&"node".to_string()));
317        
318        let inverted = step.invert(&Arc::new(tree.clone()));
320        assert!(inverted.is_some());
321    }
322}