Project

General

Profile

Download (16.9 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2018 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9
package eu.etaxonomy.cdm.api.service.dto;
10

    
11
import java.io.Serializable;
12
import java.math.BigDecimal;
13
import java.util.ArrayList;
14
import java.util.Collection;
15
import java.util.Collections;
16
import java.util.Comparator;
17
import java.util.HashMap;
18
import java.util.HashSet;
19
import java.util.List;
20
import java.util.Map;
21
import java.util.Set;
22
import java.util.UUID;
23
import java.util.stream.Collectors;
24

    
25
import org.apache.commons.lang3.StringUtils;
26

    
27
import eu.etaxonomy.cdm.model.description.CategoricalData;
28
import eu.etaxonomy.cdm.model.description.Character;
29
import eu.etaxonomy.cdm.model.description.DescriptionBase;
30
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
31
import eu.etaxonomy.cdm.model.description.Feature;
32
import eu.etaxonomy.cdm.model.description.QuantitativeData;
33
import eu.etaxonomy.cdm.model.description.StateData;
34
import eu.etaxonomy.cdm.model.description.StatisticalMeasure;
35
import eu.etaxonomy.cdm.model.term.DefinedTermBase;
36
import eu.etaxonomy.cdm.persistence.dto.FeatureDto;
37
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
38
import eu.etaxonomy.cdm.persistence.dto.TermDto;
39

    
40
/**
41
 * @author pplitzner
42
 * @since 16.04.2018
43
 */
44
public abstract class RowWrapperDTO <T extends DescriptionBase> implements Serializable {
45

    
46
    private static final long serialVersionUID = -7817164423660563673L;
47

    
48
    private DescriptionBaseDto description;
49

    
50
    private TaxonNodeDto taxonNode;
51
    private Map<UUID, Set<DescriptionElementDto>> featureToElementMap;
52
    private Map<UUID, Collection<String>> featureToDisplayDataMap;
53

    
54
    public RowWrapperDTO(DescriptionBaseDto specimenDescription, TaxonNodeDto taxonNode) {
55
        this.taxonNode = taxonNode;
56
        this.featureToElementMap = new HashMap<>();
57
        this.featureToDisplayDataMap = new HashMap<>();
58
        this.description = specimenDescription;
59

    
60
        List<DescriptionElementDto> elements = specimenDescription.getElements();
61
        if (elements != null){
62
            for (DescriptionElementDto descriptionElementBase : elements) {
63
    //            if(hasData(descriptionElementBase)){
64
                UUID featureUuid = descriptionElementBase.getFeatureUuid();
65
                addToFeatureToElementMap(featureUuid, descriptionElementBase);
66

    
67
                Collection<String> displayData = generateDisplayString(descriptionElementBase);
68
                if(displayData!=null){
69
                    addDisplayStringsToMap(featureUuid, displayData);
70
                }
71

    
72
            }
73
        }
74
    }
75

    
76
    /**
77
     * @param featureUuid
78
     * @param displayData
79
     */
80
    private void addDisplayStringsToMap(UUID featureUuid, Collection<String> displayData) {
81
        if (featureToDisplayDataMap.get(featureUuid) == null){
82
            featureToDisplayDataMap.put(featureUuid, new ArrayList<>());
83
        }
84
        featureToDisplayDataMap.get(featureUuid).addAll(displayData);
85
    }
86

    
87
    public QuantitativeDataDto addQuantitativeData(FeatureDto feature){
88
        QuantitativeDataDto data = new QuantitativeDataDto(feature);
89
        description.addElement(data);
90
        removeElementForFeature(feature.getUuid());
91
        addToFeatureToElementMap(feature.getUuid(), data);
92
        return data;
93
    }
94

    
95
    /**
96
     * @param feature
97
     * @param data
98
     */
99
    private void addToFeatureToElementMap(UUID featureUuid, DescriptionElementDto data) {
100
        if (featureToElementMap.get(featureUuid) == null){
101
            featureToElementMap.put(featureUuid, new HashSet<>());
102
        }
103
        featureToElementMap.get(featureUuid).add(data);
104
    }
105

    
106
    public CategoricalDataDto addCategoricalData(FeatureDto feature){
107
        CategoricalDataDto data = new CategoricalDataDto(feature);
108
        description.addElement(data);
109
        removeElementForFeature(feature.getUuid());
110
        addToFeatureToElementMap(feature.getUuid(), data);
111
        return data;
112
    }
113

    
114
    public DescriptionBaseDto getDescription() {
115
        return description;
116
    }
117

    
118
    /**
119
     * @param description the description to set
120
     */
121
    public void setDescription(DescriptionBaseDto description) {
122
        this.description = description;
123
    }
124

    
125
    public TaxonNodeDto getTaxonNode() {
126
        return taxonNode;
127
    }
128

    
129
    public Collection<String> getDisplayDataForFeature(UUID featureUuid){
130
        return featureToDisplayDataMap.get(featureUuid);
131
    }
132

    
133
    public Set<DescriptionElementDto> getDataValueForFeature(UUID featureUuid){
134
        Set<DescriptionElementDto> descriptionElementBase = featureToElementMap.get(featureUuid);
135
        return descriptionElementBase;
136
    }
137

    
138

    
139

    
140
    private Collection<String> generateDisplayString(DescriptionElementDto descriptionElementBase){
141
        Collection<String> displayData = new ArrayList<>();
142
        if(descriptionElementBase instanceof CategoricalDataDto){
143
            CategoricalDataDto categoricalData = (CategoricalDataDto)descriptionElementBase;
144
            List<StateDataDto> states = categoricalData.getStates();
145
            Collections.sort(states, new Comparator<StateDataDto>() {
146
                @Override
147
                public int compare(StateDataDto h1, StateDataDto h2) {
148
                    if (h1.getCount() == null && h2.getCount() != null){
149
                        return -1;
150
                    } else if (h2.getCount() == null && h1.getCount() != null){
151
                        return 1;
152
                    } else if (h1.getCount() != h2.getCount()){
153
                        return -h1.getCount().compareTo(h2.getCount());
154
                    } else {
155
                        if (h1.getState() == h2.getState()){
156
                            return h1.toString().compareTo(h2.toString());
157
                        } else if (h1.getState() == null){
158
                            return -1;
159
                        } else if (h2.getState() == null){
160
                            return 1;
161
                        }else{
162
                            return h1.getState().getTitleCache().compareTo(h2.getState().getTitleCache());
163
                        }
164
                    }
165
                }
166
            });
167
            displayData = states.stream()
168
                    .map(stateData->generateStateDataString(stateData))
169
                    .collect(Collectors.toList());
170
        }
171
        if(descriptionElementBase instanceof QuantitativeDataDto){
172
            QuantitativeDataDto quantitativeData = (QuantitativeDataDto)descriptionElementBase;
173
            displayData = Collections.singleton(generateQuantitativeDataString(quantitativeData));
174
        }
175
        return displayData;
176
    }
177

    
178
    private String generateQuantitativeDataString(QuantitativeDataDto quantitativeData) {
179
        String displayData;
180
        displayData = "";
181
        BigDecimal min = quantitativeData.getSpecificStatisticalValue(StatisticalMeasure.MIN().getUuid());
182
        BigDecimal max = quantitativeData.getSpecificStatisticalValue(StatisticalMeasure.MAX().getUuid());
183
        BigDecimal mean = quantitativeData.getSpecificStatisticalValue(StatisticalMeasure.AVERAGE().getUuid());
184
        BigDecimal low = quantitativeData.getSpecificStatisticalValue(StatisticalMeasure.TYPICAL_LOWER_BOUNDARY().getUuid());
185
        BigDecimal high = quantitativeData.getSpecificStatisticalValue(StatisticalMeasure.TYPICAL_UPPER_BOUNDARY().getUuid());
186
        BigDecimal size = quantitativeData.getSpecificStatisticalValue(StatisticalMeasure.SAMPLE_SIZE().getUuid());
187
        String typicalValues = "";
188
        if (low != null || high != null){
189
            typicalValues += low!= null?low.toString():""+"-"+high!= null?high.toString():"";
190
        }
191
        if(min!=null||max!=null){
192
            if (min!= null && max != null && min.intValue() == max.intValue()){
193
                displayData += "("+min.toString()+")"+typicalValues;
194
            }else{
195
                if (StringUtils.isBlank(typicalValues)){
196
                    displayData += "("+(min!=null?min.toString():"?")+"-"+(max!=null?max.toString():"?")+") ";
197
                }else{
198
                    displayData += "("+(min!=null?min.toString():"?")+typicalValues+(max!=null?max.toString():"?")+") ";
199
                }
200
            }
201
        }
202
        displayData += quantitativeData.getValues().stream()
203
                .filter(value->value.getType().getUuid().equals(StatisticalMeasure.EXACT_VALUE().getUuid()))
204
                .map(exact->exact.getValue().toString())
205
                .collect(Collectors.joining(", "));
206
        if (quantitativeData.getMeasurementUnit() != null && StringUtils.isNotBlank(displayData)){
207
            displayData += " "+ quantitativeData.getMeasurementIdInVocabulary();
208
        }
209

    
210
        return displayData;
211
    }
212

    
213
    private String generateStateDataString(StateData stateData) {
214
        return (stateData.getState()!=null?stateData.getState().getLabel():"[no state]")
215
                +(stateData.getCount()!=null?" ("+stateData.getCount()+")":"");
216
    }
217

    
218
    private String generateStateDataString(StateDataDto stateData) {
219
        return (stateData.getState()!=null?stateData.getState().getTitleCache():"[no state]")
220
                +(stateData.getCount()!=null?" ("+stateData.getCount()+")":"");
221
    }
222

    
223
    public void setDataValueForCategoricalData(UUID featureUuid, List<TermDto> states){
224
        Set<DescriptionElementDto> descriptionElementBase = featureToElementMap.get(featureUuid);
225

    
226
        if(states.isEmpty()){
227
            removeFeature(featureUuid, descriptionElementBase);
228
            return;
229
        }
230
        CategoricalDataDto categoricalData = null;
231
        if(descriptionElementBase!=null){
232
            if (descriptionElementBase.size() == 1){
233
                DescriptionElementDto dto = descriptionElementBase.iterator().next();
234
                if (dto instanceof CategoricalDataDto){
235
                    categoricalData = (CategoricalDataDto)dto;
236
                    categoricalData.setStateDataOnly(states);
237
                }
238
            }
239

    
240
        }else{
241
            Feature feature = DefinedTermBase.getTermByClassAndUUID(Feature.class, featureUuid);
242
            if (feature == null){
243
                feature = DefinedTermBase.getTermByClassAndUUID(Character.class, featureUuid);
244
            }
245
            categoricalData = new CategoricalDataDto(FeatureDto.fromFeature(feature));
246
            categoricalData.setStateDataOnly(states);
247
        }
248
        removeElementForFeature(featureUuid);
249
        description.getElements().add(categoricalData);
250
        addToFeatureToElementMap(featureUuid, categoricalData);
251

    
252
        // update display data cache
253
        addDisplayStringsToMap(featureUuid, generateDisplayString(categoricalData));
254
//        featureToDisplayDataMap.put(featureUuid, generateDisplayString(categoricalData));
255
    }
256

    
257
    /**
258
     * @param featureUuid
259
     * @param oldElement
260
     */
261
    private void removeElementForFeature(UUID featureUuid) {
262
        DescriptionElementDto oldElement = null;
263
        for (DescriptionElementDto elementDto: description.getElements()){
264
            if (elementDto.getFeatureUuid()!= null && elementDto.getFeatureUuid().equals(featureUuid)) {
265
                oldElement = elementDto;
266
                break;
267
            }
268

    
269
        }
270
        description.getElements().remove(oldElement);
271
        featureToElementMap.remove(featureUuid);
272
        featureToDisplayDataMap.remove(featureUuid);
273
    }
274

    
275
    private void removeFeature(UUID featureUuid, Set<DescriptionElementDto> descriptionElementBases) {
276
        Set<DescriptionElementDto> elements = featureToElementMap.get(featureUuid);
277
        if (elements == null){
278
            return;
279
        }
280
        Integer i = 0;
281
        Set<Integer> indices = new  HashSet<>();
282
        for (DescriptionElementDto dto: description.getElements()){
283
            for (DescriptionElementDto descElDto: descriptionElementBases) {
284
                if (dto.getFeatureUuid() != null && dto.getFeatureUuid().equals(descElDto.getFeatureUuid())){
285
                    indices.add(i);
286
                    break;
287
                }
288
            }
289
            i++;
290
        }
291
        for (int index: indices){
292
            description.getElements().remove(index);
293
        }
294
        featureToElementMap.remove(featureUuid);
295
        featureToDisplayDataMap.remove(featureUuid);
296

    
297
    }
298

    
299
    public void setDataValueForQuantitativeData(UUID featureUuid, Map<TermDto, List<String>> textFields, TermDto unit){
300
        Set<DescriptionElementDto> descriptionElementBase = featureToElementMap.get(featureUuid);
301
        if(textFields.values().stream().allMatch(listOfStrings->listOfStrings.isEmpty())){
302
            removeFeature(featureUuid, descriptionElementBase);
303
            return;
304
        }
305
        QuantitativeDataDto quantitativeData = null;
306
        if (descriptionElementBase == null){
307
            Feature feature = DefinedTermBase.getTermByClassAndUUID(Feature.class, featureUuid);
308
            if (feature == null){
309
                feature = DefinedTermBase.getTermByClassAndUUID(Character.class, featureUuid);
310
            }
311
            quantitativeData = new QuantitativeDataDto(FeatureDto.fromFeature(feature));
312
        }
313

    
314
        if(descriptionElementBase!=null){
315
            if (descriptionElementBase.size() == 1){
316
                DescriptionElementDto dto = descriptionElementBase.iterator().next();
317
                if (dto instanceof QuantitativeDataDto){
318
                    quantitativeData = (QuantitativeDataDto)dto;
319
                }
320
            }
321

    
322

    
323
        }
324
        if (quantitativeData == null){
325
            //TODO: check whether this is possible
326
            return;
327
        }
328
        quantitativeData.getValues().clear();
329
        quantitativeData.setMeasurementUnit(unit);
330
        //add back all values from text fields
331
        Set<StatisticalMeasurementValueDto> tempValues = new HashSet<>();
332
        textFields.forEach((measure, texts)->{
333
            texts.forEach(text->{
334
                String string = text;
335
                try {
336
                    if (StringUtils.isNotBlank(string)){
337
                        BigDecimal exactValue = new BigDecimal(string);
338
//                        StatisticalMeasurementValue newValue = StatisticalMeasurementValue.NewInstance(measure, exactValue);
339
                        StatisticalMeasurementValueDto newValueDto = new StatisticalMeasurementValueDto(measure, exactValue, null);
340
//                                StatisticalMeasurementValueDto.fromStatisticalMeasurementValue(newValue);
341
                        tempValues.add(newValueDto);
342
                    }
343
                } catch (NumberFormatException e) {
344
                }
345
            });
346
        });
347

    
348
        quantitativeData.setValues(tempValues);
349
        removeElementForFeature(featureUuid);
350
        description.getElements().add(quantitativeData);
351
        addToFeatureToElementMap(featureUuid, quantitativeData);
352
        addDisplayStringsToMap(featureUuid, generateDisplayString(quantitativeData));
353
//        featureToDisplayDataMap.put(featureUuid, generateDisplayString(quantitativeData));
354
    }
355

    
356
    @Override
357
    public int hashCode() {
358
        final int prime = 31;
359
        int result = 1;
360
        result = prime * result + ((description == null) ? 0 : description.hashCode());
361
        result = prime * result + ((featureToElementMap == null) ? 0 : featureToElementMap.hashCode());
362
        result = prime * result + ((taxonNode == null) ? 0 : taxonNode.hashCode());
363
        return result;
364
    }
365

    
366
    @Override
367
    public boolean equals(Object obj) {
368
        if (this == obj) {
369
            return true;
370
        }
371
        if (obj == null) {
372
            return false;
373
        }
374
        if (getClass() != obj.getClass()) {
375
            return false;
376
        }
377
        RowWrapperDTO<?> other = (RowWrapperDTO<?>) obj;
378
        if (description == null) {
379
            if (other.description != null) {
380
                return false;
381
            }
382
        } else if (!description.equals(other.description)) {
383
            return false;
384
        }
385
        if (featureToElementMap == null) {
386
            if (other.featureToElementMap != null) {
387
                return false;
388
            }
389
        } else if (!featureToElementMap.equals(other.featureToElementMap)) {
390
            return false;
391
        }
392
        if (taxonNode == null) {
393
            if (other.taxonNode != null) {
394
                return false;
395
            }
396
        } else if (!taxonNode.equals(other.taxonNode)) {
397
            return false;
398
        }
399
        return true;
400
    }
401

    
402
    public static boolean hasData(DescriptionElementDto element){
403
        if(element instanceof CategoricalDataDto){
404
            return !((CategoricalDataDto)element).getStates().isEmpty();
405
        }
406
        else if(element instanceof QuantitativeDataDto){
407
            return !((QuantitativeDataDto)element).getValues().isEmpty();
408
        }
409
        return false;
410
    }
411

    
412
    public static boolean hasData(DescriptionElementBase element){
413
        if(element instanceof CategoricalData){
414
            return !((CategoricalData)element).getStatesOnly().isEmpty();
415
        }
416
        else if(element instanceof QuantitativeData){
417
            return !((QuantitativeData)element).getStatisticalValues().isEmpty();
418
        }
419
        return false;
420
    }
421

    
422
}
(30-30/44)