fe8def1639eeea7894702f258dd20efcdfcc4c85
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / location / NamedArea.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9
10 package eu.etaxonomy.cdm.model.location;
11
12
13 import java.util.ArrayList;
14 import java.util.HashMap;
15 import java.util.HashSet;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Set;
19 import java.util.UUID;
20
21 import javax.persistence.Entity;
22 import javax.persistence.FetchType;
23 import javax.persistence.JoinTable;
24 import javax.persistence.ManyToMany;
25 import javax.persistence.ManyToOne;
26 import javax.persistence.Transient;
27 import javax.xml.bind.annotation.XmlAccessType;
28 import javax.xml.bind.annotation.XmlAccessorType;
29 import javax.xml.bind.annotation.XmlElement;
30 import javax.xml.bind.annotation.XmlElementWrapper;
31 import javax.xml.bind.annotation.XmlIDREF;
32 import javax.xml.bind.annotation.XmlRootElement;
33 import javax.xml.bind.annotation.XmlSchemaType;
34 import javax.xml.bind.annotation.XmlSeeAlso;
35 import javax.xml.bind.annotation.XmlType;
36
37 import org.apache.commons.lang.StringUtils;
38 import org.apache.log4j.Logger;
39 import org.hibernate.annotations.Cascade;
40 import org.hibernate.annotations.CascadeType;
41 import org.hibernate.envers.Audited;
42 import org.hibernate.search.annotations.ClassBridge;
43 import org.hibernate.search.annotations.Indexed;
44 import org.hibernate.search.annotations.Parameter;
45
46 import eu.etaxonomy.cdm.common.CdmUtils;
47 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
48 import eu.etaxonomy.cdm.hibernate.search.DefinedTermBaseClassBridge;
49 import eu.etaxonomy.cdm.model.common.CdmBase;
50 import eu.etaxonomy.cdm.model.common.DefaultTermInitializer;
51 import eu.etaxonomy.cdm.model.common.DefinedTermBase;
52 import eu.etaxonomy.cdm.model.common.Language;
53 import eu.etaxonomy.cdm.model.common.OrderedTermBase;
54 import eu.etaxonomy.cdm.model.common.Representation;
55 import eu.etaxonomy.cdm.model.common.TermType;
56 import eu.etaxonomy.cdm.model.common.TermVocabulary;
57 import eu.etaxonomy.cdm.model.common.TimePeriod;
58 import eu.etaxonomy.cdm.model.media.Media;
59
60 /**
61 * @author m.doering
62 * @created 08-Nov-2007 13:06:36
63 */
64 @XmlAccessorType(XmlAccessType.PROPERTY)
65 @XmlType(name = "NamedArea", propOrder = {
66 "kindOf",
67 "generalizationOf",
68 "partOf",
69 "includes",
70 "validPeriod",
71 "shape",
72 "pointApproximation",
73 "countries",
74 "type",
75 "level"
76 })
77 @XmlRootElement(name = "NamedArea")
78 @XmlSeeAlso({
79 Country.class
80 })
81 @Entity
82 @Indexed(index = "eu.etaxonomy.cdm.model.common.DefinedTermBase")
83 @Audited
84 @ClassBridge(impl=DefinedTermBaseClassBridge.class, params={
85 @Parameter(name="includeParentTerms", value="true")
86 })
87 public class NamedArea extends OrderedTermBase<NamedArea> implements Cloneable {
88 private static final long serialVersionUID = 6248434369557403036L;
89 private static final Logger logger = Logger.getLogger(NamedArea.class);
90
91
92 //Continent UUIDs
93 private static final UUID uuidEurope = UUID.fromString("3b69f979-408c-4080-b573-0ad78a315610");
94 private static final UUID uuidAfrica = UUID.fromString("c204c529-d8d2-458f-b939-96f0ebd2cbe8");
95 private static final UUID uuidAsiaTemperate = UUID.fromString("7f4f4f89-3b4c-475d-929f-144109bd8457");
96 private static final UUID uuidAsiaTropical = UUID.fromString("f8039275-d2c0-4753-a1ab-0336642a1499");
97 private static final UUID uuidNAmerica = UUID.fromString("81d8aca3-ddd7-4537-9f2b-5327c95b6e28");
98 private static final UUID uuidSAmerica = UUID.fromString("12b861c9-c922-498c-8b1a-62afc26d19e3");
99 private static final UUID uuidAustralasia = UUID.fromString("a2afdb9a-04a0-434c-9e75-d07dbeb86526");
100 private static final UUID uuidPacific = UUID.fromString("c57adcff-5213-45f0-a5f0-97a9f5c0f1fe");
101 private static final UUID uuidAntarctica = UUID.fromString("71fd9ab7-9b07-4eb6-8e54-c519aff56728");
102
103
104 public static final UUID uuidTdwgAreaVocabulary = UUID.fromString("1fb40504-d1d7-44b0-9731-374fbe6cac77");
105 public static final UUID uuidContinentVocabulary = UUID.fromString("e72cbcb6-58f8-4201-9774-15d0c6abc128");
106 public static final UUID uuidWaterbodyVocabulary = UUID.fromString("35a62b25-f541-4f12-a7c7-17d90dec3e03");
107
108
109 private static final UUID uuidArcticOcean = UUID.fromString("af4271e5-8897-4e6f-9db7-54ea4f28cfc0");
110 private static final UUID uuidAtlanticOcean = UUID.fromString("77e79804-1b17-4c99-873b-933fe216e3da");
111 private static final UUID uuidPacificOcean = UUID.fromString("3d68a327-104c-49d5-a2d8-c71c6600181b");
112 private static final UUID uuidIndianOcean = UUID.fromString("ff744a37-5990-462c-9c20-1e85a9943851");
113 private static final UUID uuidSouthernOcean = UUID.fromString("ef04f363-f67f-4a2c-8d98-110de4c5f654");
114 private static final UUID uuidMediterraneanSea = UUID.fromString("8811a47e-29d6-4455-8f83-8916b78a692f");
115 private static final UUID uuidBlackSea = UUID.fromString("4cb4bbae-9aab-426c-9025-e34f809165af");
116 private static final UUID uuidCaspianSea = UUID.fromString("598fec0e-b93a-4947-a1f3-601e380797f7");
117 private static final UUID uuidRedSea = UUID.fromString("ee69385e-6c80-405c-be6e-974e9fd1e297");
118 private static final UUID uuidPersianGulf = UUID.fromString("8dc16e70-74b8-4143-95cf-a659a319a854");
119
120
121
122 private static Map<String, UUID> tdwgAbbrevMap = null;
123 private static Map<String, UUID> tdwglabelMap = null;
124
125 private static Map<UUID, NamedArea> tdwgTermMap = null;
126 private static Map<UUID, NamedArea> continentMap = null;
127 private static Map<UUID, NamedArea> waterbodyMap = null;
128
129
130 private static Map<UUID, NamedArea> termMap = null;
131
132 public static final NamedArea ARCTICOCEAN () { return waterbodyMap.get(uuidArcticOcean );}
133 public static final NamedArea ATLANTICOCEAN () { return waterbodyMap.get(uuidAtlanticOcean );}
134 public static final NamedArea PACIFICOCEAN () { return waterbodyMap.get(uuidPacificOcean );}
135 public static final NamedArea INDIANOCEAN () { return waterbodyMap.get(uuidIndianOcean );}
136 public static final NamedArea SOUTHERNOCEAN () { return waterbodyMap.get(uuidSouthernOcean );}
137 public static final NamedArea MEDITERRANEANSEA () { return waterbodyMap.get(uuidMediterraneanSea );}
138 public static final NamedArea BLACKSEA () { return waterbodyMap.get(uuidBlackSea );}
139 public static final NamedArea CASPIANSEA () { return waterbodyMap.get(uuidCaspianSea );}
140 public static final NamedArea REDSEA () { return waterbodyMap.get(uuidRedSea );}
141 public static final NamedArea PERSIANGULF () { return waterbodyMap.get(uuidPersianGulf );}
142
143
144 //************************* FACTORY METHODS ****************************************/
145
146 /**
147 * Factory method
148 * @return
149 */
150 public static NamedArea NewInstance(){
151 return new NamedArea();
152 }
153
154 /**
155 * Factory method
156 * @return
157 */
158 public static NamedArea NewInstance(String term, String label, String labelAbbrev){
159 return new NamedArea(term, label, labelAbbrev);
160 }
161
162 //**************************** VARIABLES *******************************/
163
164 //description of time valid context of this area. e.g. year range
165 private TimePeriod validPeriod = TimePeriod.NewInstance();
166
167 //Binary shape definition for user's defined area as polygon
168 @ManyToOne(fetch = FetchType.LAZY)
169 @Cascade(CascadeType.SAVE_UPDATE)
170 private Media shape;
171
172 private Point pointApproximation;
173
174 @ManyToMany(fetch = FetchType.LAZY)
175 @JoinTable(name="DefinedTermBase_Country")
176 private final Set<Country> countries = new HashSet<Country>();
177
178 @ManyToOne(fetch = FetchType.LAZY)
179 private NamedAreaType type;
180
181 @ManyToOne(fetch = FetchType.LAZY)
182 private NamedAreaLevel level;
183
184
185 //********************************** Constructor *******************************************************************/
186
187 //for hibernate use only
188 @Deprecated
189 protected NamedArea() {
190 super(TermType.NamedArea);
191 }
192
193 protected NamedArea(String term, String label, String labelAbbrev) {
194 super(TermType.NamedArea, term, label, labelAbbrev);
195 }
196
197 //********************************* GETTER /SETTER *********************************************/
198
199 @XmlElement(name = "NamedAreaType")
200 @XmlIDREF
201 @XmlSchemaType(name = "IDREF")
202 public NamedAreaType getType(){
203 return this.type;
204 }
205
206 public void setType(NamedAreaType type){
207 this.type = type;
208 }
209
210 @XmlElement(name = "NamedAreaLevel")
211 @XmlIDREF
212 @XmlSchemaType(name = "IDREF")
213 public NamedAreaLevel getLevel(){
214 return this.level;
215 }
216
217 public void setLevel(NamedAreaLevel level){
218 this.level = level;
219 }
220
221 @XmlElement(name = "ValidPeriod")
222 public TimePeriod getValidPeriod(){
223 return this.validPeriod;
224 }
225
226 public void setValidPeriod(TimePeriod validPeriod){
227 this.validPeriod = validPeriod;
228 }
229
230 @XmlElement(name = "Shape")
231 @XmlIDREF
232 @XmlSchemaType(name = "IDREF")
233 public Media getShape(){
234 return this.shape;
235 }
236 public void setShape(Media shape){
237 this.shape = shape;
238 }
239
240 @XmlElementWrapper(name = "Countries")
241 @XmlElement(name = "Country")
242 @XmlIDREF
243 @XmlSchemaType(name = "IDREF")
244 public Set<Country> getCountries() {
245 return countries;
246 }
247
248 public void addCountry(Country country) {
249 this.countries.add(country);
250 }
251
252 public void removeCountry(Country country) {
253 this.countries.remove(country);
254 }
255
256 @XmlElement(name = "PointApproximation")
257 public Point getPointApproximation() {
258 return pointApproximation;
259 }
260 public void setPointApproximation(Point pointApproximation) {
261 this.pointApproximation = pointApproximation;
262 }
263
264 @Override
265 @XmlElement(name = "KindOf", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
266 @XmlIDREF
267 @XmlSchemaType(name = "IDREF")
268 public NamedArea getKindOf(){
269 return super.getKindOf();
270 }
271
272 @Override
273 public void setKindOf(NamedArea kindOf){
274 super.setKindOf(kindOf);
275 }
276
277 @XmlElement(name = "PartOf", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
278 @XmlIDREF
279 @XmlSchemaType(name = "IDREF")
280 @Override
281 public NamedArea getPartOf(){
282 return super.getPartOf();
283 }
284
285 /**
286 * FIXME this method is a workaround for a casting problem in the getPartOf implementation
287 *
288 * the partOf instance variable is typically a proxy object of type DefinedTermBase, thus
289 * does not coincide with the return value of NamedArea and a ClassCastException is thrown.
290 *
291 * It is not clear why this only occurs in the editor and not in the webservice where the same
292 * method gets called and should lead to the same results.
293 *
294 * Seems to be a bigger problem although its origin is buggy behaviour of the javassist implementation.
295 */
296 @Deprecated
297 @Transient
298 public NamedArea getPartOfWorkaround(){
299 Object area = super.getPartOf();
300
301 if(!(area instanceof NamedArea)){
302 area = HibernateProxyHelper.deproxy(area, NamedArea.class);
303 }
304
305 return (NamedArea) area;
306 }
307
308 @Override
309 public void setPartOf(NamedArea partOf){
310 this.partOf = partOf;
311 }
312
313 @Override
314 @XmlElementWrapper(name = "Generalizations", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
315 @XmlElement(name = "GeneralizationOf", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
316 @XmlIDREF
317 @XmlSchemaType(name = "IDREF")
318 public Set<NamedArea> getGeneralizationOf(){
319 return super.getGeneralizationOf();
320 }
321
322 @Override
323 protected void setGeneralizationOf(Set<NamedArea> value){
324 super.setGeneralizationOf(value);
325 }
326
327 @Override
328 @XmlElementWrapper(name = "Includes", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
329 @XmlElement(name = "Include", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
330 @XmlIDREF
331 @XmlSchemaType(name = "IDREF")
332 public Set<NamedArea> getIncludes(){
333 return super.getIncludes();
334 }
335
336 @Override
337 protected void setIncludes(Set<NamedArea> includes) {
338 super.setIncludes(includes);
339 }
340
341 @Override
342 public NamedArea readCsvLine(Class<NamedArea> termClass, List<String> csvLine, Map<UUID,DefinedTermBase> terms, boolean abbrevAsId) {
343 NamedArea newInstance = super.readCsvLine(termClass, csvLine, terms, abbrevAsId);
344
345 String levelString = csvLine.get(6);
346
347 if(levelString != null && levelString.length() != 0) {
348 UUID levelUuid = UUID.fromString(levelString);
349 NamedAreaLevel level = (NamedAreaLevel)terms.get(levelUuid);
350 newInstance.setLevel(level);
351 }
352
353 // String partOfString = csvLine.get(7);
354 //
355 // if(partOfString != null && partOfString.length() != 0) {
356 // UUID partOfUuid = UUID.fromString(partOfString);
357 // NamedArea partOf = (NamedArea)terms.get(partOfUuid);
358 // partOf.addIncludes(newInstance);
359 // }
360 return newInstance;
361 }
362
363 @Override
364 protected int partOfCsvLineIndex(){
365 return 7;
366 }
367
368
369 @Override
370 public void resetTerms(){
371 termMap = null;
372 tdwgAbbrevMap = null;
373 tdwglabelMap = null;
374 tdwgTermMap = null;
375 continentMap = null;
376 waterbodyMap = null;
377 }
378
379 @Deprecated //preliminary, will be removed in future
380 protected static NamedArea getContinentByUuid(UUID uuid){
381 if (continentMap == null){
382 return null;
383 }else{
384 return (NamedArea)continentMap.get(uuid);
385 }
386 }
387
388 @Deprecated //preliminary, will be removed in future
389 protected static NamedArea getWaterbodyByUuid(UUID uuid){
390 if (waterbodyMap == null){
391 return null;
392 }else{
393 return (NamedArea)waterbodyMap.get(uuid);
394 }
395 }
396
397 @Deprecated //preliminary, will be removed in future
398 protected static NamedArea getTdwgTermByUuid(UUID uuid){
399 if (tdwgTermMap == null){
400 DefaultTermInitializer vocabularyStore = new DefaultTermInitializer();
401 vocabularyStore.initialize();
402 }
403 return tdwgTermMap.get(uuid);
404 }
405
406 @Deprecated //preliminary, will be removed in future
407 public static NamedArea getAreaByTdwgAbbreviation(String tdwgAbbreviation){
408 if (tdwgAbbrevMap == null){
409 initTdwgMaps();
410 }
411 UUID uuid = tdwgAbbrevMap.get(tdwgAbbreviation);
412 if (uuid == null){
413 logger.info("Unknown TDWG area: " + CdmUtils.Nz(tdwgAbbreviation));
414 return null;
415 }
416 return NamedArea.getTdwgTermByUuid(uuid);
417 }
418
419 @Deprecated //preliminary, will be removed in future
420 public static NamedArea getAreaByTdwgLabel(String tdwgLabel){
421 if (tdwglabelMap == null){
422 initTdwgMaps();
423 }
424 tdwgLabel = tdwgLabel.toLowerCase();
425 UUID uuid = tdwglabelMap.get(tdwgLabel);
426 if (uuid == null){
427 logger.info("Unknown TDWG area: " + CdmUtils.Nz(tdwgLabel));
428 return null;
429 }
430 return NamedArea.getTdwgTermByUuid(uuid);
431 }
432
433 @Deprecated //preliminary, will be removed in future
434 public static boolean isTdwgAreaLabel(String label){
435 label = (label == null? null : label.toLowerCase());
436 if (tdwglabelMap.containsKey(label)){
437 return true;
438 }else{
439 return false;
440 }
441 }
442
443 @Deprecated //preliminary, will be removed in future
444 public static boolean isTdwgAreaAbbreviation(String abbrev){
445 if (tdwgAbbrevMap.containsKey(abbrev)){
446 return true;
447 }else{
448 return false;
449 }
450 }
451
452 public static final NamedArea EUROPE(){
453 return getContinentByUuid(uuidEurope);
454 }
455
456 public static final NamedArea AFRICA(){
457 return getContinentByUuid(uuidAfrica);
458 }
459
460 public static final NamedArea ASIA_TEMPERATE(){
461 return getContinentByUuid(uuidAsiaTemperate);
462 }
463
464 public static final NamedArea ASIA_TROPICAL(){
465 return getContinentByUuid(uuidAsiaTropical);
466 }
467
468 public static final NamedArea NORTH_AMERICA(){
469 return getContinentByUuid(uuidNAmerica);
470 }
471
472 public static final NamedArea ANTARCTICA(){
473 return getContinentByUuid(uuidAntarctica);
474 }
475
476 public static final NamedArea SOUTH_AMERICA(){
477 return getContinentByUuid(uuidSAmerica);
478 }
479
480 public static final NamedArea AUSTRALASIA(){
481 return getContinentByUuid(uuidAustralasia);
482 }
483
484 public static final NamedArea PACIFIC(){
485 return getContinentByUuid(uuidPacific);
486 }
487
488
489 protected void setDefaultContinentTerms(TermVocabulary<NamedArea> termVocabulary) {
490 continentMap = new HashMap<UUID, NamedArea>();
491 for (NamedArea term : termVocabulary.getTerms()){
492 continentMap.put(term.getUuid(), (NamedArea)term); //TODO casting
493 }
494 }
495
496 protected void setDefaultWaterbodyTerms(TermVocabulary<NamedArea> termVocabulary) {
497 waterbodyMap = new HashMap<UUID, NamedArea>();
498 for (NamedArea term : termVocabulary.getTerms()){
499 waterbodyMap.put(term.getUuid(), (NamedArea)term); //TODO casting
500 }
501 }
502
503 protected void setTdwgDefaultTerms(TermVocabulary<NamedArea> tdwgTermVocabulary) {
504 tdwgTermMap = new HashMap<UUID, NamedArea>();
505 for (NamedArea term : tdwgTermVocabulary.getTerms()){
506 tdwgTermMap.put(term.getUuid(), term); //TODO casting
507 addTdwgArea(term);
508 }
509
510 }
511
512 protected static void addTdwgArea(NamedArea area){
513 if (area == null){
514 logger.warn("tdwg area is null");
515 return;
516 }
517 Language lang = Language.DEFAULT();
518 Representation representation = area.getRepresentation(lang);
519 String tdwgAbbrevLabel = representation.getAbbreviatedLabel();
520 String tdwgLabel = representation.getLabel().toLowerCase();
521 if (tdwgAbbrevLabel == null){
522 logger.warn("tdwgLabel = null");
523 return;
524 }
525 //init map
526 if (tdwgAbbrevMap == null){
527 tdwgAbbrevMap = new HashMap<String, UUID>();
528 }
529 if (tdwglabelMap == null){
530 tdwglabelMap = new HashMap<String, UUID>();
531 }
532 //add to map
533 tdwgAbbrevMap.put(tdwgAbbrevLabel, area.getUuid());
534 tdwglabelMap.put(tdwgLabel, area.getUuid());
535 //add type
536 area.setType(NamedAreaType.ADMINISTRATION_AREA());
537 //add level
538 if (tdwgAbbrevLabel.trim().length()== 1){
539 area.setLevel(NamedAreaLevel.TDWG_LEVEL1());
540 }else if (tdwgAbbrevLabel.trim().length()== 2){
541 area.setLevel(NamedAreaLevel.TDWG_LEVEL2());
542 }else if (tdwgAbbrevLabel.trim().length()== 3){
543 area.setLevel(NamedAreaLevel.TDWG_LEVEL3());
544 }else if (tdwgAbbrevLabel.trim().length()== 6){
545 area.setLevel(NamedAreaLevel.TDWG_LEVEL4());
546 }else {
547 logger.warn("Unknown TDWG Level " + tdwgAbbrevLabel + "! Unvalid string length (" + tdwgAbbrevLabel.length() +")");
548 }
549 }
550
551 private static void initTdwgMaps(){
552 tdwglabelMap = new HashMap<String, UUID>();
553 tdwgAbbrevMap = new HashMap<String, UUID>();
554 }
555
556
557
558 @Override
559 protected void setDefaultTerms(TermVocabulary<NamedArea> termVocabulary) {
560 if (termVocabulary.getUuid().equals(this.uuidTdwgAreaVocabulary)){
561 this.setTdwgDefaultTerms(termVocabulary);
562 }else if (termVocabulary.getUuid().equals(this.uuidContinentVocabulary)){
563 this.setDefaultContinentTerms(termVocabulary);
564 }else if (termVocabulary.getUuid().equals(this.uuidWaterbodyVocabulary)){
565 this.setDefaultWaterbodyTerms(termVocabulary);
566 }else{
567 termMap = new HashMap<UUID, NamedArea>();
568 for (NamedArea term : termVocabulary.getTerms()){
569 termMap.put(term.getUuid(), term);
570 }
571 }
572 }
573
574 // ************** Hierarchie List ****************************
575
576 /**
577 * This method returns a sorted tree structure which sorts areas by it's level and within the same level
578 * alphabetically (TODO to be tested).
579 * The structure returned is a tree with alternating nodes that represent an area and an areaLevel.
580 * This way also areas that have children belonging to different levels can be handled.<BR>
581 * The root node is always an empty area node which holds the list of top level areaLevels.
582 * AreaLevels with no level defined are handled as if they have a separate level (level="null").
583 *
584 * There is a somehow similar implementation in {@link eu.etaxonomy.cdm.api.service.DistributionTree}
585 *
586 * @param areaList
587 * @return
588 */
589 public static NamedAreaNode getHiearchieList(List<NamedArea> areaList){
590 NamedAreaNode result = new NamedAreaNode();
591 for (NamedArea area : areaList){
592 List<NamedArea> areaHierarchie = area.getAllLevelList();
593 mergeIntoResult(result, areaHierarchie);
594 }
595 return result;
596 }
597
598
599 public static class LevelNode {
600 NamedAreaLevel level;
601 List<NamedAreaNode> areaList = new ArrayList<NamedAreaNode>();
602
603 public NamedAreaNode add(NamedArea area) {
604 NamedAreaNode node = new NamedAreaNode();
605 node.area = area;
606 areaList.add(node);
607 return node;
608
609 }
610
611 public NamedAreaNode getNamedAreaNode(NamedArea area) {
612 for (NamedAreaNode node : areaList) {
613 if (node.area.equals(area)) {
614 return node;
615 }
616 }
617 return null;
618 }
619
620 ///****************** toString ***********************************************/
621
622 @Override
623 public String toString() {
624 return toString(false, 0);
625 }
626 public String toString(boolean recursive, int identation) {
627 String result = level == null? "" :level.getTitleCache();
628 if (recursive == false){
629 return result;
630 }else{
631 int areaSize = this.areaList.size();
632 if (areaSize > 0){
633 result = "\n" + StringUtils.leftPad("", identation) + result + "[";
634 }
635 boolean isFirst = true;
636 for (NamedAreaNode level: this.areaList){
637 if (isFirst){
638 isFirst = false;
639 }else{
640 result += ",";
641 }
642 result += level.toString(recursive, identation+1);
643 }
644 if (areaSize > 0){
645 result += "]";
646
647 }
648 return result;
649 }
650 }
651
652 }
653
654 public static class NamedAreaNode {
655 NamedArea area;
656 List<LevelNode> levelList = new ArrayList<LevelNode>();
657
658 public LevelNode getLevelNode(NamedAreaLevel level) {
659 for (LevelNode node : levelList) {
660 if (node.level != null && node.level.equals(level)) {
661 return node;
662 }
663 }
664 return null;
665 }
666
667 public List<NamedAreaNode> getList(NamedAreaLevel level) {
668 LevelNode node = getLevelNode(level);
669 if (node == null) {
670 return new ArrayList<NamedAreaNode>();
671 } else {
672 return node.areaList;
673 }
674 };
675
676 public boolean contains(NamedAreaLevel level) {
677 if (getList(level).size() > 0) {
678 return true;
679 } else {
680 return false;
681 }
682 }
683
684 public LevelNode add(NamedAreaLevel level) {
685 LevelNode node = new LevelNode();
686 node.level = level;
687 levelList.add(node);
688 return node;
689 }
690
691 @Override
692 public String toString() {
693 return toString(false, 0);
694 }
695
696 public String toString(boolean recursive, int identation) {
697 String result = "";
698 if (area != null) {
699 result = area.getTitleCache();
700 }
701 if (recursive){
702 int levelSize = this.levelList.size();
703 if (levelSize > 0){
704 result = "\n" + StringUtils.leftPad("", identation) + result + "[";
705 }
706 boolean isFirst = true;
707 for (LevelNode level: this.levelList){
708 if (isFirst){
709 isFirst = false;
710 }else{
711 result += ";";
712 }
713 result += level.toString(recursive, identation+1);
714 }
715 if (levelSize > 0){
716 result += "]";
717
718 }
719 return result;
720 }else{
721 int levelSize = this.levelList.size();
722 return result + "[" + levelSize + " sublevel(s)]";
723 }
724 }
725 }
726
727 private static void mergeIntoResult(NamedAreaNode root, List<NamedArea> areaHierarchie) {
728 if (areaHierarchie.isEmpty()) {
729 return;
730 }
731 NamedArea highestArea = areaHierarchie.get(0);
732 NamedAreaLevel level = highestArea.getLevel();
733 NamedAreaNode namedAreaNode;
734 if (! root.contains(level)) {
735 LevelNode node = root.add(level);
736 namedAreaNode = node.add(highestArea);
737 //NEW
738 // root.area = highestArea;
739 } else {
740 LevelNode levelNode = root.getLevelNode(level);
741 namedAreaNode = levelNode.getNamedAreaNode(highestArea);
742 if (namedAreaNode == null) {
743 namedAreaNode = levelNode.add(highestArea);
744 }
745 }
746 List<NamedArea> newList = areaHierarchie.subList(1, areaHierarchie.size());
747 mergeIntoResult(namedAreaNode, newList);
748
749 }
750
751 @Transient
752 public List<NamedArea> getAllLevelList() {
753 List<NamedArea> result = new ArrayList<NamedArea>();
754 NamedArea copyArea = this;
755 result.add(copyArea);
756 while (copyArea.getPartOf() != null) {
757 copyArea = copyArea.getPartOf();
758 result.add(0, copyArea);
759 }
760 return result;
761 }
762
763 // ******************* toString **********************************/
764
765 @Override
766 public String toString(){
767 String result, label, level = "";
768
769 if (this.level != null){
770 level = this.level.getLabel();
771 }else{
772 level = "no level";
773 }
774 label = this.getLabel();
775 result = "[" + level + ", " + label + "]";
776
777 return result;
778 }
779
780
781
782 /**
783 * Returns the label of the named area together with the area level label and the abbreviated label.
784 * This is kind of a formatter method which may be moved to a better place in future.
785 * @param namedArea the area
786 * @param language the preferred language
787 * @return null if namedArea == null, the labelWithLevel otherwise
788 */
789 public static String labelWithLevel(NamedArea namedArea, Language language) {
790 if (namedArea == null){
791 return null;
792 }
793 NamedArea area = CdmBase.deproxy(namedArea, NamedArea.class);
794
795 StringBuilder title = new StringBuilder();
796 Representation representation = area.getPreferredRepresentation(language);
797 if (representation != null){
798 String areaString = getPreferredAreaLabel(namedArea, representation);
799
800 title.append(areaString);
801 if (area.getLevel() == null){
802 title.append(" - ");
803 title.append(area.getClass().getSimpleName());
804 }else{
805 title.append(" - ");
806 Representation levelRepresentation = area.getLevel().getPreferredRepresentation(language);
807 String levelString = getPreferredAreaLabel(area.getLevel(), levelRepresentation);
808 title.append(levelString);
809 }
810 }
811 return title.toString();
812 }
813
814 /**
815 * @param definedTerm
816 * @param representation
817 * @return
818 */
819 private static String getPreferredAreaLabel(DefinedTermBase<?> definedTerm, Representation representation) {
820 String areaString = null;
821 if (representation != null){
822 areaString = representation.getLabel();
823 if (StringUtils.isBlank(areaString)){
824 areaString = representation.getAbbreviatedLabel();
825 }
826 if (StringUtils.isBlank(areaString)){
827 areaString = representation.getText();
828 }
829 }
830 if (StringUtils.isBlank(areaString)){
831 areaString = definedTerm == null ? null : definedTerm.getTitleCache();
832 }
833 if (StringUtils.isBlank(areaString)){
834 areaString = "no title";
835 }
836 return areaString;
837 }
838
839 //*********************************** CLONE *****************************************/
840
841 /**
842 * Clones <i>this</i> NamedArea. This is a shortcut that enables to create
843 * a new instance that differs only slightly from <i>this</i> NamedArea by
844 * modifying only some of the attributes.
845 *
846 * @see eu.etaxonomy.cdm.model.common.OrderedTermBase#clone()
847 * @see java.lang.Object#clone()
848 */
849 @Override
850 public Object clone() {
851 NamedArea result;
852
853 result = (NamedArea)super.clone();
854 //no changes to level, pointApproximation, shape, type, validPeriod and countries
855 return result;
856
857 }
858
859
860 }