1 package org.lsst.ccs.utilities.structs;
2
3 import javax.swing.tree.TreeNode;
4 import java.beans.ConstructorProperties;
5 import java.io.Serializable;
6 import java.util.*;
7
8
9
10
11
12
13
14
15 public class TreeBranch<T extends Serializable> implements Serializable, TreeNode, Iterable<T> {
16
17 private static final long serialVersionUID = -8299651867210784530L;
18
19
20
21 private TreeBranch<T> parent;
22
23
24
25 private ArrayList<TreeBranch<T>> children;
26
27
28
29 private T content;
30
31
32
33
34 private int currentIndex = -1;
35
36
37
38
39
40
41 public TreeBranch(T content) {
42 this.content = content;
43 }
44
45
46
47
48
49 protected TreeBranch() {
50 }
51
52
53
54
55
56
57
58
59 @ConstructorProperties({"realParent", "content"})
60 public TreeBranch(TreeBranch<T> parent, T content) {
61
62 this.content = content;
63 if (parent != null) {
64 parent.addChild(this);
65 }
66 }
67
68
69
70
71
72
73
74 public synchronized void addChild(TreeBranch<T> child) {
75 if (child == null) {
76 throw new IllegalArgumentException("null child");
77 }
78 if (child.parent != null) {
79 throw new IllegalArgumentException(this + " node " + child + " already part of another tree " + child.parent);
80 }
81 if (children == null) {
82 children = new ArrayList<>();
83 }
84 int index = children.size();
85 children.add(child);
86 child.currentIndex = index;
87 child.parent = this;
88 }
89
90
91
92
93 public T getContent() {
94 return content;
95 }
96
97
98
99
100
101 public int getCurrentIndex() {
102 return currentIndex;
103 }
104
105
106
107
108 @Override
109 public Iterator<T> iterator() {
110 return new PreOrderIterator<T>(this);
111 }
112
113
114
115
116 public Iterator<TreeBranch<T>> nodeIterator() {
117 return new PreOrderNodeIterator<T>(this);
118 }
119
120
121
122
123 public List<TreeBranch<T>> getChildren() {
124 if (children != null) {
125 return children;
126 }
127 return Collections.emptyList();
128 }
129
130
131
132
133 public Iterator<TreeBranch<T>> getChildIterator() {
134 if (children != null) {
135 return children.iterator();
136 }
137 return Collections.emptyIterator();
138 }
139
140
141
142
143
144 public List<TreeBranch<T>> getPath() {
145 ArrayList<TreeBranch<T>> res = new ArrayList<>();
146 TreeBranch<T> curNode = this;
147 while (null != (curNode = curNode.getRealParent())) {
148 res.add(curNode);
149 }
150 Collections.reverse(res);
151 return res;
152 }
153
154
155
156
157
158
159
160 @Override
161 public TreeNode getChildAt(int childIndex) {
162 if (children != null) {
163 if (childIndex >= children.size() || childIndex < 0) {
164 return null;
165 }
166 TreeBranch<T> res = children.get(childIndex);
167 assert childIndex == res.currentIndex;
168 return res;
169 }
170 return null;
171 }
172
173
174
175
176 @Override
177 public int getChildCount() {
178 if (children == null) return 0;
179 return children.size();
180 }
181
182
183
184
185
186 @Override
187 public TreeNode getParent() {
188 return parent;
189 }
190
191
192
193
194
195
196
197 public TreeBranch<T> getRealParent() {
198 return parent;
199 }
200
201
202
203
204
205
206 @Override
207 public int getIndex(TreeNode node) {
208 if (node.getParent() != this) {
209 return -1;
210 }
211 if (children != null) {
212 TreeBranch<T> branch = (TreeBranch<T>) node;
213 return branch.currentIndex;
214 }
215 return -1;
216 }
217
218
219
220
221
222
223
224 @Override
225 public boolean getAllowsChildren() {
226 return children != null;
227 }
228
229
230
231
232 @Override
233 public boolean isLeaf() {
234 return children == null;
235 }
236
237
238
239
240 public boolean isRootNode() {
241 return parent == null;
242 }
243
244
245
246
247
248 @Override
249 public Enumeration children() {
250
251 return new Enumeration() {
252 final Iterator iter = children.iterator();
253
254 @Override
255 public boolean hasMoreElements() {
256 return iter.hasNext();
257 }
258
259 @Override
260 public Object nextElement() {
261 return iter.next();
262 }
263 };
264 }
265
266
267
268
269
270 @Override
271 public String toString() {
272 return String.valueOf(content);
273 }
274
275
276
277
278
279 public String deepString() {
280 return deepString(0) ;
281 }
282
283 protected String deepString(int level) {
284 StringBuilder stb = new StringBuilder() ;
285 for(int ix = 0 ; ix < level ; ix++) {
286 stb.append('\t') ;
287 }
288 stb.append(toString()).append('\n') ;
289 int levelChilds = level+1 ;
290 if(children != null) {
291 for (TreeBranch child : children) {
292 stb.append(child.deepString(levelChilds));
293 }
294 }
295 return stb.toString() ;
296 }
297
298
299
300
301
302
303
304 protected static class PreOrderIterator<X extends Serializable> implements Iterator<X> {
305 private final PreOrderNodeIterator<X> preOrderNodeIterator;
306
307 public PreOrderIterator(TreeBranch<X> rootNode) {
308 preOrderNodeIterator = new PreOrderNodeIterator<>(rootNode);
309 }
310
311
312 @Override
313 public X next() {
314 TreeBranch<X> node = preOrderNodeIterator.next();
315 return node.getContent();
316 }
317
318
319 @Override
320 public boolean hasNext() {
321 return preOrderNodeIterator.hasNext();
322 }
323
324
325 @Override
326 public void remove() {
327 throw new UnsupportedOperationException("remove");
328 }
329 }
330
331
332
333
334
335
336 protected static class PreOrderNodeIterator<X extends Serializable> implements Iterator<TreeBranch<X>> {
337 private final Stack<Iterator<TreeBranch<X>>> stack = new Stack<>();
338
339 public PreOrderNodeIterator(TreeBranch<X> rootNode) {
340
341 ArrayList<TreeBranch<X>> edenChildList = new ArrayList<>(1);
342 edenChildList.add(rootNode);
343 stack.push(edenChildList.iterator());
344 }
345
346
347 @Override
348 public TreeBranch<X> next() {
349
350
351 Iterator<TreeBranch<X>> iter = stack.peek();
352
353 TreeBranch<X> node = iter.next();
354
355 Iterator<TreeBranch<X>> itChildren = node.getChildIterator();
356
357 if (!iter.hasNext()) {
358 stack.pop();
359 }
360
361 if (itChildren.hasNext()) {
362 stack.push(itChildren);
363 }
364 return node;
365 }
366
367
368
369
370
371
372
373
374 @Override
375 public boolean hasNext() {
376 return (!stack.empty() && stack.peek().hasNext());
377 }
378
379
380 @Override
381 public void remove() {
382 throw new UnsupportedOperationException("remove");
383 }
384 }
385 }