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.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 TypeDesignationStatusComparator());
262
            // new LinkedHashMap for the ordered TypeDesignationStatusBase keys
263
            TypeDesignationWorkingSet orderedStringsByOrderedTypes = new TypeDesignationWorkingSet(
264
                    typeDesignationWorkingSet.getBaseEntity(),
265
                    baseEntityRef);
266
            keyList.forEach(key -> orderedStringsByOrderedTypes.put(key, typeDesignationWorkingSet.get(key)));
267
            stringsOrderedbyBaseEntityOrderdByType.put(baseEntityRef, orderedStringsByOrderedTypes);
268
       }
269

    
270
        return stringsOrderedbyBaseEntityOrderdByType;
271
    }
272

    
273
    /*
274
    private LinkedHashMap<TypedEntityReference, LinkedHashMap<String, Collection<EntityReference>>> buildOrderedRepresentations(){
275

    
276
        orderedStringsByOrderedTypes.keySet().forEach(
277
                key -> orderedRepresentations.put(
278
                        getTypeDesignationStytusLabel(key),
279
                        orderedStringsByOrderedTypes.get(key))
280
                );
281
        return orderedRepresentations;
282
    }
283
*/
284

    
285
    public TypeDesignationSetManager buildString(){
286

    
287
        if(finalString == null){
288

    
289
            finalString = "";
290
            if(getTypifiedNameCache() != null){
291
                finalString += getTypifiedNameCache() + " ";
292
            }
293

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

    
348
    /**
349
     * FIXME use the validation framework validators and to store the validation problems!!!
350
     *
351
     * @return
352
     * @throws RegistrationValidationException
353
     */
354
    private void findTypifiedName() throws RegistrationValidationException {
355

    
356
        List<String> problems = new ArrayList<>();
357

    
358
        TaxonName typifiedName = null;
359

    
360
        for(TypeDesignationBase<?> typeDesignation : typeDesignations){
361
            typeDesignation.getTypifiedNames();
362
            if(typeDesignation.getTypifiedNames().isEmpty()){
363

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

    
385
        }
386
        if(!problems.isEmpty()){
387
            // FIXME use the validation framework
388
            throw new RegistrationValidationException("Inconsistent type designations", problems);
389
        }
390

    
391
        if(typifiedName != null){
392
            // ON SUCCESS -------------------
393
            this.typifiedName = typifiedName;
394
            this.typifiedNameRef = new EntityReference(typifiedName.getUuid(), typifiedName.getTitleCache());
395

    
396
        }
397
    }
398

    
399

    
400
    /**
401
     * @return the title cache of the typifying name or <code>null</code>
402
     */
403
    public String getTypifiedNameCache() {
404
        if(typifiedNameRef != null){
405
            return typifiedNameRef.getLabel();
406
        }
407
        return null;
408
    }
409

    
410
    /**
411
     * @return the title cache of the typifying name or <code>null</code>
412
     */
413
    public EntityReference getTypifiedNameRef() {
414

    
415
       return typifiedNameRef;
416
    }
417

    
418
    /**
419
     * @return
420
     */
421
    public Collection<TypeDesignationBase> getTypeDesignations() {
422
        return typeDesignations;
423
    }
424

    
425
    /**
426
     * @param ref
427
     * @return
428
     */
429
    public TypeDesignationBase findTypeDesignation(EntityReference typeDesignationRef) {
430
        for(TypeDesignationBase td : typeDesignations){
431
            if(td.getUuid().equals(typeDesignationRef.getUuid())){
432
                return td;
433
            }
434
        }
435
        // TODO Auto-generated method stub
436
        return null;
437
    }
438

    
439

    
440
    public LinkedHashMap<TypedEntityReference, TypeDesignationWorkingSet> getOrderdTypeDesignationWorkingSets() {
441
        return orderedByTypesByBaseEntity;
442
    }
443

    
444
    /**
445
     * @param td
446
     * @return
447
     */
448
    private String stringify(TypeDesignationBase td) {
449

    
450
        if(td instanceof NameTypeDesignation){
451
            return stringify((NameTypeDesignation)td);
452
        } else {
453
            return stringify((SpecimenTypeDesignation)td, false);
454
        }
455
    }
456

    
457

    
458
    /**
459
     * @param td
460
     * @return
461
     */
462
    protected String stringify(NameTypeDesignation td) {
463

    
464
        StringBuffer sb = new StringBuffer();
465

    
466
        if(td.getTypeName() != null){
467
            sb.append(td.getTypeName().getTitleCache());
468
        }
469
        if(td.getCitation() != null){
470
            sb.append(" ").append(td.getCitation().getTitleCache());
471
            if(td.getCitationMicroReference() != null){
472
                sb.append(":").append(td.getCitationMicroReference());
473
            }
474
        }
475
        if(td.isNotDesignated()){
476
            sb.append(" not designated");
477
        }
478
        if(td.isRejectedType()){
479
            sb.append(" rejected");
480
        }
481
        if(td.isConservedType()){
482
            sb.append(" conserved");
483
        }
484
        return sb.toString();
485
    }
486

    
487
    /**
488
     * @param td
489
     * @return
490
     */
491
    private String stringify(SpecimenTypeDesignation td, boolean useFullTitleCache) {
492
        String  result = "";
493

    
494
        if(useFullTitleCache){
495
            if(td.getTypeSpecimen() != null){
496
                String nameTitleCache = td.getTypeSpecimen().getTitleCache();
497
                if(getTypifiedNameCache() != null){
498
                    nameTitleCache = nameTitleCache.replace(getTypifiedNameCache(), "");
499
                }
500
                result += nameTitleCache;
501
            }
502
        } else {
503
            if(td.getTypeSpecimen() != null){
504
                DerivedUnit du = td.getTypeSpecimen();
505
                if(du.isProtectedTitleCache()){
506
                    result += du.getTitleCache();
507
                } else {
508
                    DerivedUnitFacadeCacheStrategy cacheStrategy = new DerivedUnitFacadeCacheStrategy();
509
                    result += cacheStrategy.getTitleCache(du, true);
510
                }
511
            }
512
        }
513

    
514
        if(isPrintCitation() && td.getCitation() != null){
515
            if(td.getCitation().getAbbrevTitle() != null){
516
                result += " " + td.getCitation().getAbbrevTitle();
517
            } else {
518
                result += " " + td.getCitation().getTitleCache();
519
            }
520
            if(td.getCitationMicroReference() != null){
521
                result += " :" + td.getCitationMicroReference();
522
            }
523
        }
524
        if(td.isNotDesignated()){
525
            result += " not designated";
526
        }
527

    
528
        return result;
529
    }
530

    
531
    /**
532
     * @param td
533
     * @return
534
     * @deprecated
535
     */
536
    @Deprecated
537
    private FieldUnit findFieldUnit(SpecimenTypeDesignation td) {
538

    
539
        DerivedUnit du = td.getTypeSpecimen();
540
        return findFieldUnit(du);
541
    }
542

    
543
    private FieldUnit findFieldUnit(DerivedUnit du) {
544

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

    
567
        return null;
568
    }
569

    
570
    public String print() {
571
        return finalString.trim();
572
    }
573

    
574
    /**
575
     * @return the printCitation
576
     */
577
    public boolean isPrintCitation() {
578
        return printCitation;
579
    }
580

    
581
    /**
582
     * @param printCitation the printCitation to set
583
     */
584
    public void setPrintCitation(boolean printCitation) {
585
        this.printCitation = printCitation;
586
    }
587

    
588
    /**
589
     * @return the typifiedName
590
     */
591
    public TaxonName getTypifiedName() {
592
        return typifiedName;
593
    }
594

    
595
    public void setNameTypeBaseEntityType(NameTypeBaseEntityType nameTypeBaseEntityType){
596
        this.nameTypeBaseEntityType = nameTypeBaseEntityType;
597
    }
598

    
599
    public NameTypeBaseEntityType getNameTypeBaseEntityType(){
600
        return nameTypeBaseEntityType;
601
    }
602

    
603
    /**
604
     * TypeDesignations which refer to the same FieldUnit (SpecimenTypeDesignation) or TaxonName
605
     * (NameTypeDesignation) form a working set. The <code>TypeDesignationWorkingSet</code> internally
606
     * works with EnityReferences to the actual TypeDesignations.
607
     *
608
     * The EntityReferences for TypeDesignations are grouped by the according TypeDesignationStatus.
609
     * The TypeDesignationStatusBase keys can be ordered by the term order defined in the vocabulary.
610
     *
611
     * A workingset can be referenced by the <code>baseEntityReference</code>.
612
     */
613
    public class TypeDesignationWorkingSet extends LinkedHashMap<TypeDesignationStatusBase<?>, Collection<EntityReference>> {
614

    
615
        private static final long serialVersionUID = -1329007606500890729L;
616

    
617
        String workingSetRepresentation = null;
618

    
619
        TypedEntityReference<VersionableEntity> baseEntityReference;
620

    
621
        VersionableEntity baseEntity;
622

    
623
        List<DerivedUnit> derivedUnits = null;
624

    
625
        /**
626
         * @param baseEntityReference
627
         */
628
        public TypeDesignationWorkingSet(VersionableEntity baseEntity, TypedEntityReference<VersionableEntity> baseEntityReference) {
629
            this.baseEntity = baseEntity;
630
            this.baseEntityReference = baseEntityReference;
631
        }
632

    
633
        /**
634
         * @return
635
         */
636
        public VersionableEntity getBaseEntity() {
637
            return baseEntity;
638
        }
639

    
640
        public List<EntityReference> getTypeDesignations() {
641
            List<EntityReference> typeDesignations = new ArrayList<>();
642
            this.values().forEach(typeDesignationReferences -> typeDesignationReferences.forEach(td -> typeDesignations.add(td)));
643
            return typeDesignations;
644
        }
645

    
646
        /**
647
         * @param status
648
         * @param typeDesignationEntityReference
649
         */
650
        public void insert(TypeDesignationStatusBase<?> status, EntityReference typeDesignationEntityReference) {
651

    
652
            if(status == null){
653
                status = NULL_STATUS;
654
            }
655
            if(!containsKey(status)){
656
                put(status, new ArrayList<EntityReference>());
657
            }
658
            get(status).add(typeDesignationEntityReference);
659
        }
660

    
661

    
662
        public String getRepresentation() {
663
            return workingSetRepresentation;
664
        }
665

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

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

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

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

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

    
701
    }
702

    
703
    public enum TypeDesignationWorkingSetType {
704
        SPECIMEN_TYPE_DESIGNATION_WORKINGSET,
705
        NAME_TYPE_DESIGNATION_WORKINGSET,
706
    }
707

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

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

    
718
        }
719

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

    
728
    }
729

    
730
    class DataIntegrityException extends Exception {
731

    
732
        private static final long serialVersionUID = 1464726696296824905L;
733

    
734
        /**
735
         * @param string
736
         */
737
        public DataIntegrityException(String string) {
738
            super(string);
739
        }
740
    }
741
}
(2-2/3)