performed javacscript:fix and worked on documentation
[taxeditor.git] / taxeditor-store / src / main / java / eu / etaxonomy / taxeditor / model / FeatureNodeContainer.java
1 // $Id$
2 /**
3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
6 *
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
9 */
10
11 package eu.etaxonomy.taxeditor.model;
12
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.Comparator;
16 import java.util.HashMap;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Set;
20 import java.util.UUID;
21
22 import org.joda.time.DateTime;
23
24 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
25 import eu.etaxonomy.cdm.model.common.Annotation;
26 import eu.etaxonomy.cdm.model.common.IAnnotatableEntity;
27 import eu.etaxonomy.cdm.model.common.Marker;
28 import eu.etaxonomy.cdm.model.common.User;
29 import eu.etaxonomy.cdm.model.description.DescriptionBase;
30 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
31 import eu.etaxonomy.cdm.model.description.Feature;
32 import eu.etaxonomy.cdm.model.description.FeatureNode;
33 import eu.etaxonomy.cdm.model.description.FeatureTree;
34 import eu.etaxonomy.cdm.model.description.TaxonDescription;
35
36 /**
37 * This class is a simple container to allow generation of a datastructure that
38 * describes a feature tree according to a specific description element, i.e a tree
39 * structure that halds only the {@link FeatureNode}s that are relevant for a specific
40 * {@link TaxonDescription} as well as the {@link DescriptionElementBase} at the leaf level.
41 *
42 * This kind of datastructure is needed by interface elements such as viewers and greatly simplify
43 * the handling of {@link FeatureTree}s in conjunction with {@link TaxonDescription}s.
44 *
45 * @author n.hoffmann
46 * @created Sep 20, 2010
47 * @version 1.0
48 */
49 public class FeatureNodeContainer implements IAnnotatableEntity{
50
51 /** Constant <code>comparator</code> */
52 public static Comparator<DescriptionElementBase> comparator = new Comparator<DescriptionElementBase>() {
53
54 @Override
55 public int compare(DescriptionElementBase o1, DescriptionElementBase o2) {
56 return DescriptionHelper.getLabel(o1).compareTo(DescriptionHelper.getLabel(o2));
57 }
58 };
59
60 private FeatureNode featureNode;
61 private List<FeatureNodeContainer> children = new ArrayList<FeatureNodeContainer>();
62 private List<DescriptionElementBase> descriptionElements = new ArrayList<DescriptionElementBase>();
63
64
65 private DescriptionBase description;
66
67 /**
68 * @param description
69 */
70 private FeatureNodeContainer(DescriptionBase description) {
71 this.description = description;
72 }
73
74
75 /**
76 * Traverses the given {@link FeatureNode} and computes a FeatureNodeContainer branch if the
77 * given {@link TaxonDescription} has elements for the given feature node or any of its children
78 * or null if there are no elements.
79 *
80 * @param description a {@link eu.etaxonomy.cdm.model.description.DescriptionBase} object.
81 * @param featureTree a {@link eu.etaxonomy.cdm.model.description.FeatureTree} object.
82 * @return a {@link eu.etaxonomy.taxeditor.model.FeatureNodeContainer} object.
83 */
84 public static FeatureNodeContainer CreateTree(FeatureTree featureTree, DescriptionBase description){
85
86 List<FeatureNode> children = featureTree.getRootChildren();
87
88 FeatureNodeContainer root = new FeatureNodeContainer(description);
89
90 for(FeatureNode featureNode : children){
91 FeatureNodeContainer branch = findLeaves(featureNode, description);
92 if(branch != null){
93 root.addChild(branch);
94 }
95 }
96
97 return root;
98 }
99
100
101 /**
102 * Recursively traverse a branch of a feature tree and check if there are
103 *
104 * @param featureNode
105 * @param description
106 * @return
107 */
108 private static FeatureNodeContainer findLeaves(FeatureNode featureNode, DescriptionBase description) {
109 if(featureNode.isLeaf()){
110 return buildLeaf(featureNode, description);
111 }else{
112 for(FeatureNode childNode : featureNode.getChildren()){
113 return findLeaves(childNode, description);
114 }
115 }
116 return null;
117 }
118
119 private static FeatureNodeContainer buildLeaf(FeatureNode featureNode, DescriptionBase description){
120 List<DescriptionElementBase> elements = getDescriptionsElementsForFeature(description, featureNode.getFeature());
121 if(elements.isEmpty()){
122 return null;
123 }else{
124 FeatureNodeContainer container = new FeatureNodeContainer(description);
125 container.setFeatureNode(featureNode);
126 container.setDescriptionElements(elements);
127
128 return container.buildBranch(null);
129 }
130 }
131
132 private FeatureNodeContainer buildBranch(Map<FeatureNode, FeatureNodeContainer> featureNodeMap){
133 FeatureNode parentFeatureNode = getFeatureNode().getParent();
134
135 if(parentFeatureNode != null && parentFeatureNode.getFeature() != null){
136 if(featureNodeMap == null){
137 featureNodeMap = new HashMap<FeatureNode, FeatureNodeContainer>();
138 }
139
140 // reuse parent container if it exists
141 FeatureNodeContainer parentContainer = featureNodeMap.get(parentFeatureNode);
142 // create a new container if necessary
143 if(parentContainer == null){
144 parentContainer = new FeatureNodeContainer(getDescription());
145 parentContainer.setFeatureNode(parentFeatureNode);
146 featureNodeMap.put(parentFeatureNode, parentContainer);
147 }
148
149 parentContainer.addChild(this);
150
151 return parentContainer.buildBranch(featureNodeMap);
152 }
153 return this;
154 }
155
156 /**
157 * <p>Getter for the field <code>children</code>.</p>
158 *
159 * @return a {@link java.util.List} object.
160 */
161 public List<FeatureNodeContainer> getChildren() {
162 return children;
163 }
164
165 /**
166 * Sets the list of children of this containers children
167 *
168 * @param children a {@link java.util.List} object.
169 * @throws java.lang.IllegalStateException when <code>this</code> container contains a description element.
170 */
171 public void setChildren(List<FeatureNodeContainer> children) {
172 if(descriptionElements.isEmpty()){
173 this.children = children;
174 }else{
175 throw new IllegalStateException("Container may not have a description element set when setting children.");
176 }
177 }
178
179 /**
180 * Adds a child container to the list of this containers children
181 *
182 * @param container a {@link eu.etaxonomy.taxeditor.model.FeatureNodeContainer} object.
183 * @throws java.lang.IllegalStateException when <code>this</code> container contains a description element.
184 */
185 public void addChild(FeatureNodeContainer container){
186 if(descriptionElements.isEmpty()){
187 children.add(container);
188 }else{
189 throw new IllegalStateException("Container may not have a description element set when adding children.");
190 }
191 }
192
193 /**
194 * If {@link #isLeaf()} is true, i.e. this container should have elements, returns the list of description elements.
195 *
196 * @return a {@link java.util.List} object.
197 */
198 public List<DescriptionElementBase> getDescriptionElements() {
199 return descriptionElements;
200 }
201
202 /**
203 * Cumulates description elements for <code>this</code> container as well as child feature nodes recursively,
204 * thus returning a list of description elements for the branch of the feature tree starting with <code>this</code>
205 * node.
206 *
207 * @return a {@link java.util.List} object.
208 */
209 public List<DescriptionElementBase> getDescriptionElementsForEntireBranch(){
210 return getDescriptionElementsRecursively(new ArrayList<DescriptionElementBase>());
211 }
212
213 private List<DescriptionElementBase> getDescriptionElementsRecursively(List<DescriptionElementBase> descriptionElements){
214 if(isLeaf()){
215 descriptionElements.addAll(getDescriptionElements());
216 }else{
217 for(FeatureNodeContainer container : getChildren()){
218 container.getDescriptionElementsRecursively(descriptionElements);
219 }
220 }
221 return descriptionElements;
222 }
223
224 /**
225 * <p>getFeatureNodeContainerForDescriptionElement</p>
226 *
227 * @param descriptionElement a {@link eu.etaxonomy.cdm.model.description.DescriptionElementBase} object.
228 * @return a {@link eu.etaxonomy.taxeditor.model.FeatureNodeContainer} object.
229 */
230 public FeatureNodeContainer getFeatureNodeContainerForDescriptionElement (DescriptionElementBase descriptionElement) {
231 List<FeatureNodeContainer> leafs = getLeafs();
232
233 for(FeatureNodeContainer container : leafs){
234 if(container.getDescriptionElements().contains(descriptionElement)){
235 return container;
236 }
237 }
238 return null;
239 }
240
241 private List<FeatureNodeContainer> getLeafs(){
242 List<FeatureNodeContainer> leafs = new ArrayList<FeatureNodeContainer>();
243
244 if(isLeaf()){
245 leafs.add(this);
246 }else{
247 for(FeatureNodeContainer container : getChildren()){
248 leafs.addAll(container.getLeafs());
249 }
250 }
251 return leafs;
252 }
253
254 /**
255 * Set the description element
256 *
257 * @throws java.lang.IllegalStateException when <code>this</code> container contains child container.
258 * @param descriptionElements a {@link java.util.List} object.
259 */
260 public void setDescriptionElements(List<DescriptionElementBase> descriptionElements) {
261 if(children.isEmpty()){
262 this.descriptionElements = descriptionElements;
263 }else{
264 throw new IllegalStateException("Container may not contain child container when adding description elements.");
265 }
266 }
267
268 /**
269 * If the container is a leaf, it will hold a description element and no child containers
270 *
271 * @return a boolean.
272 */
273 public boolean isLeaf(){
274 return ! descriptionElements.isEmpty() && children.isEmpty();
275 }
276
277 private static List<DescriptionElementBase> getDescriptionsElementsForFeature(
278 DescriptionBase description, Feature feature) {
279 List<DescriptionElementBase> featureElements = new ArrayList<DescriptionElementBase>();
280
281 Set<DescriptionElementBase> elements = description.getElements();
282 if (elements != null) {
283 for (DescriptionElementBase element : elements) {
284 Feature elementFeature = (Feature) HibernateProxyHelper.deproxy(element.getFeature());
285
286 if (feature.equals(elementFeature)) {
287 featureElements.add(element);
288 }
289 }
290 }
291
292 if(featureElements.size() != 0){
293 Collections.sort(featureElements, comparator);
294 }
295
296 return featureElements;
297 }
298
299 /**
300 * <p>Setter for the field <code>featureNode</code>.</p>
301 *
302 * @param featureNode a {@link eu.etaxonomy.cdm.model.description.FeatureNode} object.
303 */
304 public void setFeatureNode(FeatureNode featureNode) {
305 this.featureNode = featureNode;
306 }
307
308 /**
309 * <p>Getter for the field <code>featureNode</code>.</p>
310 *
311 * @return a {@link eu.etaxonomy.cdm.model.description.FeatureNode} object.
312 */
313 public FeatureNode getFeatureNode() {
314 return featureNode;
315 }
316
317 /**
318 * <p>getFeature</p>
319 *
320 * @return a {@link eu.etaxonomy.cdm.model.description.Feature} object.
321 */
322 public Feature getFeature(){
323 return featureNode.getFeature();
324 }
325
326 /**
327 * <p>Getter for the field <code>description</code>.</p>
328 *
329 * @return a {@link eu.etaxonomy.cdm.model.description.DescriptionBase} object.
330 */
331 public DescriptionBase getDescription(){
332 return description;
333 }
334
335 /**
336 * {@inheritDoc}
337 *
338 ************** NOT USED ****************
339 */
340 @Override
341 public User getUpdatedBy() {return null;}
342
343 /** {@inheritDoc} */
344 @Override
345 public void setUpdatedBy(User updatedBy) {}
346
347 /** {@inheritDoc} */
348 @Override
349 public DateTime getUpdated() {return null;}
350
351 /** {@inheritDoc} */
352 @Override
353 public void setUpdated(DateTime updated) {}
354
355 /** {@inheritDoc} */
356 @Override
357 public int getId() {return 0;}
358
359 /** {@inheritDoc} */
360 @Override
361 public void setId(int id) {}
362
363 /** {@inheritDoc} */
364 @Override
365 public UUID getUuid() {return null;}
366
367 /** {@inheritDoc} */
368 @Override
369 public void setUuid(UUID uuid) {}
370
371 /** {@inheritDoc} */
372 @Override
373 public DateTime getCreated() {return null;}
374
375 /** {@inheritDoc} */
376 @Override
377 public void setCreated(DateTime created) {}
378
379 /** {@inheritDoc} */
380 @Override
381 public User getCreatedBy() {return null;}
382
383 /** {@inheritDoc} */
384 @Override
385 public void setCreatedBy(User createdBy) {}
386
387 /** {@inheritDoc} */
388 @Override
389 public Set<Annotation> getAnnotations() {return null;}
390
391 /** {@inheritDoc} */
392 @Override
393 public void addAnnotation(Annotation annotation) {}
394
395 /** {@inheritDoc} */
396 @Override
397 public void removeAnnotation(Annotation annotation) {}
398
399 /** {@inheritDoc} */
400 @Override
401 public Set<Marker> getMarkers() { return null; }
402
403 /** {@inheritDoc} */
404 @Override
405 public void addMarker(Marker marker) {}
406
407 /** {@inheritDoc} */
408 @Override
409 public void removeMarker(Marker marker) {}
410 }