Project

General

Profile

Download (48.8 KB) Statistics
| Branch: | Tag: | Revision:
1
package eu.etaxonomy.cdm.api.service;
2

    
3
import java.math.BigDecimal;
4
import java.util.ArrayList;
5
import java.util.Arrays;
6
import java.util.Collection;
7
import java.util.Collections;
8
import java.util.HashMap;
9
import java.util.HashSet;
10
import java.util.List;
11
import java.util.Map;
12
import java.util.Optional;
13
import java.util.Set;
14
import java.util.UUID;
15
import java.util.stream.Collectors;
16

    
17
import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;
18
import org.hibernate.Query;
19
import org.hibernate.Session;
20
import org.springframework.beans.factory.annotation.Autowired;
21
import org.springframework.stereotype.Service;
22
import org.springframework.transaction.annotation.Transactional;
23

    
24
import eu.etaxonomy.cdm.api.service.UpdateResult.Status;
25
import eu.etaxonomy.cdm.api.service.config.DeleteDescriptiveDataSetConfigurator;
26
import eu.etaxonomy.cdm.api.service.config.IdentifiableServiceConfiguratorImpl;
27
import eu.etaxonomy.cdm.api.service.config.RemoveDescriptionsFromDescriptiveDataSetConfigurator;
28
import eu.etaxonomy.cdm.api.service.dto.CategoricalDataDto;
29
import eu.etaxonomy.cdm.api.service.dto.DescriptionBaseDto;
30
import eu.etaxonomy.cdm.api.service.dto.DescriptionElementDto;
31
import eu.etaxonomy.cdm.api.service.dto.QuantitativeDataDto;
32
import eu.etaxonomy.cdm.api.service.dto.RowWrapperDTO;
33
import eu.etaxonomy.cdm.api.service.dto.SpecimenOrObservationDTOFactory;
34
import eu.etaxonomy.cdm.api.service.dto.SpecimenRowWrapperDTO;
35
import eu.etaxonomy.cdm.api.service.dto.StateDataDto;
36
import eu.etaxonomy.cdm.api.service.dto.StatisticalMeasurementValueDto;
37
import eu.etaxonomy.cdm.api.service.dto.TaxonRowWrapperDTO;
38
import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
39
import eu.etaxonomy.cdm.filter.TaxonNodeFilter;
40
import eu.etaxonomy.cdm.format.description.DefaultCategoricalDescriptionBuilder;
41
import eu.etaxonomy.cdm.format.description.DefaultQuantitativeDescriptionBuilder;
42
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
43
import eu.etaxonomy.cdm.model.common.CdmBase;
44
import eu.etaxonomy.cdm.model.common.IdentifiableSource;
45
import eu.etaxonomy.cdm.model.common.Language;
46
import eu.etaxonomy.cdm.model.description.CategoricalData;
47
import eu.etaxonomy.cdm.model.description.DescriptionBase;
48
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
49
import eu.etaxonomy.cdm.model.description.DescriptionType;
50
import eu.etaxonomy.cdm.model.description.DescriptiveDataSet;
51
import eu.etaxonomy.cdm.model.description.DescriptiveSystemRole;
52
import eu.etaxonomy.cdm.model.description.Feature;
53
import eu.etaxonomy.cdm.model.description.IndividualsAssociation;
54
import eu.etaxonomy.cdm.model.description.MeasurementUnit;
55
import eu.etaxonomy.cdm.model.description.PolytomousKey;
56
import eu.etaxonomy.cdm.model.description.QuantitativeData;
57
import eu.etaxonomy.cdm.model.description.SpecimenDescription;
58
import eu.etaxonomy.cdm.model.description.State;
59
import eu.etaxonomy.cdm.model.description.StatisticalMeasure;
60
import eu.etaxonomy.cdm.model.description.StatisticalMeasurementValue;
61
import eu.etaxonomy.cdm.model.description.TaxonDescription;
62
import eu.etaxonomy.cdm.model.description.TextData;
63
import eu.etaxonomy.cdm.model.location.NamedArea;
64
import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
65
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
66
import eu.etaxonomy.cdm.model.reference.CdmLinkSource;
67
import eu.etaxonomy.cdm.model.taxon.Classification;
68
import eu.etaxonomy.cdm.model.taxon.Taxon;
69
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
70
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
71
import eu.etaxonomy.cdm.model.term.DefinedTermBase;
72
import eu.etaxonomy.cdm.persistence.dao.description.IDescriptiveDataSetDao;
73
import eu.etaxonomy.cdm.persistence.dao.term.IDefinedTermDao;
74
import eu.etaxonomy.cdm.persistence.dto.DescriptiveDataSetBaseDto;
75
import eu.etaxonomy.cdm.persistence.dto.MergeResult;
76
import eu.etaxonomy.cdm.persistence.dto.SpecimenNodeWrapper;
77
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
78
import eu.etaxonomy.cdm.persistence.dto.TermDto;
79
import eu.etaxonomy.cdm.persistence.dto.TermTreeDto;
80
import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;
81
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
82
import eu.etaxonomy.cdm.strategy.generate.PolytomousKeyGenerator;
83
import eu.etaxonomy.cdm.strategy.generate.PolytomousKeyGeneratorConfigurator;
84

    
85
@Service
86
@Transactional(readOnly=true)
87
public class DescriptiveDataSetService
88
        extends IdentifiableServiceBase<DescriptiveDataSet, IDescriptiveDataSetDao>
89
        implements IDescriptiveDataSetService {
90

    
91
    private static Logger logger = LogManager.getLogger(DescriptiveDataSetService.class);
92

    
93
    @Autowired
94
    private IOccurrenceService occurrenceService;
95

    
96
    @Autowired
97
    private ITaxonService taxonService;
98

    
99
    @Autowired
100
    private IPolytomousKeyService polytomousKeyService;
101

    
102
    @Autowired
103
    private IDefinedTermDao termDao;
104

    
105
    @Autowired
106
    private IDescriptionService descriptionService;
107

    
108
    @Autowired
109
    private ITaxonNodeService taxonNodeService;
110

    
111
	@Override
112
	@Autowired
113
	protected void setDao(IDescriptiveDataSetDao dao) {
114
		this.dao = dao;
115
	}
116

    
117
	@Override
118
    public Map<DescriptionBase, Set<DescriptionElementBase>> getDescriptionElements(DescriptiveDataSet descriptiveDataSet, Set<Feature> features, Integer pageSize,	Integer pageNumber,
119
			List<String> propertyPaths) {
120
		return dao.getDescriptionElements(descriptiveDataSet, features, pageSize, pageNumber, propertyPaths);
121
	}
122

    
123
	@Override
124
	public <T extends DescriptionElementBase> Map<UuidAndTitleCache, Map<UUID, Set<T>>> getTaxonFeatureDescriptionElementMap(
125
			Class<T> clazz, UUID descriptiveDataSetUuid, DescriptiveSystemRole role) {
126
		return dao.getTaxonFeatureDescriptionElementMap(clazz, descriptiveDataSetUuid, role);
127
	}
128

    
129
	@Override
130
    public List<UuidAndTitleCache<DescriptiveDataSet>> getDescriptiveDataSetUuidAndTitleCache(Integer limitOfInitialElements, String pattern) {
131
        return dao.getDescriptiveDataSetUuidAndTitleCache( limitOfInitialElements, pattern);
132
    }
133

    
134
	@Override
135
	public List<RowWrapperDTO<?>> getRowWrapper(UUID descriptiveDataSetUuid, IProgressMonitor monitor) {
136
	    DescriptiveDataSetBaseDto datasetDto = dao.getDescriptiveDataSetDtoByUuid(descriptiveDataSetUuid);
137
//	    DescriptiveDataSet descriptiveDataSet = load(descriptiveDataSetUuid);
138
	    monitor.beginTask("Load row wrapper", datasetDto.getDescriptionUuids().size());
139
	    List<RowWrapperDTO<?>> wrappers = new ArrayList<>();
140
	    Set<UUID> descriptions = datasetDto.getDescriptionUuids();
141
	    for (UUID description : descriptions) {
142
            if(monitor.isCanceled()){
143
                return new ArrayList<>();
144
            }
145
            DescriptionBaseDto descDto = descriptionService.loadDto(description);
146
            RowWrapperDTO<?> rowWrapper = null;
147
            if (descDto != null && descDto.getTaxonDto() != null &&
148
                    (descDto.getTypes().contains(DescriptionType.DEFAULT_VALUES_FOR_AGGREGATION)
149
                            || descDto.getTypes().contains(DescriptionType.AGGREGATED_STRUC_DESC)
150
                            || descDto.getTypes().contains(DescriptionType.SECONDARY_DATA)
151
                            )){
152
                rowWrapper = createTaxonRowWrapper(descDto, datasetDto.getUuid());
153
            }
154
            else if (descDto != null &&descDto.getSpecimenDto() != null && (descDto.getTypes() == null ||
155
                    !descDto.getTypes().contains(DescriptionType.CLONE_FOR_SOURCE))){
156
                rowWrapper = createSpecimenRowWrapper(descDto, descriptiveDataSetUuid);
157
            }
158
            if(rowWrapper!=null){
159
                wrappers.add(rowWrapper);
160
            }
161
            monitor.worked(1);
162
        }
163
	    return wrappers;
164
	}
165

    
166
    @Override
167
    public Collection<SpecimenNodeWrapper> loadSpecimens(DescriptiveDataSet descriptiveDataSet){
168
        List<UUID> filteredNodes = findFilteredTaxonNodes(descriptiveDataSet);
169
        if(filteredNodes.isEmpty()){
170
            return Collections.emptySet();
171
        }
172
        Collection<SpecimenNodeWrapper> result = occurrenceService.listUuidAndTitleCacheByAssociatedTaxon(filteredNodes, null, null);
173

    
174
        return result;
175
    }
176

    
177
    @Override
178
    public Collection<SpecimenNodeWrapper> loadSpecimens(UUID descriptiveDataSetUuid){
179
        DescriptiveDataSet dataSet = load(descriptiveDataSetUuid);
180
        return loadSpecimens(dataSet);
181
    }
182

    
183

    
184
    @Override
185
    public List<UUID> findFilteredTaxonNodes(DescriptiveDataSet descriptiveDataSet){
186
        TaxonNodeFilter filter = TaxonNodeFilter.NewRankInstance(descriptiveDataSet.getMinRank(), descriptiveDataSet.getMaxRank());
187
        descriptiveDataSet.getGeoFilter().forEach(area -> filter.orArea(area.getUuid()));
188
        descriptiveDataSet.getTaxonSubtreeFilter().forEach(node -> filter.orSubtree(node));
189
        filter.setIncludeUnpublished(true);
190

    
191
        return taxonNodeService.uuidList(filter);
192
    }
193

    
194
    @Override
195
    public List<TaxonNode> loadFilteredTaxonNodes(DescriptiveDataSet descriptiveDataSet, List<String> propertyPaths){
196
        return taxonNodeService.load(findFilteredTaxonNodes(descriptiveDataSet), propertyPaths);
197
    }
198

    
199
    @Override
200
    public DescriptionBaseDto findDefaultDescription(UUID specimenDescriptionUuid, UUID dataSetUuid){
201
        DescriptionBaseDto specimenDescription = descriptionService.loadDto(specimenDescriptionUuid);
202
        DescriptiveDataSetBaseDto dataSet = dao.getDescriptiveDataSetDtoByUuid(dataSetUuid);
203
        TaxonNodeDto node = findTaxonNodeForDescription(specimenDescription, dataSet);
204
        return recurseDefaultDescription(node, dataSet);
205
    }
206

    
207
    private DescriptionBaseDto recurseDefaultDescription(TaxonNodeDto node, DescriptiveDataSetBaseDto dataSet){
208
        DescriptionBaseDto defaultDescription = null;
209
        if(node!=null && node.getTaxonUuid()!=null){
210
            defaultDescription = getTaxonDescriptionForDescriptiveDataSetAndType(dataSet, node.getTaxonUuid(), DescriptionType.DEFAULT_VALUES_FOR_AGGREGATION);
211
            if(defaultDescription==null && node.getParentUUID()!=null){
212
                defaultDescription = recurseDefaultDescription(taxonNodeService.dto(node.getParentUUID()), dataSet);
213
            }
214
        }
215
        return defaultDescription;
216
    }
217

    
218
    private TaxonNodeDto findTaxonNodeForDescription(DescriptionBaseDto description, DescriptiveDataSetBaseDto descriptiveDataSet){
219
        UuidAndTitleCache<SpecimenOrObservationBase> specimen = description.getSpecimenDto();
220
        //get taxon node
221

    
222
        
223
        return descriptionService.findTaxonNodeDtoForIndividualAssociation(specimen.getUuid(), descriptiveDataSet.getSubTreeFilter().iterator().next().getClassificationUUID());
224
        //NOTE: don't remove cast as it does not compile on some systems
225
//        List<DescriptionBaseDto> descDtos = descriptionService.loadDtos(descriptiveDataSet.getDescriptionUuids());
226
//        descriptionService.
227
//        Set<IndividualsAssociation> associations = descDtos
228
//                .stream()
229
//                .flatMap(desc->desc.getElements().stream())// put all description element in one stream
230
//                .filter(element->element.get)
231
//                .map(ia->(IndividualsAssociation)ia)
232
//                .collect(Collectors.toSet());
233
//        UUID classification = descriptiveDataSet.getSubTreeFilter().iterator().next().getClassificationUUID();
234
//        for (IndividualsAssociation individualsAssociation : associations) {
235
//            if(individualsAssociation.getAssociatedSpecimenOrObservation().equals(specimen)){
236
//                return ((TaxonDescription) individualsAssociation.getInDescription()).getTaxon().getTaxonNode(classification);
237
//            }
238
//        }
239
//        return null;
240
    }
241

    
242
    @Override
243
    public TaxonRowWrapperDTO createTaxonRowWrapper(UUID taxonDescriptionUuid, UUID descriptiveDataSetUuid) {
244
        DescriptionBaseDto description = descriptionService.loadDto(taxonDescriptionUuid);
245
        return createTaxonRowWrapper(description, descriptiveDataSetUuid);
246
    }
247

    
248
    @Override
249
    @Transactional(readOnly=false)
250
    public UpdateResult addRowWrapperToDataset(Collection<SpecimenRowWrapperDTO> wrappers, UUID datasetUuid, boolean addDatasetSource){
251
        UpdateResult result = new UpdateResult();
252
        DescriptiveDataSet dataSet = load(datasetUuid);
253
        result.setCdmEntity(dataSet);
254

    
255
        List<UUID> taxonUuids = wrappers.stream().map(wrapper->wrapper.getTaxonNode().getTaxonUuid()).collect(Collectors.toList());
256
        List<TaxonBase> taxa = taxonService.load(taxonUuids, Arrays.asList(new String[]{"descriptions"}));
257

    
258
        for (SpecimenRowWrapperDTO wrapper : wrappers) {
259
            Optional<TaxonBase> findAny = taxa.stream().filter(taxon->taxon.getUuid().equals(wrapper.getTaxonNode().getTaxonUuid())).findAny();
260
            if(!findAny.isPresent()){
261
                result.addException(new IllegalArgumentException("Could not create wrapper for "+ wrapper.getSpecimenDto().getLabel()));
262
                continue;
263
            }
264
            Taxon taxon = (Taxon) findAny.get();
265

    
266
            SpecimenOrObservationBase<?> specimen = occurrenceService.load(wrapper.getSpecimenDto().getUuid());
267

    
268
            TaxonDescription taxonDescription = taxon.getDescriptions().stream()
269
                    .filter(desc->desc.getTypes().contains(DescriptionType.INDIVIDUALS_ASSOCIATION))
270
                    .findFirst().orElseGet(()->{
271
                        TaxonDescription td = TaxonDescription.NewInstance(taxon);
272
                        td.addType(DescriptionType.INDIVIDUALS_ASSOCIATION);
273
                        td.setTitleCache("Specimens used by " + dataSet.getTitleCache() + " for " + getTaxonLabel(taxon), true);
274
                        return td;});
275
            IndividualsAssociation association = null;
276
            for (DescriptionElementBase el:taxonDescription.getElements()){
277
                if (el instanceof IndividualsAssociation){
278
                    IndividualsAssociation indAss = (IndividualsAssociation)el;
279
                    if (indAss.getAssociatedSpecimenOrObservation().getUuid().equals(specimen.getUuid())){
280
                        association = indAss;
281
                    }
282
                }
283
            }
284

    
285
            if (association == null){
286
                association = IndividualsAssociation.NewInstance(specimen);
287
                taxonDescription.addElement(association);
288
                taxonService.saveOrUpdate(taxon);
289
                result.addUpdatedObject(taxon);
290
            }
291

    
292

    
293

    
294
            UUID specimenDescriptionUuid = wrapper.getDescription().getDescriptionUuid();
295
            DescriptionBaseDto descriptionDto = wrapper.getDescription();
296
            DescriptionBase<?> specimenDescription =  descriptionService.load(specimenDescriptionUuid);
297
            //if description already exist use the loaded one and add changed data otherwise create a new one and add to specimen
298
            if (specimenDescription == null){
299
                specimenDescription = SpecimenDescription.NewInstance(specimen);
300
                specimenDescription.setUuid(specimenDescriptionUuid);
301
                List<DescriptionElementDto> elementDtos = descriptionDto.getElements();
302

    
303
                for (DescriptionElementDto elementDto: elementDtos){
304
                    if (elementDto instanceof CategoricalDataDto){
305
                        eu.etaxonomy.cdm.model.description.Character feature = DefinedTermBase.getTermByClassAndUUID(eu.etaxonomy.cdm.model.description.Character.class, elementDto.getFeatureUuid());
306
                        CategoricalData data = CategoricalData.NewInstance(feature);
307
                        for (StateDataDto stateDto:((CategoricalDataDto) elementDto).getStates()){
308
                            State state = DefinedTermBase.getTermByClassAndUUID(State.class, stateDto.getState().getUuid());
309
                            data.addStateData(state);
310
                            specimenDescription.addElement(data);
311
                        }
312
                    }
313
                    if (elementDto instanceof QuantitativeDataDto){
314
                        eu.etaxonomy.cdm.model.description.Character feature = DefinedTermBase.getTermByClassAndUUID(eu.etaxonomy.cdm.model.description.Character.class, elementDto.getFeatureUuid());
315
                        QuantitativeData data = QuantitativeData.NewInstance(feature);
316
                        if (((QuantitativeDataDto) elementDto).getMeasurementUnit() != null){
317
                            MeasurementUnit unit = DefinedTermBase.getTermByClassAndUUID(MeasurementUnit.class, ((QuantitativeDataDto) elementDto).getMeasurementUnit().getUuid());
318
                            data.setUnit(unit);
319
                        }
320

    
321
                        for (StatisticalMeasurementValueDto stateDto:((QuantitativeDataDto) elementDto).getValues()){
322
                            StatisticalMeasure statMeasure = DefinedTermBase.getTermByClassAndUUID(StatisticalMeasure.class, stateDto.getType().getUuid());
323
                            StatisticalMeasurementValue value = StatisticalMeasurementValue.NewInstance(statMeasure, stateDto.getValue());
324
                            data.addStatisticalValue(value);
325
                            specimenDescription.addElement(data);
326
                        }
327
                    }
328
                }
329

    
330
            }else {
331
                List<DescriptionElementDto> elementDtos = descriptionDto.getElements();
332
                for (DescriptionElementDto elementDto: elementDtos){
333
                    if (elementDto instanceof CategoricalDataDto){
334
                        eu.etaxonomy.cdm.model.description.Character feature = DefinedTermBase.getTermByClassAndUUID(eu.etaxonomy.cdm.model.description.Character.class, elementDto.getFeatureUuid());
335
                        List<DescriptionElementBase> uniqueElementList = specimenDescription.getElements().stream().filter(element -> element.getUuid().equals(elementDto.getElementUuid())).collect(Collectors.toList());
336
                        List<State> allStates = new ArrayList<>();
337
                        CategoricalData element = null;
338
                        if (uniqueElementList.size() == 1){
339
                            element = HibernateProxyHelper.deproxy(uniqueElementList.get(0), CategoricalData.class);
340
                        }else{
341
                            element = CategoricalData.NewInstance(feature);
342
                        }
343
                        for (StateDataDto stateDto:((CategoricalDataDto) elementDto).getStates()){
344
                            State state = DefinedTermBase.getTermByClassAndUUID(State.class, stateDto.getState().getUuid());
345
                            allStates.add(state);
346
                        }
347
                        element.setStateDataOnly(allStates);
348
                    }
349
                    if (elementDto instanceof QuantitativeDataDto){
350
                        eu.etaxonomy.cdm.model.description.Character feature = DefinedTermBase.getTermByClassAndUUID(eu.etaxonomy.cdm.model.description.Character.class, elementDto.getFeatureUuid());
351
                        QuantitativeData data = QuantitativeData.NewInstance(feature);
352
                        if (((QuantitativeDataDto) elementDto).getMeasurementUnit() != null){
353
                            MeasurementUnit unit = DefinedTermBase.getTermByClassAndUUID(MeasurementUnit.class, ((QuantitativeDataDto) elementDto).getMeasurementUnit().getUuid());
354
                            data.setUnit(unit);
355
                        }
356

    
357
                        for (StatisticalMeasurementValueDto stateDto:((QuantitativeDataDto) elementDto).getValues()){
358
                            StatisticalMeasure statMeasure = DefinedTermBase.getTermByClassAndUUID(StatisticalMeasure.class, stateDto.getType().getUuid());
359
                            StatisticalMeasurementValue value = StatisticalMeasurementValue.NewInstance(statMeasure, stateDto.getValue());
360
                            data.addStatisticalValue(value);
361
                            specimenDescription.addElement(data);
362
                        }
363
                    }
364
                }
365
            }
366
            if(addDatasetSource){
367
                for (IdentifiableSource source: dataSet.getSources()) {
368
                    try {
369
                        specimenDescription.addSource(source.clone());
370
                    } catch (CloneNotSupportedException e) {
371
                        //nothing
372
                    }
373
                }
374

    
375
            }
376

    
377
            //add specimen description to data set
378
            specimenDescription.addDescriptiveDataSet(dataSet);
379
            //add taxon description with IndividualsAssociation to the specimen to data set
380
            taxonDescription.addDescriptiveDataSet(dataSet);
381
            result.addUpdatedObject(specimen);
382
            result.addUpdatedObject(specimenDescription);
383
            result.addUpdatedObject(taxonDescription);
384
        }
385
        saveOrUpdate(dataSet);
386
        return result;
387
    }
388

    
389
    private String getTaxonLabel(Taxon taxon) {
390
        if (taxon.getName() != null){
391
            return taxon.getName().getTitleCache();
392
        }else{
393
            return taxon.getTitleCache();
394
        }
395
    }
396

    
397
    private SpecimenRowWrapperDTO createSpecimenRowWrapper(DescriptionBaseDto description, UUID taxonNodeUuid,
398
            UUID datasetUuid) {
399
        TaxonNodeDto taxonNode = taxonNodeService.dto(taxonNodeUuid);
400
        DescriptiveDataSetBaseDto descriptiveDataSet = getDescriptiveDataSetDtoByUuid(datasetUuid);
401
//        UuidAndTitleCache<SpecimenOrObservationBase> specimen = description.getSpecimenDto();
402
        SpecimenOrObservationBase specimen = occurrenceService.find(description.getSpecimenDto().getUuid());
403

    
404
        //supplemental information
405
        if(taxonNode==null){
406
            taxonNode = findTaxonNodeForDescription(description, descriptiveDataSet);
407
        }
408
        FieldUnit fieldUnit = null;
409
        String identifier = null;
410
        NamedArea country = null;
411
        if(taxonNode==null){
412
            return null;
413
        }
414
        //taxon node was found
415

    
416
        //get field unit
417
        Collection<FieldUnit> fieldUnits = occurrenceService.findFieldUnits(specimen.getUuid(),
418
                Arrays.asList(new String[]{
419
                        "gatheringEvent",
420
                        "gatheringEvent.country"
421
                }));
422
        if(fieldUnits.size()>1){
423
            logger.error("More than one or no field unit found for specimen"); //$NON-NLS-1$
424
            return null;
425
        }
426
        else{
427
            if (fieldUnits.size()>0){
428
                fieldUnit = fieldUnits.iterator().next();
429
            }
430
        }
431
        //get identifier
432

    
433
        identifier = occurrenceService.getMostSignificantIdentifier(specimen.getUuid());
434
        //get country
435
        if(fieldUnit != null && fieldUnit.getGatheringEvent() != null){
436
            country = fieldUnit.getGatheringEvent().getCountry();
437
        }
438
        //get default taxon description
439
//        TaxonDescription defaultTaxonDescription = findDefaultDescription(description.getUuid(), descriptiveDataSet.getUuid());
440
        DescriptionBaseDto defaultTaxonDescription = recurseDefaultDescription(taxonNode, descriptiveDataSet);
441
        TaxonRowWrapperDTO taxonRowWrapper = defaultTaxonDescription != null
442
                ? createTaxonRowWrapper(defaultTaxonDescription.getDescriptionUuid(), descriptiveDataSet.getUuid()) : null;
443
//                use description not specimen for specimenRow
444
        SpecimenRowWrapperDTO specimenRowWrapperDTO = new SpecimenRowWrapperDTO(description, SpecimenOrObservationDTOFactory.fromEntity(specimen), specimen.getRecordBasis(), taxonNode, fieldUnit, identifier, country);
445
        specimenRowWrapperDTO.setDefaultDescription(taxonRowWrapper);
446
        return specimenRowWrapperDTO;
447
    }
448

    
449
    @Override
450
    public SpecimenRowWrapperDTO createSpecimenRowWrapper(DescriptionBaseDto description, UUID descriptiveDataSetUuid){
451
        return createSpecimenRowWrapper(description, null, descriptiveDataSetUuid);
452
	}
453

    
454
    @Override
455
    public SpecimenRowWrapperDTO createSpecimenRowWrapper(UUID specimenUuid, UUID taxonNodeUuid, UUID descriptiveDataSetUuid){
456

    
457
        SpecimenOrObservationBase<?> specimen = occurrenceService.load(specimenUuid);
458
        DescriptionBaseDto specimenDescription = findSpecimenDescription(descriptiveDataSetUuid, specimen);
459
        return createSpecimenRowWrapper(specimenDescription, taxonNodeUuid, descriptiveDataSetUuid);
460
    }
461

    
462
    @Override
463
    @Transactional(readOnly = false)
464
    public UpdateResult updateCaches(Class<? extends DescriptiveDataSet> clazz, Integer stepSize,
465
            IIdentifiableEntityCacheStrategy<DescriptiveDataSet> cacheStrategy, IProgressMonitor monitor) {
466
        if (clazz == null) {
467
            clazz = DescriptiveDataSet.class;
468
        }
469
        return super.updateCachesImpl(clazz, stepSize, cacheStrategy, monitor);
470
    }
471

    
472
//    private TaxonDescription findTaxonDescriptionByDescriptionType(DescriptiveDataSetBaseDto dataSet, UUID taxonUuid, DescriptionType descriptionType){
473
//        descriptionService.find
474
//        Optional<TaxonDescription> first = taxon.getDescriptions().stream()
475
//                .filter(desc -> desc.getTypes().stream().anyMatch(type -> type.equals(descriptionType)))
476
//                .filter(desc -> dataSet.getDescriptions().contains(desc))
477
//                .findFirst();
478
//        if(first.isPresent()){
479
//            return HibernateProxyHelper.deproxy(descriptionService.load(first.get().getUuid(),
480
//                  Arrays.asList("taxon", "descriptionElements", "descriptionElements.feature")), TaxonDescription.class);
481
//        }
482
//        return null;
483
//    }
484
//
485
//    @Override
486
//    public TaxonDescription findTaxonDescriptionByDescriptionType(UUID dataSetUuid, UUID taxonNodeUuid, DescriptionType descriptionType){
487
//        DescriptiveDataSet dataSet = load(dataSetUuid);
488
//        TaxonNode taxonNode = taxonNodeService.load(taxonNodeUuid);
489
//        return findTaxonDescriptionByDescriptionType(dataSet, taxonNode.getTaxon(), descriptionType);
490
//    }
491
    @Override
492
    public DescriptionBaseDto getTaxonDescriptionForDescriptiveDataSetAndType(DescriptiveDataSetBaseDto dataSet, UUID taxonUuid, DescriptionType descriptionType){
493
        Session session = getSession();
494
        String queryString = "SELECT d.uuid FROM DescriptiveDataSet a JOIN a.descriptions as d JOIN d.taxon t WHERE t.uuid = :taxonuuid AND a.uuid = :dataSetUuid  and :descriptionType IN d.types";
495

    
496
        Query query;
497
        query = session.createQuery(queryString);
498
        query.setParameter("taxonuuid", taxonUuid);
499
        query.setParameter("dataSetUuid", dataSet.getUuid());
500
        query.setParameter("descriptionType", descriptionType.getKey());
501

    
502
        @SuppressWarnings("unchecked")
503
        List<UUID> result = query.list();
504
        List<DescriptionBaseDto> list = new ArrayList<>();
505
        list.addAll(descriptionService.loadDtos(new HashSet(result)));
506

    
507
        if (list.isEmpty()){
508
            return null;
509
        }else {
510
		List<DescriptionBaseDto> correctTypeOnly = new ArrayList<>();
511
		for (DescriptionBaseDto dto: list) {
512
			if (dto.getTypes().contains(descriptionType)) {
513
				correctTypeOnly.add(dto);
514
			}
515
		}
516
		if (correctTypeOnly.isEmpty()) {
517
			return null;
518
		}else {
519
			return correctTypeOnly.get(0);
520
		}
521
        }
522

    
523
//        return list.get(0);
524
    }
525

    
526
    @Override
527
    @Transactional(readOnly=false)
528
    public UpdateResult generatePolytomousKey(UUID descriptiveDataSetUuid, UUID taxonUuid) {
529
        UpdateResult result = new UpdateResult();
530

    
531
        PolytomousKeyGeneratorConfigurator keyConfig = new PolytomousKeyGeneratorConfigurator();
532
        DescriptiveDataSet descriptiveDataSet = load(descriptiveDataSetUuid);
533
        keyConfig.setDataSet(descriptiveDataSet);
534
        PolytomousKey key = new PolytomousKeyGenerator().invoke(keyConfig);
535
        IdentifiableServiceConfiguratorImpl<PolytomousKey> serviceConfig= new IdentifiableServiceConfiguratorImpl<>();
536
        serviceConfig.setTitleSearchString(descriptiveDataSet.getTitleCache());
537
        List<PolytomousKey> list = polytomousKeyService.findByTitle(serviceConfig).getRecords();
538
        if(list!=null){
539
            list.forEach(polytomousKey->polytomousKeyService.delete(polytomousKey));
540
        }
541
        key.setTitleCache(descriptiveDataSet.getTitleCache(), true);
542

    
543
        Taxon taxon = (Taxon) taxonService.load(taxonUuid);
544
        key.addTaxonomicScope(taxon);
545

    
546
        polytomousKeyService.saveOrUpdate(key);
547

    
548
        result.setCdmEntity(key);
549
        result.addUpdatedObject(taxon);
550
        return result;
551
    }
552

    
553
    @Override
554
    @Transactional(readOnly=false)
555
    public DeleteResult removeDescription(UUID descriptionUuid, UUID descriptiveDataSetUuid, RemoveDescriptionsFromDescriptiveDataSetConfigurator config) {
556
        DeleteResult result = new DeleteResult();
557
        DescriptiveDataSet dataSet = load(descriptiveDataSetUuid);
558
        DescriptionBase<?> descriptionBase = descriptionService.load(descriptionUuid);
559
        if(dataSet==null || descriptionBase==null){
560
            result.setError();
561
        }
562
        else{
563
            removeDescriptionFromDataSet(result, dataSet, descriptionBase, config);
564
        }
565
        return result;
566
    }
567

    
568

    
569
    @Override
570
    @Transactional(readOnly=false)
571
    public DeleteResult removeDescriptions(List<UUID> descriptionUuids, UUID descriptiveDataSetUuid, RemoveDescriptionsFromDescriptiveDataSetConfigurator config) {
572
        DeleteResult result = new DeleteResult();
573
        DescriptiveDataSet dataSet = load(descriptiveDataSetUuid);
574
        List<DescriptionBase> descriptions = descriptionService.load(descriptionUuids, null);
575
        if(dataSet==null || descriptions==null){
576
            result.setError();
577
        }
578
        else{
579
            for (DescriptionBase<?> description: descriptions){
580
                removeDescriptionFromDataSet(result, dataSet, description, config);
581
            }
582
        }
583
        return result;
584
    }
585

    
586
    private void removeDescriptionFromDataSet(DeleteResult result, DescriptiveDataSet dataSet,
587
            DescriptionBase<?> description, RemoveDescriptionsFromDescriptiveDataSetConfigurator config) {
588
        if (description == null){
589
            return;
590
        }
591
        boolean success = dataSet.removeDescription(description);
592
        result.addDeletedObject(description);// remove taxon description with IndividualsAssociation from data set
593
        if(description instanceof SpecimenDescription){
594
            @SuppressWarnings({ "unchecked", "cast" })
595
            //NOTE: don't remove cast as it does not compile on some systems
596
            Set<IndividualsAssociation> associations = (Set<IndividualsAssociation>)dataSet.getDescriptions()
597
                    .stream()
598
                    .flatMap(desc->desc.getElements().stream())// put all description element in one stream
599
                    .filter(element->element instanceof IndividualsAssociation)
600
                    .map(ia->(IndividualsAssociation)ia)
601
                    .collect(Collectors.toSet());
602

    
603
            for (IndividualsAssociation individualsAssociation : associations) {
604
                if(individualsAssociation.getAssociatedSpecimenOrObservation().equals(description.getDescribedSpecimenOrObservation())){
605
                    dataSet.removeDescription(individualsAssociation.getInDescription());
606
                    result.addUpdatedObject(individualsAssociation.getInDescription());
607
                }
608
            }
609
        }
610
        if (description instanceof TaxonDescription){
611
            DeleteResult isDeletable = descriptionService.isDeletable(description.getUuid());
612
            for (CdmBase relatedCdmBase: isDeletable.getRelatedObjects()){
613
                if (relatedCdmBase instanceof CdmLinkSource){
614
                    CdmLinkSource linkSource = (CdmLinkSource)relatedCdmBase;
615
                    if (linkSource.getTarget().equals(this)){
616

    
617
                    }
618
                }
619
            }
620

    
621

    
622
        }
623
        if (!config.isOnlyRemoveDescriptionsFromDataSet()){
624
            DeleteResult deleteResult = descriptionService.deleteDescription(description);
625
            result.includeResult(deleteResult);
626
            result.addUpdatedObject(dataSet);
627
        }else{
628
            MergeResult<DescriptiveDataSet> mergeResult = dao.merge(dataSet, true);
629
            result.addUpdatedObject(mergeResult.getMergedEntity());
630
        }
631

    
632
        result.setStatus(success?Status.OK:Status.ERROR);
633
    }
634

    
635
    @Override
636
    @Transactional(readOnly = false)
637
    public DeleteResult delete(UUID datasetUuid, DeleteDescriptiveDataSetConfigurator config,  IProgressMonitor monitor){
638
        DescriptiveDataSet dataSet = dao.load(datasetUuid);
639
        monitor.beginTask("Delete Descriptive Dataset", dataSet.getDescriptions().size() +1);
640

    
641
        DeleteResult result = new DeleteResult();
642
        DeleteResult descriptionResult = new DeleteResult();
643
        if (!dataSet.getDescriptions().isEmpty()){
644
            Set<DescriptionBase> descriptions = new HashSet<>();;
645
            for (DescriptionBase<?> desc: dataSet.getDescriptions()){
646
                descriptions.add(desc);
647
            }
648
            monitor.subTask("Delete descriptions");
649
            for (DescriptionBase<?> desc: descriptions){
650
                dataSet.removeDescription(desc);
651
                if (desc instanceof SpecimenDescription && config.isDeleteAllSpecimenDescriptions()){
652
                    descriptionResult.includeResult(descriptionService.deleteDescription(desc));
653
                }else if (desc instanceof TaxonDescription){
654
                    if( desc.getTypes().contains(DescriptionType.DEFAULT_VALUES_FOR_AGGREGATION) && config.isDeleteAllDefaultDescriptions()){
655
                        descriptionResult.includeResult(descriptionService.deleteDescription(desc));
656
                    }else if (desc.getTypes().contains(DescriptionType.SECONDARY_DATA) && config.isDeleteAllLiteratureDescriptions()){
657
                        descriptionResult.includeResult(descriptionService.deleteDescription(desc));
658
                    }else if (desc.getTypes().contains(DescriptionType.AGGREGATED_STRUC_DESC) && config.isDeleteAllAggregatedDescriptions()){
659
                        descriptionResult.includeResult(descriptionService.deleteDescription(desc));
660
                    }
661
                }
662
            }
663
        }
664
        dao.delete(dataSet);
665
        monitor.worked(1);
666
        monitor.done();
667
        result.includeResult(descriptionResult);
668
        result.setStatus(Status.OK);
669
        result.addDeletedObject(dataSet);
670
        return result;
671
    }
672

    
673
    @Override
674
    @Transactional(readOnly=false)
675
    public TaxonRowWrapperDTO createTaxonDescription(UUID dataSetUuid, UUID taxonNodeUuid, DescriptionType descriptionType){
676
        DescriptiveDataSet dataSet = load(dataSetUuid);
677
        TaxonNode taxonNode = taxonNodeService.load(taxonNodeUuid, Arrays.asList("taxon"));
678
        TaxonDescription newTaxonDescription = TaxonDescription.NewInstance(taxonNode.getTaxon());
679
        newTaxonDescription.setTitleCache(dataSet.getLabel()+": "+newTaxonDescription.generateTitle(), true); //$NON-NLS-2$
680
        newTaxonDescription.getTypes().add(descriptionType);
681
        dataSet.addDescription(newTaxonDescription);
682
        saveOrUpdate(dataSet);
683
        return createTaxonRowWrapper(newTaxonDescription.getUuid(), dataSet.getUuid());
684
    }
685

    
686
    @Override
687
    public Map<UUID, List<TermDto>> getSupportedStatesForFeature(Set<UUID> featureUuids){
688
        return termDao.getSupportedStatesForFeature(featureUuids);
689
    }
690

    
691
    @Override
692
    @Transactional(readOnly=false)
693
    public DescriptionBaseDto findSpecimenDescription(UUID descriptiveDataSetUuid, SpecimenOrObservationBase specimen){
694
        DescriptiveDataSetBaseDto dataSet = this.getDescriptiveDataSetDtoByUuid(descriptiveDataSetUuid);
695
//        SpecimenOrObservationBase specimen = occurrenceService.load(specimenUuid);
696

    
697
        TermTreeDto datasetFeatures = dataSet.getDescriptiveSystem();
698
        List<DescriptionElementBase> matchingDescriptionElements = new ArrayList<>();
699

    
700
        for (SpecimenDescription specimenDescription : (Set<SpecimenDescription>) specimen.getDescriptions()) {
701
            specimenDescription = (SpecimenDescription) descriptionService.load(specimenDescription.getUuid());
702

    
703
            //check if description is already added to data set
704
            if(dataSet.getDescriptionUuids().contains(specimenDescription.getUuid()) ){
705
                return DescriptionBaseDto.fromDescription(specimenDescription);
706
            }
707

    
708
            //gather specimen description features and check for match with dataset features
709
            Set<Feature> specimenDescriptionFeatures = new HashSet<>();
710
            for (DescriptionElementBase specimenDescriptionElement : specimenDescription.getElements()) {
711
                Feature feature = specimenDescriptionElement.getFeature();
712
                specimenDescriptionFeatures.add(feature);
713
                boolean contains = false;
714
                for (TermDto featureDto:datasetFeatures.getTerms()){
715
                    if (featureDto.getUuid().equals(feature.getUuid())){
716
                        contains = true;
717
                        break;
718
                    }
719
                }
720
                if(contains && RowWrapperDTO.hasData(specimenDescriptionElement)){
721
                    matchingDescriptionElements.add(specimenDescriptionElement);
722
                }
723
            }
724
        }
725
        //Create new specimen description if description has not already been added to the dataset
726
        SpecimenDescription newDesription = SpecimenDescription.NewInstance(specimen);
727
        newDesription.setTitleCache("Dataset "+dataSet.getTitleCache()+": "+newDesription.generateTitle(), true); //$NON-NLS-2$
728

    
729
        //check for equals description element (same feature and same values)
730
        Map<Feature, List<DescriptionElementBase>> featureToElementMap = new HashMap<>();
731
        for(DescriptionElementBase element:matchingDescriptionElements){
732
            List<DescriptionElementBase> list = featureToElementMap.get(element.getFeature());
733
            if(list==null){
734
                list = new ArrayList<>();
735
            }
736
            list.add(element);
737
            featureToElementMap.put(element.getFeature(), list);
738
        }
739
        Set<DescriptionElementBase> descriptionElementsToClone = new HashSet<>();
740
        for(Feature feature:featureToElementMap.keySet()){
741
            List<DescriptionElementBase> elements = featureToElementMap.get(feature);
742
            //no duplicate description elements found for this feature
743
            if(elements.size()==1){
744
                descriptionElementsToClone.add(elements.get(0));
745
            }
746
            //duplicates found -> check if all are equal
747
            else{
748
                DescriptionElementBase match = null;
749
                for (DescriptionElementBase descriptionElementBase : elements) {
750
                    if(match==null){
751
                        match = descriptionElementBase;
752
                    }
753
                    else if(!new DescriptionElementCompareWrapper(match).equals(new DescriptionElementCompareWrapper(descriptionElementBase))){
754
                        match = null;
755
                        //TODO: propagate message
756
//                        MessagingUtils.informationDialog(Messages.CharacterMatrix_MULTIPLE_DATA,
757
//                                String.format(Messages.CharacterMatrix_MULTIPLE_DATA_MESSAGE, feature.getLabel()));
758
                        break;
759
                    }
760
                }
761
                if(match!=null){
762
                    descriptionElementsToClone.add(match);
763
                }
764
            }
765
        }
766
        //clone matching descriptionElements
767
        for (DescriptionElementBase descriptionElementBase : descriptionElementsToClone) {
768
            DescriptionElementBase clone;
769
            clone = descriptionElementBase.clone(newDesription);
770
            clone.getSources().forEach(source -> {
771
                if(descriptionElementBase instanceof CategoricalData){
772
                    TextData label = new DefaultCategoricalDescriptionBuilder().build((CategoricalData) descriptionElementBase, Arrays.asList(new Language[]{Language.DEFAULT()}));
773
                    source.setOriginalNameString(label.getText(Language.DEFAULT()));
774
                }
775
                else if(descriptionElementBase instanceof QuantitativeData){
776
                    TextData label = new DefaultQuantitativeDescriptionBuilder().build((QuantitativeData) descriptionElementBase, Arrays.asList(new Language[]{Language.DEFAULT()}));
777
                    source.setOriginalNameString(label.getText(Language.DEFAULT()));
778
                }
779
            });
780
        }
781

    
782
        //add sources of data set
783
//        if(addDatasetSource){
784
//            dataSet.getSources().forEach(source->{
785
//                try {
786
//                    newDesription.addSource(source.clone());
787
//                } catch (CloneNotSupportedException e) {
788
//                    //nothing
789
//                }
790
//            });
791
//        }
792
        return DescriptionBaseDto.fromDescription(newDesription);
793

    
794
    }
795

    
796
    //TODO: this should either be solved in the model class itself
797
    //OR this should cover all possibilities including modifiers for example
798
    private class DescriptionElementCompareWrapper {
799

    
800
        private DescriptionElementBase element;
801
        private Set<UUID> stateUuids = new HashSet<>();
802
        private Set<BigDecimal> avgs = new HashSet<>();
803
        private Set<BigDecimal> exacts = new HashSet<>();
804
        private Set<BigDecimal> maxs = new HashSet<>();
805
        private Set<BigDecimal> mins = new HashSet<>();
806
        private Set<BigDecimal> sampleSizes = new HashSet<>();
807
        private Set<BigDecimal> standardDevs = new HashSet<>();
808
        private Set<BigDecimal> lowerBounds = new HashSet<>();
809
        private Set<BigDecimal> upperBounds = new HashSet<>();
810
        private Set<BigDecimal> variances = new HashSet<>();
811

    
812
        public DescriptionElementCompareWrapper(DescriptionElementBase element) {
813
            this.element = element;
814
            if(element.isInstanceOf(CategoricalData.class)){
815
                CategoricalData elementData = (CategoricalData)element;
816
                elementData.getStatesOnly().forEach(state->stateUuids.add(state.getUuid()));
817
            }
818
            else if(element.isInstanceOf(QuantitativeData.class)){
819
                QuantitativeData elementData = (QuantitativeData)element;
820
                elementData.getStatisticalValues().forEach(value->{
821
                    if(value.getType().equals(StatisticalMeasure.AVERAGE())){
822
                        avgs.add(value.getValue());
823
                    }
824
                    else if(value.getType().equals(StatisticalMeasure.EXACT_VALUE())){
825
                        exacts.add(value.getValue());
826

    
827
                    }
828
                    else if(value.getType().equals(StatisticalMeasure.MAX())){
829
                        maxs.add(value.getValue());
830
                    }
831
                    else if(value.getType().equals(StatisticalMeasure.MIN())){
832
                        mins.add(value.getValue());
833
                    }
834
                    else if(value.getType().equals(StatisticalMeasure.SAMPLE_SIZE())){
835
                        sampleSizes.add(value.getValue());
836

    
837
                    }
838
                    else if(value.getType().equals(StatisticalMeasure.STANDARD_DEVIATION())){
839
                        standardDevs.add(value.getValue());
840
                    }
841
                    else if(value.getType().equals(StatisticalMeasure.TYPICAL_LOWER_BOUNDARY())){
842
                        lowerBounds.add(value.getValue());
843

    
844
                    }
845
                    else if(value.getType().equals(StatisticalMeasure.TYPICAL_UPPER_BOUNDARY())){
846
                        upperBounds.add(value.getValue());
847
                    }
848
                    else if(value.getType().equals(StatisticalMeasure.VARIANCE())){
849
                        variances.add(value.getValue());
850
                    }
851
                });
852
            }
853
        }
854

    
855
        @Override
856
        public int hashCode() {
857
            final int prime = 31;
858
            int result = 1;
859
            result = prime * result + getOuterType().hashCode();
860
            result = prime * result + ((avgs == null) ? 0 : avgs.hashCode());
861
            result = prime * result + ((element == null) ? 0 : element.hashCode());
862
            result = prime * result + ((exacts == null) ? 0 : exacts.hashCode());
863
            result = prime * result + ((lowerBounds == null) ? 0 : lowerBounds.hashCode());
864
            result = prime * result + ((maxs == null) ? 0 : maxs.hashCode());
865
            result = prime * result + ((mins == null) ? 0 : mins.hashCode());
866
            result = prime * result + ((sampleSizes == null) ? 0 : sampleSizes.hashCode());
867
            result = prime * result + ((standardDevs == null) ? 0 : standardDevs.hashCode());
868
            result = prime * result + ((stateUuids == null) ? 0 : stateUuids.hashCode());
869
            result = prime * result + ((upperBounds == null) ? 0 : upperBounds.hashCode());
870
            result = prime * result + ((variances == null) ? 0 : variances.hashCode());
871
            return result;
872
        }
873

    
874
        @Override
875
        public boolean equals(Object obj) {
876
            if (this == obj) {
877
                return true;
878
            }
879
            if (obj == null) {
880
                return false;
881
            }
882
            if (getClass() != obj.getClass()) {
883
                return false;
884
            }
885
            DescriptionElementCompareWrapper other = (DescriptionElementCompareWrapper) obj;
886
            if (!getOuterType().equals(other.getOuterType())) {
887
                return false;
888
            }
889
            if (avgs == null) {
890
                if (other.avgs != null) {
891
                    return false;
892
                }
893
            } else if (!avgs.equals(other.avgs)) {
894
                return false;
895
            }
896
            if (element == null) {
897
                if (other.element != null) {
898
                    return false;
899
                }
900
            } else if (!element.equals(other.element)) {
901
                return false;
902
            }
903
            if (exacts == null) {
904
                if (other.exacts != null) {
905
                    return false;
906
                }
907
            } else if (!exacts.equals(other.exacts)) {
908
                return false;
909
            }
910
            if (lowerBounds == null) {
911
                if (other.lowerBounds != null) {
912
                    return false;
913
                }
914
            } else if (!lowerBounds.equals(other.lowerBounds)) {
915
                return false;
916
            }
917
            if (maxs == null) {
918
                if (other.maxs != null) {
919
                    return false;
920
                }
921
            } else if (!maxs.equals(other.maxs)) {
922
                return false;
923
            }
924
            if (mins == null) {
925
                if (other.mins != null) {
926
                    return false;
927
                }
928
            } else if (!mins.equals(other.mins)) {
929
                return false;
930
            }
931
            if (sampleSizes == null) {
932
                if (other.sampleSizes != null) {
933
                    return false;
934
                }
935
            } else if (!sampleSizes.equals(other.sampleSizes)) {
936
                return false;
937
            }
938
            if (standardDevs == null) {
939
                if (other.standardDevs != null) {
940
                    return false;
941
                }
942
            } else if (!standardDevs.equals(other.standardDevs)) {
943
                return false;
944
            }
945
            if (stateUuids == null) {
946
                if (other.stateUuids != null) {
947
                    return false;
948
                }
949
            } else if (!stateUuids.equals(other.stateUuids)) {
950
                return false;
951
            }
952
            if (upperBounds == null) {
953
                if (other.upperBounds != null) {
954
                    return false;
955
                }
956
            } else if (!upperBounds.equals(other.upperBounds)) {
957
                return false;
958
            }
959
            if (variances == null) {
960
                if (other.variances != null) {
961
                    return false;
962
                }
963
            } else if (!variances.equals(other.variances)) {
964
                return false;
965
            }
966
            return true;
967
        }
968

    
969
        private DescriptiveDataSetService getOuterType() {
970
            return DescriptiveDataSetService.this;
971
        }
972
    }
973

    
974
    @Override
975
    public DescriptiveDataSetBaseDto getDescriptiveDataSetDtoByUuid(UUID uuid) {
976
        return dao.getDescriptiveDataSetDtoByUuid(uuid);
977
    }
978

    
979
    @Override
980
    public TaxonRowWrapperDTO createTaxonRowWrapper(DescriptionBaseDto description, UUID descriptiveDataSetUuid) {
981
        Classification classification = null;
982
        DescriptiveDataSet descriptiveDataSet = dao.load(descriptiveDataSetUuid, null);
983
        Optional<TaxonNode> first = descriptiveDataSet.getTaxonSubtreeFilter().stream()
984
                .filter(node->node.getClassification()!=null).findFirst();
985
        Optional<Classification> classificationOptional = first.map(node->node.getClassification());
986
        Set<DescriptionBaseDto> descriptions = new HashSet<>();
987
        TaxonNodeDto nodeDto = null;
988
        if(classificationOptional.isPresent()){
989
            classification = classificationOptional.get();
990
            nodeDto = taxonNodeService.dto(description.getTaxonDto().getUuid(), classification.getUuid());
991
        }
992

    
993
        return new TaxonRowWrapperDTO(description, nodeDto, descriptions);
994
    }
995

    
996
//    @Override
997
//    public DescriptionBaseDto findTaxonDescriptionByDescriptionType(UUID dataSetUuid, UUID taxonNodeUuid, DescriptionType descriptionType){
998
//      DescriptiveDataSetBaseDto dataSet = getDescriptiveDataSetDtoByUuid(dataSetUuid);
999
//      TaxonNode taxonNode = taxonNodeService.load(taxonNodeUuid);
1000
//      return findTaxonDescriptionByDescriptionType(dataSet, taxonNode.getTaxon(), descriptionType);
1001
//  }
1002

    
1003
}
(13-13/95)