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;
18
import org.apache.logging.log4j.Logger;
19
import org.hibernate.Query;
20
import org.hibernate.Session;
21
import org.springframework.beans.factory.annotation.Autowired;
22
import org.springframework.stereotype.Service;
23
import org.springframework.transaction.annotation.Transactional;
24

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

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

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

    
94
    @Autowired
95
    private IOccurrenceService occurrenceService;
96

    
97
    @Autowired
98
    private ITaxonService taxonService;
99

    
100
    @Autowired
101
    private IPolytomousKeyService polytomousKeyService;
102

    
103
    @Autowired
104
    private IDefinedTermDao termDao;
105

    
106
    @Autowired
107
    private IDescriptionService descriptionService;
108

    
109
    @Autowired
110
    private ITaxonNodeService taxonNodeService;
111

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

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

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

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

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

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

    
175
        return result;
176
    }
177

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

    
184

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

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

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

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

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

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

    
223

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

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

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

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

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

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

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

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

    
293

    
294

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

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

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

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

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

    
376
            }
377

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

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

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

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

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

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

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

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

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

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

    
473
//    private TaxonDescription findTaxonDescriptionByDescriptionType(DescriptiveDataSetBaseDto dataSet, UUID taxonUuid, DescriptionType descriptionType){
474
//        descriptionService.find
475
//        Optional<TaxonDescription> first = taxon.getDescriptions().stream()
476
//                .filter(desc -> desc.getTypes().stream().anyMatch(type -> type.equals(descriptionType)))
477
//                .filter(desc -> dataSet.getDescriptions().contains(desc))
478
//                .findFirst();
479
//        if(first.isPresent()){
480
//            return HibernateProxyHelper.deproxy(descriptionService.load(first.get().getUuid(),
481
//                  Arrays.asList("taxon", "descriptionElements", "descriptionElements.feature")), TaxonDescription.class);
482
//        }
483
//        return null;
484
//    }
485
//
486
//    @Override
487
//    public TaxonDescription findTaxonDescriptionByDescriptionType(UUID dataSetUuid, UUID taxonNodeUuid, DescriptionType descriptionType){
488
//        DescriptiveDataSet dataSet = load(dataSetUuid);
489
//        TaxonNode taxonNode = taxonNodeService.load(taxonNodeUuid);
490
//        return findTaxonDescriptionByDescriptionType(dataSet, taxonNode.getTaxon(), descriptionType);
491
//    }
492
    @Override
493
    public DescriptionBaseDto getTaxonDescriptionForDescriptiveDataSetAndType(DescriptiveDataSetBaseDto dataSet, UUID taxonUuid, DescriptionType descriptionType){
494
        Session session = getSession();
495
        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";
496

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

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

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

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

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

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

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

    
547
        polytomousKeyService.saveOrUpdate(key);
548

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

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

    
569

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

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

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

    
618
                    }
619
                }
620
            }
621

    
622

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

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

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

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

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

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

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

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

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

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

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

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

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

    
795
    }
796

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1004
}
(13-13/95)