Skip to main content

ember_plus/tree/
node.rs

1//! Tree node implementations.
2
3use std::collections::HashMap;
4use std::sync::Arc;
5use parking_lot::RwLock;
6
7use crate::error::{Error, Result};
8use crate::glow::{
9    EmberValue, ParameterType, ParameterAccess, MatrixType, MatrixAddressingMode,
10    TupleItemDescription, StringIntegerPair, Label,
11    EmberPath, GlowElement, GlowRoot, GlowNode, GlowParameter, 
12    GlowFunction, GlowMatrix, GlowConnection, parse_path,
13};
14
15/// Reference to a tree node.
16pub type TreeNodeRef = Arc<RwLock<TreeNode>>;
17
18/// The root of an Ember+ tree.
19#[derive(Debug, Default)]
20pub struct EmberTree {
21    /// Root children (keyed by number)
22    children: HashMap<i32, TreeNodeRef>,
23    /// Path index for quick lookups
24    path_index: HashMap<String, TreeNodeRef>,
25}
26
27impl EmberTree {
28    /// Create a new empty tree.
29    pub fn new() -> Self {
30        EmberTree::default()
31    }
32
33    /// Add a node at the root level.
34    pub fn add_root_child(&mut self, node: TreeNode) -> TreeNodeRef {
35        let number = node.number();
36        let node_ref = Arc::new(RwLock::new(node));
37        self.children.insert(number, Arc::clone(&node_ref));
38        self.update_path_index(&node_ref, vec![number]);
39        node_ref
40    }
41
42    /// Get a root-level child by number.
43    pub fn get_child(&self, number: i32) -> Option<TreeNodeRef> {
44        self.children.get(&number).cloned()
45    }
46
47    /// Get all root-level children.
48    pub fn children(&self) -> impl Iterator<Item = &TreeNodeRef> {
49        self.children.values()
50    }
51
52    /// Get a node by path.
53    pub fn get_by_path(&self, path: &[i32]) -> Option<TreeNodeRef> {
54        if path.is_empty() {
55            return None;
56        }
57
58        let path_str = path.iter()
59            .map(|n| n.to_string())
60            .collect::<Vec<_>>()
61            .join(".");
62        
63        if let Some(node) = self.path_index.get(&path_str) {
64            return Some(Arc::clone(node));
65        }
66
67        // Manual traversal if not in index
68        let mut current = self.get_child(path[0])?;
69        
70        for &number in &path[1..] {
71            let node = current.read();
72            let child = node.get_child(number)?;
73            drop(node);
74            current = child;
75        }
76        
77        Some(current)
78    }
79
80    /// Get a node by path string (e.g., "0.1.2").
81    pub fn get_by_path_str(&self, path: &str) -> Result<Option<TreeNodeRef>> {
82        let path = parse_path(path)?;
83        Ok(self.get_by_path(&path))
84    }
85
86    /// Update the tree from a Glow root message.
87    pub fn update_from_glow(&mut self, root: &GlowRoot) {
88        for element in &root.elements {
89            self.update_element(element, vec![]);
90        }
91    }
92
93    /// Update a single element in the tree.
94    fn update_element(&mut self, element: &GlowElement, parent_path: Vec<i32>) {
95        match element {
96            GlowElement::Node(node) => {
97                let mut path = parent_path.clone();
98                path.push(node.number);
99                
100                let tree_node = self.ensure_node(&path);
101                {
102                    let mut n = tree_node.write();
103                    n.update_from_glow_node(node);
104                }
105                
106                for child in &node.children {
107                    self.update_element(child, path.clone());
108                }
109            }
110            GlowElement::Parameter(param) => {
111                let mut path = parent_path.clone();
112                path.push(param.number);
113                
114                let tree_node = self.ensure_node(&path);
115                {
116                    let mut n = tree_node.write();
117                    n.update_from_glow_parameter(param);
118                }
119            }
120            GlowElement::Function(func) => {
121                let mut path = parent_path.clone();
122                path.push(func.number);
123                
124                let tree_node = self.ensure_node(&path);
125                {
126                    let mut n = tree_node.write();
127                    n.update_from_glow_function(func);
128                }
129            }
130            GlowElement::Matrix(matrix) => {
131                let mut path = parent_path.clone();
132                path.push(matrix.number);
133                
134                let tree_node = self.ensure_node(&path);
135                {
136                    let mut n = tree_node.write();
137                    n.update_from_glow_matrix(matrix);
138                }
139            }
140            GlowElement::QualifiedNode(path, node) => {
141                let tree_node = self.ensure_node(path);
142                {
143                    let mut n = tree_node.write();
144                    n.update_from_glow_node(node);
145                }
146                
147                for child in &node.children {
148                    self.update_element(child, path.clone());
149                }
150            }
151            GlowElement::QualifiedParameter(path, param) => {
152                let tree_node = self.ensure_node(path);
153                {
154                    let mut n = tree_node.write();
155                    n.update_from_glow_parameter(param);
156                }
157            }
158            GlowElement::QualifiedFunction(path, func) => {
159                let tree_node = self.ensure_node(path);
160                {
161                    let mut n = tree_node.write();
162                    n.update_from_glow_function(func);
163                }
164            }
165            GlowElement::QualifiedMatrix(path, matrix) => {
166                let tree_node = self.ensure_node(path);
167                {
168                    let mut n = tree_node.write();
169                    n.update_from_glow_matrix(matrix);
170                }
171            }
172            _ => {}
173        }
174    }
175
176    /// Ensure a node exists at the given path, creating intermediates as needed.
177    fn ensure_node(&mut self, path: &[i32]) -> TreeNodeRef {
178        if path.is_empty() {
179            panic!("Cannot ensure node at empty path");
180        }
181
182        // Check if already exists
183        if let Some(node) = self.get_by_path(path) {
184            return node;
185        }
186
187        // Create root node if needed
188        if !self.children.contains_key(&path[0]) {
189            let new_node = Arc::new(RwLock::new(TreeNode::new_node(path[0])));
190            self.children.insert(path[0], Arc::clone(&new_node));
191            let path_str = path[0].to_string();
192            self.path_index.insert(path_str, new_node);
193        }
194        
195        let root_node = Arc::clone(self.children.get(&path[0]).unwrap());
196
197        if path.len() == 1 {
198            return root_node;
199        }
200
201        // Traverse and create intermediate nodes
202        let mut current = root_node;
203        let mut current_path = vec![path[0]];
204        
205        for &number in &path[1..] {
206            current_path.push(number);
207            let child = {
208                let mut node = current.write();
209                if let Some(existing) = node.get_child(number) {
210                    existing
211                } else {
212                    let new_child = Arc::new(RwLock::new(TreeNode::new_node(number)));
213                    node.add_child(Arc::clone(&new_child));
214                    new_child
215                }
216            };
217            let path_str = current_path.iter()
218                .map(|n| n.to_string())
219                .collect::<Vec<_>>()
220                .join(".");
221            self.path_index.insert(path_str, Arc::clone(&child));
222            current = child;
223        }
224
225        current
226    }
227
228    /// Update the path index for a node.
229    fn update_path_index(&mut self, node: &TreeNodeRef, path: Vec<i32>) {
230        let path_str = path.iter()
231            .map(|n| n.to_string())
232            .collect::<Vec<_>>()
233            .join(".");
234        self.path_index.insert(path_str, Arc::clone(node));
235    }
236
237    /// Clear the tree.
238    pub fn clear(&mut self) {
239        self.children.clear();
240        self.path_index.clear();
241    }
242
243    /// Convert the tree to Glow elements.
244    pub fn to_glow_elements(&self) -> Vec<GlowElement> {
245        self.children.values()
246            .map(|node| node.read().to_glow_element())
247            .collect()
248    }
249}
250
251/// Contents of a tree node.
252#[derive(Debug, Clone)]
253pub enum NodeContents {
254    /// A container node
255    Node {
256        identifier: Option<String>,
257        description: Option<String>,
258        is_root: Option<bool>,
259        is_online: Option<bool>,
260        schema_identifiers: Option<String>,
261    },
262    /// A parameter
263    Parameter {
264        identifier: Option<String>,
265        description: Option<String>,
266        value: Option<EmberValue>,
267        minimum: Option<EmberValue>,
268        maximum: Option<EmberValue>,
269        access: Option<ParameterAccess>,
270        format: Option<String>,
271        enumeration: Option<String>,
272        factor: Option<i32>,
273        is_online: Option<bool>,
274        formula: Option<String>,
275        step: Option<i32>,
276        default: Option<EmberValue>,
277        parameter_type: Option<ParameterType>,
278        stream_identifier: Option<i32>,
279        enum_map: Vec<StringIntegerPair>,
280    },
281    /// A function
282    Function {
283        identifier: Option<String>,
284        description: Option<String>,
285        arguments: Vec<TupleItemDescription>,
286        result: Vec<TupleItemDescription>,
287    },
288    /// A matrix
289    Matrix {
290        identifier: Option<String>,
291        description: Option<String>,
292        matrix_type: Option<MatrixType>,
293        addressing_mode: Option<MatrixAddressingMode>,
294        target_count: Option<i32>,
295        source_count: Option<i32>,
296        max_connections_per_target: Option<i32>,
297        max_total_connections: Option<i32>,
298        targets: Vec<i32>,
299        sources: Vec<i32>,
300        connections: Vec<GlowConnection>,
301        labels: Vec<Label>,
302    },
303}
304
305impl Default for NodeContents {
306    fn default() -> Self {
307        NodeContents::Node {
308            identifier: None,
309            description: None,
310            is_root: None,
311            is_online: None,
312            schema_identifiers: None,
313        }
314    }
315}
316
317/// A node in the Ember+ tree.
318#[derive(Debug)]
319pub struct TreeNode {
320    /// Node number
321    number: i32,
322    /// Node contents
323    contents: NodeContents,
324    /// Child nodes
325    children: HashMap<i32, TreeNodeRef>,
326}
327
328impl TreeNode {
329    /// Create a new container node.
330    pub fn new_node(number: i32) -> Self {
331        TreeNode {
332            number,
333            contents: NodeContents::Node {
334                identifier: None,
335                description: None,
336                is_root: None,
337                is_online: None,
338                schema_identifiers: None,
339            },
340            children: HashMap::new(),
341        }
342    }
343
344    /// Create a new parameter node.
345    pub fn new_parameter(number: i32, value: EmberValue) -> Self {
346        TreeNode {
347            number,
348            contents: NodeContents::Parameter {
349                identifier: None,
350                description: None,
351                value: Some(value),
352                minimum: None,
353                maximum: None,
354                access: Some(ParameterAccess::ReadWrite),
355                format: None,
356                enumeration: None,
357                factor: None,
358                is_online: None,
359                formula: None,
360                step: None,
361                default: None,
362                parameter_type: None,
363                stream_identifier: None,
364                enum_map: vec![],
365            },
366            children: HashMap::new(),
367        }
368    }
369
370    /// Get the node number.
371    pub fn number(&self) -> i32 {
372        self.number
373    }
374
375    /// Get the node contents.
376    pub fn contents(&self) -> &NodeContents {
377        &self.contents
378    }
379
380    /// Get mutable node contents.
381    pub fn contents_mut(&mut self) -> &mut NodeContents {
382        &mut self.contents
383    }
384
385    /// Get the identifier.
386    pub fn identifier(&self) -> Option<&str> {
387        match &self.contents {
388            NodeContents::Node { identifier, .. } => identifier.as_deref(),
389            NodeContents::Parameter { identifier, .. } => identifier.as_deref(),
390            NodeContents::Function { identifier, .. } => identifier.as_deref(),
391            NodeContents::Matrix { identifier, .. } => identifier.as_deref(),
392        }
393    }
394
395    /// Get the description.
396    pub fn description(&self) -> Option<&str> {
397        match &self.contents {
398            NodeContents::Node { description, .. } => description.as_deref(),
399            NodeContents::Parameter { description, .. } => description.as_deref(),
400            NodeContents::Function { description, .. } => description.as_deref(),
401            NodeContents::Matrix { description, .. } => description.as_deref(),
402        }
403    }
404
405    /// Check if this is a container node.
406    pub fn is_node(&self) -> bool {
407        matches!(self.contents, NodeContents::Node { .. })
408    }
409
410    /// Check if this is a parameter.
411    pub fn is_parameter(&self) -> bool {
412        matches!(self.contents, NodeContents::Parameter { .. })
413    }
414
415    /// Check if this is a function.
416    pub fn is_function(&self) -> bool {
417        matches!(self.contents, NodeContents::Function { .. })
418    }
419
420    /// Check if this is a matrix.
421    pub fn is_matrix(&self) -> bool {
422        matches!(self.contents, NodeContents::Matrix { .. })
423    }
424
425    /// Get the parameter value if this is a parameter.
426    pub fn value(&self) -> Option<&EmberValue> {
427        match &self.contents {
428            NodeContents::Parameter { value, .. } => value.as_ref(),
429            _ => None,
430        }
431    }
432
433    /// Set the parameter value.
434    pub fn set_value(&mut self, new_value: EmberValue) {
435        if let NodeContents::Parameter { value, .. } = &mut self.contents {
436            *value = Some(new_value);
437        }
438    }
439
440    /// Add a child node.
441    pub fn add_child(&mut self, child: TreeNodeRef) {
442        let number = child.read().number;
443        self.children.insert(number, child);
444    }
445
446    /// Get a child by number.
447    pub fn get_child(&self, number: i32) -> Option<TreeNodeRef> {
448        self.children.get(&number).cloned()
449    }
450
451    /// Get all children.
452    pub fn children(&self) -> impl Iterator<Item = &TreeNodeRef> {
453        self.children.values()
454    }
455
456    /// Update from a Glow node.
457    pub fn update_from_glow_node(&mut self, glow: &GlowNode) {
458        self.contents = NodeContents::Node {
459            identifier: glow.identifier.clone(),
460            description: glow.description.clone(),
461            is_root: glow.is_root,
462            is_online: glow.is_online,
463            schema_identifiers: glow.schema_identifiers.clone(),
464        };
465    }
466
467    /// Update from a Glow parameter.
468    pub fn update_from_glow_parameter(&mut self, glow: &GlowParameter) {
469        self.contents = NodeContents::Parameter {
470            identifier: glow.identifier.clone(),
471            description: glow.description.clone(),
472            value: glow.value.clone(),
473            minimum: glow.minimum.clone(),
474            maximum: glow.maximum.clone(),
475            access: glow.access,
476            format: glow.format.clone(),
477            enumeration: glow.enumeration.clone(),
478            factor: glow.factor,
479            is_online: glow.is_online,
480            formula: glow.formula.clone(),
481            step: glow.step,
482            default: glow.default.clone(),
483            parameter_type: glow.parameter_type,
484            stream_identifier: glow.stream_identifier,
485            enum_map: glow.enum_map.clone(),
486        };
487    }
488
489    /// Update from a Glow function.
490    pub fn update_from_glow_function(&mut self, glow: &GlowFunction) {
491        self.contents = NodeContents::Function {
492            identifier: glow.identifier.clone(),
493            description: glow.description.clone(),
494            arguments: glow.arguments.clone(),
495            result: glow.result.clone(),
496        };
497    }
498
499    /// Update from a Glow matrix.
500    pub fn update_from_glow_matrix(&mut self, glow: &GlowMatrix) {
501        self.contents = NodeContents::Matrix {
502            identifier: glow.identifier.clone(),
503            description: glow.description.clone(),
504            matrix_type: glow.matrix_type,
505            addressing_mode: glow.addressing_mode,
506            target_count: glow.target_count,
507            source_count: glow.source_count,
508            max_connections_per_target: glow.max_connections_per_target,
509            max_total_connections: glow.max_total_connections,
510            targets: glow.targets.clone(),
511            sources: glow.sources.clone(),
512            connections: glow.connections.clone(),
513            labels: glow.labels.clone(),
514        };
515    }
516
517    /// Convert to a Glow element (non-qualified, for nested children).
518    pub fn to_glow_element(&self) -> GlowElement {
519        match &self.contents {
520            NodeContents::Node { identifier, description, is_root, is_online, schema_identifiers } => {
521                let mut node = GlowNode::new(self.number);
522                node.identifier = identifier.clone();
523                node.description = description.clone();
524                node.is_root = *is_root;
525                node.is_online = *is_online;
526                node.schema_identifiers = schema_identifiers.clone();
527                // Don't include children for non-qualified - client should request them
528                GlowElement::Node(node)
529            }
530            NodeContents::Parameter { identifier, description, value, minimum, maximum, access, format, enumeration, factor, is_online, formula, step, default, parameter_type, stream_identifier, enum_map } => {
531                let mut param = GlowParameter::new(self.number);
532                param.identifier = identifier.clone();
533                param.description = description.clone();
534                param.value = value.clone();
535                param.minimum = minimum.clone();
536                param.maximum = maximum.clone();
537                param.access = *access;
538                param.format = format.clone();
539                param.enumeration = enumeration.clone();
540                param.factor = *factor;
541                param.is_online = *is_online;
542                param.formula = formula.clone();
543                param.step = *step;
544                param.default = default.clone();
545                param.parameter_type = *parameter_type;
546                param.stream_identifier = *stream_identifier;
547                param.enum_map = enum_map.clone();
548                GlowElement::Parameter(param)
549            }
550            NodeContents::Function { identifier, description, arguments, result } => {
551                let mut func = GlowFunction::new(self.number);
552                func.identifier = identifier.clone();
553                func.description = description.clone();
554                func.arguments = arguments.clone();
555                func.result = result.clone();
556                GlowElement::Function(func)
557            }
558            NodeContents::Matrix { identifier, description, matrix_type, addressing_mode, target_count, source_count, max_connections_per_target, max_total_connections, targets, sources, connections, labels } => {
559                let mut matrix = GlowMatrix::new(self.number);
560                matrix.identifier = identifier.clone();
561                matrix.description = description.clone();
562                matrix.matrix_type = *matrix_type;
563                matrix.addressing_mode = *addressing_mode;
564                matrix.target_count = *target_count;
565                matrix.source_count = *source_count;
566                matrix.max_connections_per_target = *max_connections_per_target;
567                matrix.max_total_connections = *max_total_connections;
568                matrix.targets = targets.clone();
569                matrix.sources = sources.clone();
570                matrix.connections = connections.clone();
571                matrix.labels = labels.clone();
572                GlowElement::Matrix(matrix)
573            }
574        }
575    }
576
577    /// Convert to a qualified Glow element with full path.
578    /// This is the correct format for server responses.
579    pub fn to_qualified_glow_element(&self, path: &EmberPath) -> GlowElement {
580        match &self.contents {
581            NodeContents::Node { identifier, description, is_root, is_online, schema_identifiers } => {
582                let mut node = GlowNode::new(self.number);
583                node.identifier = identifier.clone();
584                node.description = description.clone();
585                node.is_root = *is_root;
586                node.is_online = *is_online;
587                node.schema_identifiers = schema_identifiers.clone();
588                GlowElement::QualifiedNode(path.clone(), node)
589            }
590            NodeContents::Parameter { identifier, description, value, minimum, maximum, access, format, enumeration, factor, is_online, formula, step, default, parameter_type, stream_identifier, enum_map } => {
591                let mut param = GlowParameter::new(self.number);
592                param.identifier = identifier.clone();
593                param.description = description.clone();
594                param.value = value.clone();
595                param.minimum = minimum.clone();
596                param.maximum = maximum.clone();
597                param.access = *access;
598                param.format = format.clone();
599                param.enumeration = enumeration.clone();
600                param.factor = *factor;
601                param.is_online = *is_online;
602                param.formula = formula.clone();
603                param.step = *step;
604                param.default = default.clone();
605                param.parameter_type = *parameter_type;
606                param.stream_identifier = *stream_identifier;
607                param.enum_map = enum_map.clone();
608                GlowElement::QualifiedParameter(path.clone(), param)
609            }
610            NodeContents::Function { identifier, description, arguments, result } => {
611                let mut func = GlowFunction::new(self.number);
612                func.identifier = identifier.clone();
613                func.description = description.clone();
614                func.arguments = arguments.clone();
615                func.result = result.clone();
616                GlowElement::QualifiedFunction(path.clone(), func)
617            }
618            NodeContents::Matrix { identifier, description, matrix_type, addressing_mode, target_count, source_count, max_connections_per_target, max_total_connections, targets, sources, connections, labels } => {
619                let mut matrix = GlowMatrix::new(self.number);
620                matrix.identifier = identifier.clone();
621                matrix.description = description.clone();
622                matrix.matrix_type = *matrix_type;
623                matrix.addressing_mode = *addressing_mode;
624                matrix.target_count = *target_count;
625                matrix.source_count = *source_count;
626                matrix.max_connections_per_target = *max_connections_per_target;
627                matrix.max_total_connections = *max_total_connections;
628                matrix.targets = targets.clone();
629                matrix.sources = sources.clone();
630                matrix.connections = connections.clone();
631                matrix.labels = labels.clone();
632                GlowElement::QualifiedMatrix(path.clone(), matrix)
633            }
634        }
635    }
636}