Project

General

Profile

Download (26.8 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2017 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
package eu.etaxonomy.cdm.api.service.name;
10

    
11
import java.util.ArrayList;
12
import java.util.Arrays;
13
import java.util.Collection;
14
import java.util.Collections;
15
import java.util.Comparator;
16
import java.util.HashMap;
17
import java.util.LinkedHashMap;
18
import java.util.LinkedList;
19
import java.util.List;
20
import java.util.Map;
21
import java.util.Optional;
22
import java.util.Set;
23

    
24
import org.hibernate.search.hcore.util.impl.HibernateHelper;
25

    
26
import eu.etaxonomy.cdm.api.facade.DerivedUnitFacadeCacheStrategy;
27
import eu.etaxonomy.cdm.api.service.dto.EntityReference;
28
import eu.etaxonomy.cdm.api.service.dto.TypedEntityReference;
29
import eu.etaxonomy.cdm.api.service.exception.RegistrationValidationException;
30
import eu.etaxonomy.cdm.model.common.CdmBase;
31
import eu.etaxonomy.cdm.model.common.TermVocabulary;
32
import eu.etaxonomy.cdm.model.common.VersionableEntity;
33
import eu.etaxonomy.cdm.model.name.NameTypeDesignation;
34
import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;
35
import eu.etaxonomy.cdm.model.name.TaxonName;
36
import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
37
import eu.etaxonomy.cdm.model.name.TypeDesignationStatusBase;
38
import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
39
import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
40
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
41
/**
42
 * Manages a collection of {@link TypeDesignationBase TypeDesignations} for the same typified name.
43
 *
44
 * Type designations are ordered by the base type which is a {@link TaxonName} for {@link NameTypeDesignation NameTypeDesignations} or
45
 * in case of {@link SpecimenTypeDesignation SpecimenTypeDesignations} the  associate {@link FieldUnit} or the {@link DerivedUnit}
46
 * if the former is missing. The type designations per base type are furthermore ordered by the {@link TypeDesignationStatusBase}.
47
 *
48
 * The TypeDesignationSetManager also provides string representations of the whole ordered set of all
49
 * {@link TypeDesignationBase TypeDesignations} and of the TypeDesignationWorkingSets:
50
 * <ul>
51
 *  <li>{@link #print()})
52
 *  <li>{@link #getOrderdTypeDesignationWorkingSets()} ... {@link TypeDesignationWorkingSet#getRepresentation()}
53
 * </ul>
54
 * Prior using the representations you need to trigger their generation by calling {@link #buildString()}
55
 *
56
 * @author a.kohlbecker
57
 * @since Mar 10, 2017
58
 *
59
 */
60
public class TypeDesignationSetManager {
61

    
62
    enum NameTypeBaseEntityType{
63

    
64
        NAME_TYPE_DESIGNATION,
65
        TYPE_NAME;
66

    
67
    }
68

    
69
    private static final String TYPE_STATUS_SEPARATOR = "; ";
70

    
71
    private static final String TYPE_SEPARATOR = "; ";
72

    
73
    private static final String TYPE_DESIGNATION_SEPARATOR = ", ";
74

    
75
    private Collection<TypeDesignationBase> typeDesignations;
76

    
77
    private NameTypeBaseEntityType nameTypeBaseEntityType = NameTypeBaseEntityType.NAME_TYPE_DESIGNATION;
78

    
79
    /**
80
     * Groups the EntityReferences for each of the TypeDesignations by the according TypeDesignationStatus.
81
     * The TypeDesignationStatusBase keys are already ordered by the term order defined in the vocabulary.
82
     */
83
    private LinkedHashMap<TypedEntityReference, TypeDesignationWorkingSet> orderedByTypesByBaseEntity;
84

    
85
    private EntityReference typifiedNameRef;
86

    
87
    private TaxonName typifiedName;
88

    
89
    private String finalString = null;
90

    
91
    final NullTypeDesignationStatus NULL_STATUS = new NullTypeDesignationStatus();
92

    
93
    private List<String> probelms = new ArrayList<>();
94

    
95
    private boolean printCitation = false;
96

    
97
    /**
98
     * @param containgEntity
99
     * @param taxonName
100
     * @throws RegistrationValidationException
101
     *
102
     */
103
    public TypeDesignationSetManager(Collection<TypeDesignationBase> typeDesignations) throws RegistrationValidationException {
104
        this.typeDesignations = typeDesignations;
105
        findTypifiedName();
106
        mapAndSort();
107
    }
108

    
109
    /**
110
     * @param typifiedName2
111
     */
112
    public TypeDesignationSetManager(TaxonName typifiedName) {
113
        this.typeDesignations = new ArrayList<>();
114
        this.typifiedNameRef = new EntityReference(typifiedName.getUuid(), typifiedName.getTitleCache());
115
    }
116

    
117
    /**
118
     * Add one or more TypeDesignations to the manager. This causes re-grouping and re-ordering
119
     * of all managed TypeDesignations.
120
     *
121
     * @param containgEntity
122
     * @param typeDesignations
123
     */
124
    public void addTypeDesigations(CdmBase containgEntity, TypeDesignationBase ... typeDesignations){
125
       this.typeDesignations.addAll(Arrays.asList(typeDesignations));
126
       mapAndSort();
127
    }
128

    
129
    /**
130
     * Groups and orders all managed TypeDesignations.
131
     *
132
     * @param containgEntity
133
     */
134
    protected void mapAndSort() {
135
        finalString = null;
136
        Map<TypedEntityReference, TypeDesignationWorkingSet> byBaseEntityByTypeStatus = new HashMap<>();
137
        this.typeDesignations.forEach(td -> mapTypeDesignation(byBaseEntityByTypeStatus, td));
138
        orderedByTypesByBaseEntity = orderByTypeByBaseEntity(byBaseEntityByTypeStatus);
139
    }
140

    
141

    
142
    /**
143
     *
144
     * @param containgEntity
145
     * @param byBaseEntityByTypeStatus
146
     * @param td
147
     */
148
    private void mapTypeDesignation(Map<TypedEntityReference, TypeDesignationWorkingSet> byBaseEntityByTypeStatus,
149
            TypeDesignationBase<?> td){
150

    
151
        TypeDesignationStatusBase<?> status = td.getTypeStatus();
152

    
153
        try {
154
            final VersionableEntity baseEntity = baseEntity(td);
155
            final TypedEntityReference<VersionableEntity> baseEntityReference = makeEntityReference(baseEntity);
156

    
157
            EntityReference typeDesignationEntityReference = new EntityReference(td.getUuid(), stringify(td));
158

    
159
            TypeDesignationWorkingSet typedesignationWorkingSet;
160
            if(!byBaseEntityByTypeStatus.containsKey(baseEntityReference)){
161
                byBaseEntityByTypeStatus.put(baseEntityReference, new TypeDesignationWorkingSet(baseEntity, baseEntityReference));
162
            }
163

    
164
            typedesignationWorkingSet = byBaseEntityByTypeStatus.get(baseEntityReference);
165
            typedesignationWorkingSet.insert(status, typeDesignationEntityReference);
166
        } catch (DataIntegrityException e){
167
            probelms.add(e.getMessage());
168
        }
169
    }
170

    
171
    /**
172
     * @param td
173
     * @return
174
     * @throws DataIntegrityException
175
     */
176
    protected VersionableEntity baseEntity(TypeDesignationBase<?> td) throws DataIntegrityException {
177

    
178
        VersionableEntity baseEntity = null;
179
        if(td  instanceof SpecimenTypeDesignation){
180
            SpecimenTypeDesignation std = (SpecimenTypeDesignation) td;
181
            FieldUnit fu = findFieldUnit(std);
182
            if(fu != null){
183
                baseEntity = fu;
184
            } else if(((SpecimenTypeDesignation) td).getTypeSpecimen() != null){
185
                baseEntity = ((SpecimenTypeDesignation) td).getTypeSpecimen();
186
            }
187
        } else if(td instanceof NameTypeDesignation){
188
            if(nameTypeBaseEntityType == NameTypeBaseEntityType.NAME_TYPE_DESIGNATION){
189
                baseEntity = td;
190
            } else {
191
                // only other option is TaxonName
192
                baseEntity = ((NameTypeDesignation)td).getTypeName();
193
            }
194
        }
195
        if(baseEntity == null) {
196
            throw new DataIntegrityException("Incomplete TypeDesignation, no type missin in " + td.toString());
197
        }
198
        return baseEntity;
199
    }
200

    
201
    /**
202
     * @param td
203
     * @return
204
     */
205
    protected TypedEntityReference<VersionableEntity> makeEntityReference(VersionableEntity baseEntity) {
206

    
207
        baseEntity = (VersionableEntity) HibernateHelper.unproxy(baseEntity);
208
        String label = "";
209
        if(baseEntity  instanceof FieldUnit){
210
                label = ((FieldUnit)baseEntity).getTitleCache();
211
        }
212

    
213
        TypedEntityReference<VersionableEntity> baseEntityReference = new TypedEntityReference(baseEntity.getClass(), baseEntity.getUuid(), label);
214

    
215
        return baseEntityReference;
216
    }
217

    
218

    
219
    private LinkedHashMap<TypedEntityReference, TypeDesignationWorkingSet> orderByTypeByBaseEntity(
220
            Map<TypedEntityReference, TypeDesignationWorkingSet> stringsByTypeByBaseEntity){
221

    
222
       // order the FieldUnit TypeName keys
223
       List<TypedEntityReference> baseEntityKeyList = new LinkedList<>(stringsByTypeByBaseEntity.keySet());
224
       Collections.sort(baseEntityKeyList, new Comparator<TypedEntityReference>(){
225
        /**
226
         * Sorts the base entities (TypedEntityReference) in the following order:
227
         *
228
         * 1. FieldUnits
229
         * 2. DerivedUnit (in case of missing FieldUnit we expect the base type to be DerivedUnit)
230
         * 3. NameType
231
         *
232
         * {@inheritDoc}
233
         */
234
        @Override
235
        public int compare(TypedEntityReference o1, TypedEntityReference o2) {
236

    
237
            Class type1 = o1.getType();
238
            Class type2 = o2.getType();
239

    
240
            if(!type1.equals(type2)) {
241
                if(type1.equals(FieldUnit.class) || type2.equals(FieldUnit.class)){
242
                    // FieldUnits first
243
                    return type1.equals(FieldUnit.class) ? -1 : 1;
244
                } else {
245
                    // name types last (in case of missing FieldUnit we expect the base type to be DerivedUnit which comes into the middle)
246
                    return type2.equals(TaxonName.class) || type2.equals(NameTypeDesignation.class) ? -1 : 1;
247
                }
248
            } else {
249
                return o1.getLabel().compareTo(o2.getLabel());
250
            }
251
        }});
252

    
253
       // new LinkedHashMap for the ordered FieldUnitOrTypeName keys
254
       LinkedHashMap<TypedEntityReference, TypeDesignationWorkingSet> stringsOrderedbyBaseEntityOrderdByType = new LinkedHashMap<>(stringsByTypeByBaseEntity.size());
255

    
256
       for(TypedEntityReference baseEntityRef : baseEntityKeyList){
257

    
258
           TypeDesignationWorkingSet typeDesignationWorkingSet = stringsByTypeByBaseEntity.get(baseEntityRef);
259
           // order the TypeDesignationStatusBase keys
260
            List<TypeDesignationStatusBase<?>> keyList = new LinkedList<>(typeDesignationWorkingSet.keySet());
261
            Collections.sort(keyList, new Comparator<TypeDesignationStatusBase>() {
262
                @SuppressWarnings("unchecked")
263
                @Override
264
                public int compare(TypeDesignationStatusBase o1, TypeDesignationStatusBase o2) {
265
                    // fix inverted order of cdm terms by -1*
266
                    if(o1 == null && o2 == null || o1 instanceof NullTypeDesignationStatus && o2 instanceof NullTypeDesignationStatus){
267
                        return 0;
268
                    }
269
                    if(o1 == null || o1 instanceof NullTypeDesignationStatus){
270
                        return -1;
271
                    }
272

    
273
                    if(o2 == null || o2 instanceof NullTypeDesignationStatus){
274
                        return 1;
275
                    }
276
                    return -1 * o1.compareTo(o2);
277
                }
278
            });
279
            // new LinkedHashMap for the ordered TypeDesignationStatusBase keys
280
            TypeDesignationWorkingSet orderedStringsByOrderedTypes = new TypeDesignationWorkingSet(
281
                    typeDesignationWorkingSet.getBaseEntity(),
282
                    baseEntityRef);
283
            keyList.forEach(key -> orderedStringsByOrderedTypes.put(key, typeDesignationWorkingSet.get(key)));
284
            stringsOrderedbyBaseEntityOrderdByType.put(baseEntityRef, orderedStringsByOrderedTypes);
285
       }
286

    
287
        return stringsOrderedbyBaseEntityOrderdByType;
288
    }
289

    
290
    /*
291
    private LinkedHashMap<TypedEntityReference, LinkedHashMap<String, Collection<EntityReference>>> buildOrderedRepresentations(){
292

    
293
        orderedStringsByOrderedTypes.keySet().forEach(
294
                key -> orderedRepresentations.put(
295
                        getTypeDesignationStytusLabel(key),
296
                        orderedStringsByOrderedTypes.get(key))
297
                );
298
        return orderedRepresentations;
299
    }
300
*/
301

    
302
    public TypeDesignationSetManager buildString(){
303

    
304
        if(finalString == null){
305

    
306
            finalString = "";
307
            if(getTypifiedNameCache() != null){
308
                finalString += getTypifiedNameCache() + " ";
309
            }
310

    
311
            int typeCount = 0;
312
            if(orderedByTypesByBaseEntity != null){
313
                for(TypedEntityReference baseEntityRef : orderedByTypesByBaseEntity.keySet()) {
314
                    StringBuilder sb = new StringBuilder();
315
                    if(typeCount++ > 0){
316
                        sb.append(TYPE_SEPARATOR);
317
                    }
318
                    boolean isNameTypeDesignation = false;
319
                    if(SpecimenOrObservationBase.class.isAssignableFrom(baseEntityRef.getType())){
320
                        sb.append("Type: ");
321
                    } else {
322
                        sb.append("NameType: ");
323
                        isNameTypeDesignation = true;
324
                    }
325
                    if(!baseEntityRef.getLabel().isEmpty()){
326
                        sb.append(baseEntityRef.getLabel()).append(" ");
327
                    }
328
                    TypeDesignationWorkingSet typeDesignationWorkingSet = orderedByTypesByBaseEntity.get(baseEntityRef);
329
                    if(!isNameTypeDesignation ){
330
                        sb.append("(");
331
                    }
332
                    int typeStatusCount = 0;
333
                    for(TypeDesignationStatusBase<?> typeStatus : typeDesignationWorkingSet.keySet()) {
334
                        if(typeStatusCount++  > 0){
335
                            sb.append(TYPE_STATUS_SEPARATOR);
336
                        }
337
                        boolean isPlural = typeDesignationWorkingSet.get(typeStatus).size() > 1;
338
                        if(!typeStatus.equals(NULL_STATUS)) {
339
                            sb.append(typeStatus.getLabel());
340
                            if(isPlural){
341
                                sb.append("s: ");
342
                            } else {
343
                                sb.append(", ");
344
                            }
345
                        }
346
                        int typeDesignationCount = 0;
347
                        for(EntityReference typeDesignationEntityReference : typeDesignationWorkingSet.get(typeStatus)) {
348
                            if(typeDesignationCount++  > 0){
349
                                sb.append(TYPE_DESIGNATION_SEPARATOR);
350
                            }
351
                            sb.append(typeDesignationEntityReference.getLabel());
352
                        }
353
                    }
354
                    if(!isNameTypeDesignation ){
355
                        sb.append(")");
356
                    }
357
                    typeDesignationWorkingSet.setRepresentation(sb.toString());
358
                    finalString += typeDesignationWorkingSet.getRepresentation();
359
                }
360
            }
361
        }
362
        return this;
363
    }
364

    
365
    /**
366
     * FIXME use the validation framework validators and to store the validation problems!!!
367
     *
368
     * @return
369
     * @throws RegistrationValidationException
370
     */
371
    private void findTypifiedName() throws RegistrationValidationException {
372

    
373
        List<String> problems = new ArrayList<>();
374

    
375
        TaxonName typifiedName = null;
376

    
377
        for(TypeDesignationBase<?> typeDesignation : typeDesignations){
378
            typeDesignation.getTypifiedNames();
379
            if(typeDesignation.getTypifiedNames().isEmpty()){
380

    
381
                //TODO instead throw RegistrationValidationException()
382
                problems.add("Missing typifiedName in " + typeDesignation.toString());
383
                continue;
384
            }
385
            if(typeDesignation.getTypifiedNames().size() > 1){
386
              //TODO instead throw RegistrationValidationException()
387
                problems.add("Multiple typifiedName in " + typeDesignation.toString());
388
                continue;
389
            }
390
            if(typifiedName == null){
391
                // remember
392
                typifiedName = typeDesignation.getTypifiedNames().iterator().next();
393
            } else {
394
                // compare
395
                TaxonName otherTypifiedName = typeDesignation.getTypifiedNames().iterator().next();
396
                if(!typifiedName.getUuid().equals(otherTypifiedName.getUuid())){
397
                  //TODO instead throw RegistrationValidationException()
398
                    problems.add("Multiple typifiedName in " + typeDesignation.toString());
399
                }
400
            }
401

    
402
        }
403
        if(!problems.isEmpty()){
404
            // FIXME use the validation framework
405
            throw new RegistrationValidationException("Inconsistent type designations", problems);
406
        }
407

    
408
        if(typifiedName != null){
409
            // ON SUCCESS -------------------
410
            this.typifiedName = typifiedName;
411
            this.typifiedNameRef = new EntityReference(typifiedName.getUuid(), typifiedName.getTitleCache());
412

    
413
        }
414
    }
415

    
416

    
417
    /**
418
     * @return the title cache of the typifying name or <code>null</code>
419
     */
420
    public String getTypifiedNameCache() {
421
        if(typifiedNameRef != null){
422
            return typifiedNameRef.getLabel();
423
        }
424
        return null;
425
    }
426

    
427
    /**
428
     * @return the title cache of the typifying name or <code>null</code>
429
     */
430
    public EntityReference getTypifiedNameRef() {
431

    
432
       return typifiedNameRef;
433
    }
434

    
435
    /**
436
     * @return
437
     */
438
    public Collection<TypeDesignationBase> getTypeDesignations() {
439
        return typeDesignations;
440
    }
441

    
442
    /**
443
     * @param ref
444
     * @return
445
     */
446
    public TypeDesignationBase findTypeDesignation(EntityReference typeDesignationRef) {
447
        for(TypeDesignationBase td : typeDesignations){
448
            if(td.getUuid().equals(typeDesignationRef.getUuid())){
449
                return td;
450
            }
451
        }
452
        // TODO Auto-generated method stub
453
        return null;
454
    }
455

    
456

    
457
    public LinkedHashMap<TypedEntityReference, TypeDesignationWorkingSet> getOrderdTypeDesignationWorkingSets() {
458
        return orderedByTypesByBaseEntity;
459
    }
460

    
461
    /**
462
     * @param td
463
     * @return
464
     */
465
    private String stringify(TypeDesignationBase td) {
466

    
467
        if(td instanceof NameTypeDesignation){
468
            return stringify((NameTypeDesignation)td);
469
        } else {
470
            return stringify((SpecimenTypeDesignation)td, false);
471
        }
472
    }
473

    
474

    
475
    /**
476
     * @param td
477
     * @return
478
     */
479
    protected String stringify(NameTypeDesignation td) {
480

    
481
        StringBuffer sb = new StringBuffer();
482

    
483
        if(td.getTypeName() != null){
484
            sb.append(td.getTypeName().getTitleCache());
485
        }
486
        if(td.getCitation() != null){
487
            sb.append(" ").append(td.getCitation().getTitleCache());
488
            if(td.getCitationMicroReference() != null){
489
                sb.append(":").append(td.getCitationMicroReference());
490
            }
491
        }
492
        if(td.isNotDesignated()){
493
            sb.append(" not designated");
494
        }
495
        if(td.isRejectedType()){
496
            sb.append(" rejected");
497
        }
498
        if(td.isConservedType()){
499
            sb.append(" conserved");
500
        }
501
        return sb.toString();
502
    }
503

    
504
    /**
505
     * @param td
506
     * @return
507
     */
508
    private String stringify(SpecimenTypeDesignation td, boolean useFullTitleCache) {
509
        String  result = "";
510

    
511
        if(useFullTitleCache){
512
            if(td.getTypeSpecimen() != null){
513
                String nameTitleCache = td.getTypeSpecimen().getTitleCache();
514
                if(getTypifiedNameCache() != null){
515
                    nameTitleCache = nameTitleCache.replace(getTypifiedNameCache(), "");
516
                }
517
                result += nameTitleCache;
518
            }
519
        } else {
520
            if(td.getTypeSpecimen() != null){
521
                DerivedUnit du = td.getTypeSpecimen();
522
                if(du.isProtectedTitleCache()){
523
                    result += du.getTitleCache();
524
                } else {
525
                    DerivedUnitFacadeCacheStrategy cacheStrategy = new DerivedUnitFacadeCacheStrategy();
526
                    result += cacheStrategy.getTitleCache(du, true);
527
                }
528
            }
529
        }
530

    
531
        if(isPrintCitation() && td.getCitation() != null){
532
            if(td.getCitation().getAbbrevTitle() != null){
533
                result += " " + td.getCitation().getAbbrevTitle();
534
            } else {
535
                result += " " + td.getCitation().getTitleCache();
536
            }
537
            if(td.getCitationMicroReference() != null){
538
                result += " :" + td.getCitationMicroReference();
539
            }
540
        }
541
        if(td.isNotDesignated()){
542
            result += " not designated";
543
        }
544

    
545
        return result;
546
    }
547

    
548
    /**
549
     * @param td
550
     * @return
551
     * @deprecated
552
     */
553
    @Deprecated
554
    private FieldUnit findFieldUnit(SpecimenTypeDesignation td) {
555

    
556
        DerivedUnit du = td.getTypeSpecimen();
557
        return findFieldUnit(du);
558
    }
559

    
560
    private FieldUnit findFieldUnit(DerivedUnit du) {
561

    
562
        if(du == null || du.getOriginals() == null){
563
            return null;
564
        }
565
        @SuppressWarnings("rawtypes")
566
        Set<SpecimenOrObservationBase> originals = du.getDerivedFrom().getOriginals();
567
        @SuppressWarnings("rawtypes")
568
        Optional<SpecimenOrObservationBase> fieldUnit = originals.stream()
569
                .filter(original -> original instanceof FieldUnit).findFirst();
570
        if (fieldUnit.isPresent()) {
571
            return (FieldUnit) fieldUnit.get();
572
        } else {
573
            for (@SuppressWarnings("rawtypes")
574
            SpecimenOrObservationBase sob : originals) {
575
                if (sob instanceof DerivedUnit) {
576
                    FieldUnit fu = findFieldUnit((DerivedUnit) sob);
577
                    if (fu != null) {
578
                        return fu;
579
                    }
580
                }
581
            }
582
        }
583

    
584
        return null;
585
    }
586

    
587
    public String print() {
588
        return finalString.trim();
589
    }
590

    
591
    /**
592
     * @return the printCitation
593
     */
594
    public boolean isPrintCitation() {
595
        return printCitation;
596
    }
597

    
598
    /**
599
     * @param printCitation the printCitation to set
600
     */
601
    public void setPrintCitation(boolean printCitation) {
602
        this.printCitation = printCitation;
603
    }
604

    
605
    /**
606
     * @return the typifiedName
607
     */
608
    public TaxonName getTypifiedName() {
609
        return typifiedName;
610
    }
611

    
612
    public void setNameTypeBaseEntityType(NameTypeBaseEntityType nameTypeBaseEntityType){
613
        this.nameTypeBaseEntityType = nameTypeBaseEntityType;
614
    }
615

    
616
    public NameTypeBaseEntityType getNameTypeBaseEntityType(){
617
        return nameTypeBaseEntityType;
618
    }
619

    
620
    /**
621
     * TypeDesignations which refer to the same FieldUnit (SpecimenTypeDesignation) or TaxonName
622
     * (NameTypeDesignation) form a working set. The <code>TypeDesignationWorkingSet</code> internally
623
     * works with EnityReferences to the actual TypeDesignations.
624
     *
625
     * The EntityReferences for TypeDesignations are grouped by the according TypeDesignationStatus.
626
     * The TypeDesignationStatusBase keys can be ordered by the term order defined in the vocabulary.
627
     *
628
     * A workingset can be referenced by the <code>baseEntityReference</code>.
629
     */
630
    public class TypeDesignationWorkingSet extends LinkedHashMap<TypeDesignationStatusBase<?>, Collection<EntityReference>> {
631

    
632
        private static final long serialVersionUID = -1329007606500890729L;
633

    
634
        String workingSetRepresentation = null;
635

    
636
        TypedEntityReference<VersionableEntity> baseEntityReference;
637

    
638
        VersionableEntity baseEntity;
639

    
640
        List<DerivedUnit> derivedUnits = null;
641

    
642
        /**
643
         * @param baseEntityReference
644
         */
645
        public TypeDesignationWorkingSet(VersionableEntity baseEntity, TypedEntityReference<VersionableEntity> baseEntityReference) {
646
            this.baseEntity = baseEntity;
647
            this.baseEntityReference = baseEntityReference;
648
        }
649

    
650
        /**
651
         * @return
652
         */
653
        public VersionableEntity getBaseEntity() {
654
            return baseEntity;
655
        }
656

    
657
        public List<EntityReference> getTypeDesignations() {
658
            List<EntityReference> typeDesignations = new ArrayList<>();
659
            this.values().forEach(typeDesignationReferences -> typeDesignationReferences.forEach(td -> typeDesignations.add(td)));
660
            return typeDesignations;
661
        }
662

    
663
        /**
664
         * @param status
665
         * @param typeDesignationEntityReference
666
         */
667
        public void insert(TypeDesignationStatusBase<?> status, EntityReference typeDesignationEntityReference) {
668

    
669
            if(status == null){
670
                status = NULL_STATUS;
671
            }
672
            if(!containsKey(status)){
673
                put(status, new ArrayList<EntityReference>());
674
            }
675
            get(status).add(typeDesignationEntityReference);
676
        }
677

    
678

    
679
        public String getRepresentation() {
680
            return workingSetRepresentation;
681
        }
682

    
683
        public void setRepresentation(String representation){
684
            this.workingSetRepresentation = representation;
685
        }
686

    
687
        /**
688
         * A reference to the entity which is the common base entity for all TypeDesignations in this workingset.
689
         * For a {@link SpecimenTypeDesignation} this is usually the {@link FieldUnit} if it is present. Otherwise it can also be
690
         * a {@link DerivedUnit} or something else depending on the specific use case.
691
         *
692
         * @return the baseEntityReference
693
         */
694
        public TypedEntityReference<VersionableEntity> getBaseEntityReference() {
695
            return baseEntityReference;
696
        }
697

    
698
        @Override
699
        public String toString(){
700
            if(workingSetRepresentation != null){
701
                return workingSetRepresentation;
702
            } else {
703
                return super.toString();
704
            }
705
        }
706

    
707
        /**
708
         * @return
709
         */
710
        public boolean isSpecimenTypeDesigationWorkingSet() {
711
            return SpecimenOrObservationBase.class.isAssignableFrom(baseEntityReference.getType());
712
        }
713

    
714
        public TypeDesignationWorkingSetType getWorkingsetType() {
715
            return isSpecimenTypeDesigationWorkingSet() ? TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET : TypeDesignationWorkingSetType.NAME_TYPE_DESIGNATION_WORKINGSET;
716
        }
717

    
718
    }
719

    
720
    public enum TypeDesignationWorkingSetType {
721
        SPECIMEN_TYPE_DESIGNATION_WORKINGSET,
722
        NAME_TYPE_DESIGNATION_WORKINGSET,
723
    }
724

    
725
    @SuppressWarnings({ "deprecation", "serial" })
726
    class NullTypeDesignationStatus extends TypeDesignationStatusBase<NullTypeDesignationStatus>{
727

    
728
        /**
729
         * {@inheritDoc}
730
         */
731
        @Override
732
        public void resetTerms() {
733
            // empty
734

    
735
        }
736

    
737
        /**
738
         * {@inheritDoc}
739
         */
740
        @Override
741
        protected void setDefaultTerms(TermVocabulary<NullTypeDesignationStatus> termVocabulary) {
742
            // empty
743
        }
744

    
745
    }
746

    
747
    class DataIntegrityException extends Exception {
748

    
749
        private static final long serialVersionUID = 1464726696296824905L;
750

    
751
        /**
752
         * @param string
753
         */
754
        public DataIntegrityException(String string) {
755
            super(string);
756
        }
757
    }
758
}
    (1-1/1)