Project

General

Profile

Download (17 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():"";
190
            typicalValues += high!= null? "-"+ high.toString():"";
191
        }
192
        if(min!=null||max!=null){
193
            if (min!= null && max != null && min.intValue() == max.intValue()){
194
                displayData += "("+min.toString()+")"+typicalValues;
195
            }else{
196
                if (StringUtils.isBlank(typicalValues)){
197
                    displayData += "("+(min!=null?min.toString():"?")+"-"+(max!=null?max.toString():"?")+") ";
198
                }else{
199
                    displayData += "("+(min!=null?min.toString():"?")+ "-)"+typicalValues;
200
                    displayData += "(-"+(max!=null?max.toString():"?")+") ";
201
                }
202
            }
203
        }
204
        displayData += quantitativeData.getValues().stream()
205
                .filter(value->value.getType().getUuid().equals(StatisticalMeasure.EXACT_VALUE().getUuid()))
206
                .map(exact->exact.getValue().toString())
207
                .collect(Collectors.joining(", "));
208
        if (quantitativeData.getMeasurementUnit() != null && StringUtils.isNotBlank(displayData)){
209
            displayData += " "+ quantitativeData.getMeasurementIdInVocabulary();
210
        }
211

    
212
        return displayData;
213
    }
214

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

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

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

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

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

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

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

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

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

    
299
    }
300

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

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

    
324

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

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

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

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

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

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

    
424
}
(31-31/45)