Project

General

Profile

Download (26 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.vaadin.util.converter;
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.model.common.CdmBase;
28
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
29
import eu.etaxonomy.cdm.model.common.TermVocabulary;
30
import eu.etaxonomy.cdm.model.name.NameTypeDesignation;
31
import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;
32
import eu.etaxonomy.cdm.model.name.TaxonName;
33
import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
34
import eu.etaxonomy.cdm.model.name.TypeDesignationStatusBase;
35
import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
36
import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
37
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
38
import eu.etaxonomy.cdm.vaadin.model.EntityReference;
39
import eu.etaxonomy.cdm.vaadin.model.TypedEntityReference;
40
import eu.etaxonomy.cdm.vaadin.view.registration.RegistrationValidationException;
41

    
42
/**
43
 * Manages a collection of {@link TypeDesignationBase TypeDesignations} for the same typified name.
44
 *
45
 * Type designations are ordered by the base type which is a {@link TaxonName} for {@link NameTypeDesignation NameTypeDesignations} or
46
 * in case of {@link SpecimenTypeDesignation SpecimenTypeDesignations} the  associate {@link FieldUnit} or the {@link DerivedUnit}
47
 * if the former is missing. The type designations per base type are furthermore ordered by the {@link TypeDesignationStatusBase}.
48
 *
49
 * The TypeDesignationSetManager also provides string representations of the whole ordered set of all
50
 * {@link TypeDesignationBase TypeDesignations} and of the TypeDesignationWorkingSets:
51
 * <ul>
52
 *  <li>{@link #print()})
53
 *  <li>{@link #getOrderdTypeDesignationWorkingSets()} ... {@link TypeDesignationWorkingSet#getRepresentation()}
54
 * </ul>
55
 * Prior using the representations you need to trigger their generation by calling {@link #buildString()}
56
 *
57
 * @author a.kohlbecker
58
 * @since Mar 10, 2017
59
 *
60
 */
61
public class TypeDesignationSetManager {
62

    
63

    
64
    private static final String TYPE_STATUS_SEPARATOR = "; ";
65

    
66
    private static final String TYPE_SEPARATOR = "; ";
67

    
68
    private static final String TYPE_DESIGNATION_SEPARATOR = ", ";
69

    
70
    private Collection<TypeDesignationBase> typeDesignations;
71

    
72
    private int workingSetIdAutoIncrement = 0;
73

    
74
    /**
75
     * Groups the EntityReferences for each of the TypeDesignations by the according TypeDesignationStatus.
76
     * The TypeDesignationStatusBase keys are already ordered by the term order defined in the vocabulary.
77
     */
78
    private LinkedHashMap<TypedEntityReference, TypeDesignationWorkingSet> orderedByTypesByBaseEntity;
79

    
80
    private EntityReference typifiedName;
81

    
82
    private String finalString = null;
83

    
84
    final NullTypeDesignationStatus NULL_STATUS = new NullTypeDesignationStatus();
85

    
86
    private List<String> probelms = new ArrayList<>();
87

    
88
    private boolean printCitation = false;
89

    
90
    /**
91
     * @param containgEntity
92
     * @param taxonName
93
     * @throws RegistrationValidationException
94
     *
95
     */
96
    public TypeDesignationSetManager(Collection<TypeDesignationBase> typeDesignations) throws RegistrationValidationException {
97
        this.typeDesignations = typeDesignations;
98
        this.typifiedName = findTypifiedName();
99
        mapAndSort();
100
    }
101

    
102
    /**
103
     * @param typifiedName2
104
     */
105
    public TypeDesignationSetManager(TaxonName typifiedName) {
106
        this.typeDesignations = new ArrayList<>();
107
        this.typifiedName = new EntityReference(typifiedName.getId(), typifiedName.getTitleCache());
108
    }
109

    
110
    /**
111
     * Add one or more TypeDesignations to the manager. This causes re-grouping and re-ordering
112
     * of all managed TypeDesignations.
113
     *
114
     * @param containgEntity
115
     * @param typeDesignations
116
     */
117
    public void addTypeDesigations(CdmBase containgEntity, TypeDesignationBase ... typeDesignations){
118
       this.typeDesignations.addAll(Arrays.asList(typeDesignations));
119
       mapAndSort();
120
    }
121

    
122
    /**
123
     * Groups and orders all managed TypeDesignations.
124
     *
125
     * @param containgEntity
126
     */
127
    protected void mapAndSort() {
128
        finalString = null;
129
        Map<TypedEntityReference, TypeDesignationWorkingSet> byBaseEntityByTypeStatus = new HashMap<>();
130
        this.typeDesignations.forEach(td -> mapTypeDesignation(byBaseEntityByTypeStatus, td));
131
        orderedByTypesByBaseEntity = orderByTypeByBaseEntity(byBaseEntityByTypeStatus);
132
    }
133

    
134

    
135
    /**
136
     *
137
     * @param containgEntity
138
     * @param byBaseEntityByTypeStatus
139
     * @param td
140
     */
141
    private void mapTypeDesignation(Map<TypedEntityReference, TypeDesignationWorkingSet> byBaseEntityByTypeStatus,
142
            TypeDesignationBase<?> td){
143

    
144
        TypeDesignationStatusBase<?> status = td.getTypeStatus();
145

    
146
        try {
147
            final IdentifiableEntity<?> baseEntity = baseEntity(td);
148
            final TypedEntityReference<IdentifiableEntity<?>> baseEntityReference = makeEntityReference(baseEntity);
149

    
150
            EntityReference typeDesignationEntityReference = new EntityReference(td.getId(), stringify(td));
151

    
152
            TypeDesignationWorkingSet typedesignationWorkingSet;
153
            if(!byBaseEntityByTypeStatus.containsKey(baseEntityReference)){
154
                byBaseEntityByTypeStatus.put(baseEntityReference, new TypeDesignationWorkingSet(baseEntity, baseEntityReference));
155
            }
156

    
157
            typedesignationWorkingSet = byBaseEntityByTypeStatus.get(baseEntityReference);
158
            typedesignationWorkingSet.insert(status, typeDesignationEntityReference);
159
        } catch (DataIntegrityException e){
160
            probelms.add(e.getMessage());
161
        }
162
    }
163

    
164
    /**
165
     * @param td
166
     * @return
167
     * @throws DataIntegrityException
168
     */
169
    protected IdentifiableEntity<?> baseEntity(TypeDesignationBase<?> td) throws DataIntegrityException {
170

    
171
        IdentifiableEntity<?> baseEntity = null;
172
        if(td  instanceof SpecimenTypeDesignation){
173
            SpecimenTypeDesignation std = (SpecimenTypeDesignation) td;
174
            FieldUnit fu = findFieldUnit(std);
175
            if(fu != null){
176
                baseEntity = fu;
177
            } else if(((SpecimenTypeDesignation) td).getTypeSpecimen() != null){
178
                baseEntity = ((SpecimenTypeDesignation) td).getTypeSpecimen();
179
            }
180
        } else if(td instanceof NameTypeDesignation){
181
            baseEntity = ((NameTypeDesignation)td).getTypeName();
182
        }
183
        if(baseEntity == null) {
184
            throw new DataIntegrityException("Incomplete TypeDesignation, no type missin in " + td.toString());
185
        }
186
        return baseEntity;
187
    }
188

    
189
    /**
190
     * @param td
191
     * @return
192
     */
193
    protected TypedEntityReference<IdentifiableEntity<?>> makeEntityReference(IdentifiableEntity<?> baseEntity) {
194

    
195
        baseEntity = (IdentifiableEntity<?>) HibernateHelper.unproxy(baseEntity);
196
        String label = "";
197
        if(baseEntity  instanceof FieldUnit){
198
                label = ((FieldUnit)baseEntity).getTitleCache();
199
        }
200

    
201
        TypedEntityReference<IdentifiableEntity<?>> baseEntityReference = new TypedEntityReference(baseEntity.getClass(), baseEntity.getId(), label);
202

    
203
        return baseEntityReference;
204
    }
205

    
206

    
207
    private LinkedHashMap<TypedEntityReference, TypeDesignationWorkingSet> orderByTypeByBaseEntity(
208
            Map<TypedEntityReference, TypeDesignationWorkingSet> stringsByTypeByBaseEntity){
209

    
210
       // order the FieldUnit TypeName keys
211
       List<TypedEntityReference> baseEntityKeyList = new LinkedList<>(stringsByTypeByBaseEntity.keySet());
212
       Collections.sort(baseEntityKeyList, new Comparator<TypedEntityReference>(){
213
        /**
214
         * Sorts the base entities (TypedEntityReference) in the following order:
215
         *
216
         * 1. FieldUnits
217
         * 2. DerivedUnit (in case of missing FieldUnit we expect the base type to be DerivedUnit)
218
         * 3. NameType
219
         *
220
         * {@inheritDoc}
221
         */
222
        @Override
223
        public int compare(TypedEntityReference o1, TypedEntityReference o2) {
224

    
225
            Class type1 = o1.getType();
226
            Class type2 = o2.getType();
227

    
228
            if(!type1.equals(type2)) {
229
                if(type1.equals(FieldUnit.class) || type2.equals(FieldUnit.class)){
230
                    // FieldUnits first
231
                    return type1.equals(FieldUnit.class) ? -1 : 1;
232
                } else {
233
                    // name types last (in case of missing FieldUnit we expect the base type to be DerivedUnit which comes into the middle)
234
                    return type2.equals(TaxonName.class) ? -1 : 1;
235
                }
236
            } else {
237
                return o1.getLabel().compareTo(o2.getLabel());
238
            }
239
        }});
240

    
241
       // new LinkedHashMap for the ordered FieldUnitOrTypeName keys
242
       LinkedHashMap<TypedEntityReference, TypeDesignationWorkingSet> stringsOrderedbyBaseEntityOrderdByType = new LinkedHashMap<>(stringsByTypeByBaseEntity.size());
243

    
244
       for(TypedEntityReference baseEntityRef : baseEntityKeyList){
245

    
246
           TypeDesignationWorkingSet typeDesignationWorkingSet = stringsByTypeByBaseEntity.get(baseEntityRef);
247
           // order the TypeDesignationStatusBase keys
248
            List<TypeDesignationStatusBase<?>> keyList = new LinkedList<>(typeDesignationWorkingSet.keySet());
249
            Collections.sort(keyList, new Comparator<TypeDesignationStatusBase>() {
250
                @SuppressWarnings("unchecked")
251
                @Override
252
                public int compare(TypeDesignationStatusBase o1, TypeDesignationStatusBase o2) {
253
                    // fix inverted order of cdm terms by -1*
254
                    return -1 * o1.compareTo(o2);
255
                }
256
            });
257
            // new LinkedHashMap for the ordered TypeDesignationStatusBase keys
258
            TypeDesignationWorkingSet orderedStringsByOrderedTypes = new TypeDesignationWorkingSet(
259
                    typeDesignationWorkingSet.getBaseEntity(),
260
                    baseEntityRef);
261
            orderedStringsByOrderedTypes.setWorkingSetId(typeDesignationWorkingSet.workingSetId); // preserve original workingSetId
262
            keyList.forEach(key -> orderedStringsByOrderedTypes.put(key, typeDesignationWorkingSet.get(key)));
263
            stringsOrderedbyBaseEntityOrderdByType.put(baseEntityRef, orderedStringsByOrderedTypes);
264
       }
265

    
266
        return stringsOrderedbyBaseEntityOrderdByType;
267
    }
268

    
269
    /*
270
    private LinkedHashMap<TypedEntityReference, LinkedHashMap<String, Collection<EntityReference>>> buildOrderedRepresentations(){
271

    
272
        orderedStringsByOrderedTypes.keySet().forEach(
273
                key -> orderedRepresentations.put(
274
                        getTypeDesignationStytusLabel(key),
275
                        orderedStringsByOrderedTypes.get(key))
276
                );
277
        return orderedRepresentations;
278
    }
279
*/
280

    
281
    public TypeDesignationSetManager buildString(){
282

    
283
        if(finalString == null){
284

    
285
            finalString = "";
286
            if(getTypifiedNameCache() != null){
287
                finalString += getTypifiedNameCache() + " ";
288
            }
289

    
290
            int typeCount = 0;
291
            if(orderedByTypesByBaseEntity != null){
292
                for(TypedEntityReference baseEntityRef : orderedByTypesByBaseEntity.keySet()) {
293
                    StringBuilder sb = new StringBuilder();
294
                    if(typeCount++ > 0){
295
                        sb.append(TYPE_SEPARATOR);
296
                    }
297
                    boolean isNameTypeDesignation = false;
298
                    if(SpecimenOrObservationBase.class.isAssignableFrom(baseEntityRef.getType())){
299
                        sb.append("Type: ");
300
                    } else {
301
                        sb.append("NameType: ");
302
                        isNameTypeDesignation = true;
303
                    }
304
                    if(!baseEntityRef.getLabel().isEmpty()){
305
                        sb.append(baseEntityRef.getLabel()).append(" ");
306
                    }
307
                    TypeDesignationWorkingSet typeDesignationWorkingSet = orderedByTypesByBaseEntity.get(baseEntityRef);
308
                    if(!isNameTypeDesignation ){
309
                        sb.append("(");
310
                    }
311
                    int typeStatusCount = 0;
312
                    for(TypeDesignationStatusBase<?> typeStatus : typeDesignationWorkingSet.keySet()) {
313
                        if(typeStatusCount++  > 0){
314
                            sb.append(TYPE_STATUS_SEPARATOR);
315
                        }
316
                        boolean isPlural = typeDesignationWorkingSet.get(typeStatus).size() > 1;
317
                        if(!typeStatus.equals(NULL_STATUS)) {
318
                            sb.append(typeStatus.getLabel());
319
                            if(isPlural){
320
                                sb.append("s: ");
321
                            } else {
322
                                sb.append(", ");
323
                            }
324
                        }
325
                        int typeDesignationCount = 0;
326
                        for(EntityReference typeDesignationEntityReference : typeDesignationWorkingSet.get(typeStatus)) {
327
                            if(typeDesignationCount++  > 0){
328
                                sb.append(TYPE_DESIGNATION_SEPARATOR);
329
                            }
330
                            sb.append(typeDesignationEntityReference.getLabel());
331
                        }
332
                    }
333
                    if(!isNameTypeDesignation ){
334
                        sb.append(")");
335
                    }
336
                    typeDesignationWorkingSet.setRepresentation(sb.toString());
337
                    finalString += typeDesignationWorkingSet.getRepresentation();
338
                }
339
            }
340
        }
341
        return this;
342
    }
343

    
344
    /**
345
     * FIXME use the validation framework validators and to store the validation problems!!!
346
     *
347
     * @return
348
     * @throws RegistrationValidationException
349
     */
350
    private EntityReference findTypifiedName() throws RegistrationValidationException {
351

    
352
        List<String> problems = new ArrayList<>();
353

    
354
        TaxonName typifiedName = null;
355

    
356
        for(TypeDesignationBase<?> typeDesignation : typeDesignations){
357
            typeDesignation.getTypifiedNames();
358
            if(typeDesignation.getTypifiedNames().isEmpty()){
359

    
360
                //TODO instead throw RegistrationValidationException()
361
                problems.add("Missing typifiedName in " + typeDesignation.toString());
362
                continue;
363
            }
364
            if(typeDesignation.getTypifiedNames().size() > 1){
365
              //TODO instead throw RegistrationValidationException()
366
                problems.add("Multiple typifiedName in " + typeDesignation.toString());
367
                continue;
368
            }
369
            if(typifiedName == null){
370
                // remember
371
                typifiedName = typeDesignation.getTypifiedNames().iterator().next();
372
            } else {
373
                // compare
374
                TaxonName otherTypifiedName = typeDesignation.getTypifiedNames().iterator().next();
375
                if(typifiedName.getId() != otherTypifiedName.getId()){
376
                  //TODO instead throw RegistrationValidationException()
377
                    problems.add("Multiple typifiedName in " + typeDesignation.toString());
378
                }
379
            }
380

    
381
        }
382
        if(!problems.isEmpty()){
383
            // FIXME use the validation framework
384
            throw new RegistrationValidationException("Inconsistent type designations", problems);
385
        }
386

    
387
        if(typifiedName != null){
388
            return new EntityReference(typifiedName.getId(), typifiedName.getTitleCache());
389
        }
390
        return null;
391
    }
392

    
393

    
394
    /**
395
     * @return the title cache of the typifying name or <code>null</code>
396
     */
397
    public String getTypifiedNameCache() {
398
        if(typifiedName != null){
399
            return typifiedName.getLabel();
400
        }
401
        return null;
402
    }
403

    
404
    /**
405
     * @return the title cache of the typifying name or <code>null</code>
406
     */
407
    public EntityReference getTypifiedName() {
408

    
409
       return typifiedName;
410
    }
411

    
412
    /**
413
     * @return
414
     */
415
    public Collection<TypeDesignationBase> getTypeDesignations() {
416
        return typeDesignations;
417
    }
418

    
419
    /**
420
     * @param ref
421
     * @return
422
     */
423
    public TypeDesignationBase findTypeDesignation(EntityReference typeDesignationRef) {
424
        for(TypeDesignationBase td : typeDesignations){
425
            if(td.getId() == typeDesignationRef.getId()){
426
                return td;
427
            }
428
        }
429
        // TODO Auto-generated method stub
430
        return null;
431
    }
432

    
433

    
434
    public LinkedHashMap<TypedEntityReference, TypeDesignationWorkingSet> getOrderdTypeDesignationWorkingSets() {
435
        return orderedByTypesByBaseEntity;
436
    }
437

    
438
    /**
439
     * @param td
440
     * @return
441
     */
442
    private String stringify(TypeDesignationBase td) {
443

    
444
        if(td instanceof NameTypeDesignation){
445
            return stringify((NameTypeDesignation)td);
446
        } else {
447
            return stringify((SpecimenTypeDesignation)td, false);
448
        }
449
    }
450

    
451

    
452
    /**
453
     * @param td
454
     * @return
455
     */
456
    protected String stringify(NameTypeDesignation td) {
457

    
458
        StringBuffer sb = new StringBuffer();
459

    
460
        if(td.getTypeName() != null){
461
            sb.append(td.getTypeName().getTitleCache());
462
        }
463
        if(td.getCitation() != null){
464
            sb.append(" ").append(td.getCitation().getTitleCache());
465
            if(td.getCitationMicroReference() != null){
466
                sb.append(":").append(td.getCitationMicroReference());
467
            }
468
        }
469
        if(td.isNotDesignated()){
470
            sb.append(" not designated");
471
        }
472
        if(td.isRejectedType()){
473
            sb.append(" rejected");
474
        }
475
        if(td.isConservedType()){
476
            sb.append(" conserved");
477
        }
478
        return sb.toString();
479
    }
480

    
481
    /**
482
     * @param td
483
     * @return
484
     */
485
    private String stringify(SpecimenTypeDesignation td, boolean useFullTitleCache) {
486
        String  result = "";
487

    
488
        if(useFullTitleCache){
489
            if(td.getTypeSpecimen() != null){
490
                String nameTitleCache = td.getTypeSpecimen().getTitleCache();
491
                if(getTypifiedNameCache() != null){
492
                    nameTitleCache = nameTitleCache.replace(getTypifiedNameCache(), "");
493
                }
494
                result += nameTitleCache;
495
            }
496
        } else {
497
            if(td.getTypeSpecimen() != null){
498
                DerivedUnit du = td.getTypeSpecimen();
499
                if(du.isProtectedTitleCache()){
500
                    result += du.getTitleCache();
501
                } else {
502
                    DerivedUnitFacadeCacheStrategy cacheStrategy = new DerivedUnitFacadeCacheStrategy();
503
                    result += cacheStrategy.getTitleCache(du, true);
504
                }
505
            }
506
        }
507

    
508
        if(isPrintCitation() && td.getCitation() != null){
509
            if(td.getCitation().getAbbrevTitle() != null){
510
                result += " " + td.getCitation().getAbbrevTitle();
511
            } else {
512
                result += " " + td.getCitation().getTitleCache();
513
            }
514
            if(td.getCitationMicroReference() != null){
515
                result += " :" + td.getCitationMicroReference();
516
            }
517
        }
518
        if(td.isNotDesignated()){
519
            result += " not designated";
520
        }
521

    
522
        return result;
523
    }
524

    
525
    /**
526
     * @param td
527
     * @return
528
     * @deprecated
529
     */
530
    @Deprecated
531
    private FieldUnit findFieldUnit(SpecimenTypeDesignation td) {
532

    
533
        DerivedUnit du = td.getTypeSpecimen();
534
        return findFieldUnit(du);
535
    }
536

    
537
    private FieldUnit findFieldUnit(DerivedUnit du) {
538

    
539
        if(du == null || du.getOriginals() == null){
540
            return null;
541
        }
542
        @SuppressWarnings("rawtypes")
543
        Set<SpecimenOrObservationBase> originals = du.getDerivedFrom().getOriginals();
544
        @SuppressWarnings("rawtypes")
545
        Optional<SpecimenOrObservationBase> fieldUnit = originals.stream()
546
                .filter(original -> original instanceof FieldUnit).findFirst();
547
        if (fieldUnit.isPresent()) {
548
            return (FieldUnit) fieldUnit.get();
549
        } else {
550
            for (@SuppressWarnings("rawtypes")
551
            SpecimenOrObservationBase sob : originals) {
552
                if (sob instanceof DerivedUnit) {
553
                    FieldUnit fu = findFieldUnit((DerivedUnit) sob);
554
                    if (fu != null) {
555
                        return fu;
556
                    }
557
                }
558
            }
559
        }
560

    
561
        return null;
562
    }
563

    
564
    public String print() {
565
        return finalString.trim();
566
    }
567

    
568
    /**
569
     * @return the printCitation
570
     */
571
    public boolean isPrintCitation() {
572
        return printCitation;
573
    }
574

    
575
    /**
576
     * @param printCitation the printCitation to set
577
     */
578
    public void setPrintCitation(boolean printCitation) {
579
        this.printCitation = printCitation;
580
    }
581

    
582
    /**
583
     * TypeDesignations which refer to the same FieldUnit (SpecimenTypeDesignation) or TaxonName
584
     * (NameTypeDesignation) form a working set. The <code>TypeDesignationWorkingSet</code> internally
585
     * works with EnityReferences to the actual TypeDesignations.
586
     *
587
     * The EntityReferences for TypeDesignations are grouped by the according TypeDesignationStatus.
588
     * The TypeDesignationStatusBase keys can be ordered by the term order defined in the vocabulary.
589
     *
590
     * A workingset can be referenced by the <code>workingSetId</code>, this is a autoincrement
591
     * value which is created during the process of determining the workingsets in a collection of
592
     * TypeDesignations.
593
     *
594
     * TODO: consider using a concatenation of baseEntity.getClass() + baseEntity.getId() as workingset identifier
595
     */
596
    public class TypeDesignationWorkingSet extends LinkedHashMap<TypeDesignationStatusBase<?>, Collection<EntityReference>> {
597

    
598
        private static final long serialVersionUID = -1329007606500890729L;
599

    
600
        String workingSetRepresentation = null;
601

    
602
        TypedEntityReference<IdentifiableEntity<?>> baseEntityReference;
603

    
604
        IdentifiableEntity<?> baseEntity;
605

    
606
        List<DerivedUnit> derivedUnits = null;
607

    
608
        int workingSetId = workingSetIdAutoIncrement++;
609

    
610
        /**
611
         * @param baseEntityReference
612
         */
613
        public TypeDesignationWorkingSet(IdentifiableEntity<?> baseEntity, TypedEntityReference<IdentifiableEntity<?>> baseEntityReference) {
614
            this.baseEntity = baseEntity;
615
            this.baseEntityReference = baseEntityReference;
616
        }
617

    
618
        /**
619
         * @return
620
         */
621
        public IdentifiableEntity<?> getBaseEntity() {
622
            return baseEntity;
623
        }
624

    
625
        public List<EntityReference> getTypeDesignations() {
626
            List<EntityReference> typeDesignations = new ArrayList<>();
627
            this.values().forEach(typeDesignationReferences -> typeDesignationReferences.forEach(td -> typeDesignations.add(td)));
628
            return typeDesignations;
629
        }
630

    
631
        /**
632
         * @param status
633
         * @param typeDesignationEntityReference
634
         */
635
        public void insert(TypeDesignationStatusBase<?> status, EntityReference typeDesignationEntityReference) {
636

    
637
            if(status == null){
638
                status = NULL_STATUS;
639
            }
640
            if(!containsKey(status)){
641
                put(status, new ArrayList<EntityReference>());
642
            }
643
            get(status).add(typeDesignationEntityReference);
644
        }
645

    
646
        /**
647
         * @return the workingSetId
648
         */
649
        public int getWorkingSetId() {
650
            return workingSetId;
651
        }
652

    
653
        /**
654
         * @param workingSetId the workingSetId to set
655
         */
656
        public void setWorkingSetId(int workingSetId) {
657
            this.workingSetId = workingSetId;
658
        }
659

    
660
        public String getRepresentation() {
661
            return workingSetRepresentation;
662
        }
663

    
664
        public void setRepresentation(String representation){
665
            this.workingSetRepresentation = representation;
666
        }
667

    
668
        /**
669
         * A reference to the entity which is the common base entity for all TypeDesignations in this workingset.
670
         * For a {@link SpecimenTypeDesignation} this is usually the {@link FieldUnit} if it is present. Otherwise it can also be
671
         * a {@link DerivedUnit} or something else depending on the specific use case.
672
         *
673
         * @return the baseEntityReference
674
         */
675
        public TypedEntityReference getBaseEntityReference() {
676
            return baseEntityReference;
677
        }
678

    
679
        @Override
680
        public String toString(){
681
            if(workingSetRepresentation != null){
682
                return workingSetRepresentation;
683
            } else {
684
                return super.toString();
685
            }
686
        }
687

    
688
        /**
689
         * @return
690
         */
691
        public boolean isSpecimenTypeDesigationWorkingSet() {
692
            return SpecimenOrObservationBase.class.isAssignableFrom(baseEntityReference.getType());
693
        }
694

    
695
        public TypeDesignationWorkingSetType getWorkingsetType() {
696
            return isSpecimenTypeDesigationWorkingSet() ? TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET : TypeDesignationWorkingSetType.NAME_TYPE_DESIGNATION_WORKINGSET;
697
        }
698

    
699
    }
700

    
701
    public enum TypeDesignationWorkingSetType {
702
        SPECIMEN_TYPE_DESIGNATION_WORKINGSET,
703
        NAME_TYPE_DESIGNATION_WORKINGSET,
704
    }
705

    
706
    @SuppressWarnings({ "deprecation", "serial" })
707
    class NullTypeDesignationStatus extends TypeDesignationStatusBase<NullTypeDesignationStatus>{
708

    
709
        /**
710
         * {@inheritDoc}
711
         */
712
        @Override
713
        public void resetTerms() {
714
            // empty
715

    
716
        }
717

    
718
        /**
719
         * {@inheritDoc}
720
         */
721
        @Override
722
        protected void setDefaultTerms(TermVocabulary<NullTypeDesignationStatus> termVocabulary) {
723
            // empty
724
        }
725

    
726
    }
727

    
728
}
(6-6/7)