ref #2975 add noDataStatus to descriptive data
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / description / QuantitativeData.java
1 /**
2 * Copyright (C) 2007 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
10 package eu.etaxonomy.cdm.model.description;
11
12 import java.math.BigDecimal;
13 import java.util.HashSet;
14 import java.util.Iterator;
15 import java.util.Set;
16
17 import javax.persistence.Column;
18 import javax.persistence.Entity;
19 import javax.persistence.FetchType;
20 import javax.persistence.ManyToOne;
21 import javax.persistence.OneToMany;
22 import javax.persistence.Transient;
23 import javax.validation.constraints.NotEmpty;
24 import javax.xml.bind.annotation.XmlAccessType;
25 import javax.xml.bind.annotation.XmlAccessorType;
26 import javax.xml.bind.annotation.XmlAttribute;
27 import javax.xml.bind.annotation.XmlElement;
28 import javax.xml.bind.annotation.XmlElementWrapper;
29 import javax.xml.bind.annotation.XmlIDREF;
30 import javax.xml.bind.annotation.XmlRootElement;
31 import javax.xml.bind.annotation.XmlSchemaType;
32 import javax.xml.bind.annotation.XmlTransient;
33 import javax.xml.bind.annotation.XmlType;
34
35 import org.apache.logging.log4j.LogManager;
36 import org.apache.logging.log4j.Logger;
37 import org.hibernate.annotations.Cascade;
38 import org.hibernate.annotations.CascadeType;
39 import org.hibernate.annotations.Type;
40 import org.hibernate.envers.Audited;
41 import org.hibernate.search.annotations.Indexed;
42
43 import eu.etaxonomy.cdm.common.BigDecimalUtil;
44 import eu.etaxonomy.cdm.model.term.DefinedTerm;
45 import eu.etaxonomy.cdm.validation.Level2;
46
47 /**
48 * This class represents information pieces expressed in numerical data
49 * (in opposition to {@link CategoricalData categorical data} on one side and to literal data on
50 * the other side). Only {@link TaxonDescription taxon descriptions} and
51 * {@link SpecimenDescription specimen descriptions} may contain quantitative data.<BR>
52 * The "length of leaves" {@link Feature feature} for instance can be measured in inches.
53 * If the length of leaves of a particular tree is described as
54 * "typically between 3 and 5 inches" and "at the utmost 8 inches" then three
55 * {@link StatisticalMeasurementValue statistical measurement value} instances
56 * must be assigned to an instance of the present class
57 * (with the {@link MeasurementUnit measurement unit} set to "inch"):<ul>
58 * <li> the first one with the value "3" and the {@link StatisticalMeasure statistical measure}
59 * "typical lower boundary",
60 * <li> the second one with the value "5" and the statistical measure
61 * "typical upper boundary"
62 * <li> the third one with the value "8" and the statistical measure "maximum"
63 * </ul>
64 * <P>
65 * This class corresponds partially to CodedDescriptionType according to
66 * the SDD schema.
67 *
68 * @author m.doering
69 * @since 08-Nov-2007 13:06:46
70 */
71 @XmlAccessorType(XmlAccessType.FIELD)
72 @XmlType(name = "QuantitativeData", propOrder = {
73 "unit",
74 "statisticalValues",
75 "unknownData"
76 })
77 @XmlRootElement(name = "QuantitativeData")
78 @Entity
79 @Indexed(index = "eu.etaxonomy.cdm.model.description.DescriptionElementBase")
80 @Audited
81 public class QuantitativeData
82 extends DescriptionElementBase {
83
84 private static final long serialVersionUID = -2755806455420051488L;
85 @SuppressWarnings("unused")
86 private static final Logger logger = LogManager.getLogger();
87
88 @XmlElement(name = "MeasurementUnit")
89 @XmlIDREF
90 @XmlSchemaType(name = "IDREF")
91 @ManyToOne(fetch = FetchType.LAZY)
92 private MeasurementUnit unit;
93
94 @XmlElementWrapper(name = "StatisticalValues")
95 @XmlElement(name = "StatisticalValue")
96 @OneToMany(fetch = FetchType.LAZY, mappedBy="quantitativeData", orphanRemoval=true)
97 @Cascade({ CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
98 @NotEmpty(groups = Level2.class)
99 private Set<StatisticalMeasurementValue> statisticalValues = new HashSet<>();
100
101 //see #4471
102 // @Column(precision = 20, scale = 10)
103 // private BigDecimal minimum;
104 //
105 // @Column(precision = 20, scale = 10)
106 // private BigDecimal maximum;
107 //
108 // @Column(precision = 20, scale = 10)
109 // private BigDecimal average;
110 //
111 // @Column(precision = 16, scale = 8)
112 // private BigDecimal variance;
113 //
114 // @Column(precision = 16, scale = 8)
115 // private BigDecimal standardDeviation;
116 //
117 // @Column(precision = 20, scale = 10)
118 // private BigDecimal singleValue;
119 //
120 // private Integer sampleSize;
121
122 @XmlElement(name = "UnknownData")
123 @Deprecated //will be replaced by #noDataStatus
124 private Boolean unknownData = false;
125
126 @XmlAttribute(name ="NoDataStatus")
127 @Column(name="noDataStatus", length=10)
128 @Type(type = "eu.etaxonomy.cdm.hibernate.EnumUserType",
129 parameters = {@org.hibernate.annotations.Parameter(name = "enumClass", value = "eu.etaxonomy.cdm.model.description.NoDescriptiveDataStatus")}
130 )
131 //see also CategoricalData.noDataStatus
132 private NoDescriptiveDataStatus noDataStatus;
133
134 // ******************************** FACTORY METHODS *******************************/
135
136 /**
137 * Creates a new empty quantitative data instance.
138 */
139 public static QuantitativeData NewInstance(){
140 return new QuantitativeData();
141 }
142
143 /**
144 * Creates a new quantitative data instance of type feature.
145 */
146 public static QuantitativeData NewInstance(Feature feature){
147 return new QuantitativeData(feature);
148 }
149
150 /**
151 * Creates a new quantitative data instance of type feature with defined min and may value.
152 */
153 public static QuantitativeData NewMinMaxInstance(Feature feature, BigDecimal min, BigDecimal max){
154 QuantitativeData result = new QuantitativeData(feature);
155 if (min != null){
156 StatisticalMeasurementValue minValue = StatisticalMeasurementValue.NewInstance(StatisticalMeasure.MIN(),min);
157 result.addStatisticalValue(minValue);
158 }
159 if (max != null){
160 StatisticalMeasurementValue maxValue = StatisticalMeasurementValue.NewInstance(StatisticalMeasure.MAX(), max);
161 result.addStatisticalValue(maxValue);
162 }
163 return result;
164 }
165
166 /**
167 * Creates a new quantitative data instance of type feature with defined exact value.
168 */
169 public static QuantitativeData NewExactValueInstance(Feature feature, BigDecimal... exactValues){
170 QuantitativeData result = new QuantitativeData(feature);
171 for (BigDecimal exactVal : exactValues){
172 StatisticalMeasurementValue exactValue = StatisticalMeasurementValue.NewInstance(StatisticalMeasure.EXACT_VALUE(), exactVal);
173 result.addStatisticalValue(exactValue);
174 }
175 return result;
176 }
177
178 public static QuantitativeData NewMinMaxInstance(Feature feature, MeasurementUnit unit, BigDecimal min, BigDecimal max){
179 QuantitativeData result = NewMinMaxInstance(feature, min, max);
180 result.setUnit(unit);
181 return result;
182 }
183
184 public static QuantitativeData NewExactValueInstance(Feature feature, MeasurementUnit unit, BigDecimal... exactValues){
185 QuantitativeData result = NewExactValueInstance(feature, exactValues);
186 result.setUnit(unit);
187 return result;
188 }
189
190 // ******************************** CONSTRUCTOR *******************************/
191
192 /**
193 * Class constructor: creates a new empty quantitative data instance.
194 */
195 protected QuantitativeData(){
196 super(null);
197 }
198
199 /**
200 * Class constructor: creates a new empty quantitative data instance.
201 */
202 protected QuantitativeData(Feature feature){
203 super(feature);
204 }
205
206 // ******************************** GETTER /SETTER *******************************/
207
208 /**
209 * Returns the set of {@link StatisticalMeasurementValue statistical measurement values} describing
210 * the {@link Feature feature} corresponding to <i>this</i> quantitative data.
211 */
212 public Set<StatisticalMeasurementValue> getStatisticalValues() {
213 return statisticalValues;
214 }
215
216 @Deprecated //for internal use only
217 protected void setStatisticalValues(Set<StatisticalMeasurementValue> statisticalValues) {
218 this.statisticalValues = statisticalValues;
219 }
220 /**
221 * Adds a {@link StatisticalMeasurementValue statistical measurement value} to the set of
222 * {@link #getStatisticalValues() statistical measurement values} describing
223 * the {@link Feature feature} corresponding to <i>this</i> quantitative data.
224 *
225 * @param statisticalValue the statistical measurement value to be added to
226 * <i>this</i> quantitative data
227 * @see #getStatisticalValues()
228 */
229 @SuppressWarnings("deprecation")
230 public void addStatisticalValue(StatisticalMeasurementValue statisticalValue) {
231 this.statisticalValues.add(statisticalValue);
232 statisticalValue.setQuantitativeData(this);
233 }
234 /**
235 * Removes one element from the set of {@link #getStatisticalValues() statistical measurement values}
236 * describing the {@link Feature feature} corresponding to <i>this</i> quantitative data.
237 *
238 * @param statisticalValue the statistical measurement value which should be removed
239 * @see #getStatisticalValues()
240 * @see #addStatisticalValue(StatisticalMeasurementValue)
241 */
242 @SuppressWarnings("deprecation")
243 public void removeStatisticalValue(StatisticalMeasurementValue statisticalValue) {
244 this.statisticalValues.remove(statisticalValue);
245 statisticalValue.setQuantitativeData(null);
246 }
247
248
249 /**
250 * Returns the {@link MeasurementUnit measurement unit} used in <i>this</i>
251 * quantitative data.
252 */
253 public MeasurementUnit getUnit(){
254 return this.unit;
255 }
256 /**
257 * @see #getUnit()
258 */
259 public void setUnit(MeasurementUnit unit){
260 this.unit = unit;
261 }
262
263 // ******************************** TRANSIENT METHODS *******************************/
264
265 @Transient
266 public BigDecimal getOverallMin(){
267 BigDecimal result = BigDecimalUtil.MAX_BIGDECIMAL;
268 for (StatisticalMeasurementValue value : statisticalValues){
269 if (withRangeValue(value)){
270 result = result.min(value.getValue());
271 }
272 }
273 return (result == BigDecimalUtil.MAX_BIGDECIMAL)? null: result;
274 }
275
276 @Transient
277 public BigDecimal getOverallMax(){
278 BigDecimal result = BigDecimalUtil.MIN_BIGDECIMAL;
279 for (StatisticalMeasurementValue value : statisticalValues){
280 if (withRangeValue(value)){
281 result = result.max(value.getValue());
282 }
283 }
284 return (result == BigDecimalUtil.MIN_BIGDECIMAL)? null: result;
285 }
286
287 private boolean withRangeValue(StatisticalMeasurementValue value) {
288 StatisticalMeasure type = value.getType();
289 if (type != null){
290 if (type.isAverage()|| type.isMin() || type.isTypicalLowerBoundary()||type.isMax()||type.isTypicalUpperBoundary()||type.isExactValue()){
291 return true;
292 }
293 }
294 return false;
295 }
296
297 /**
298 * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
299 * with the corresponding {@link StatisticalMeasure statistical measure} "minimum" and
300 * belonging to <i>this</i> quantitative data. Returns <code>null</code> if no such
301 * statistical measurement value instance exists.
302 */
303 @Transient
304 public BigDecimal getMin(){
305 return getSpecificStatisticalValue(StatisticalMeasure.MIN());
306 }
307
308 /**
309 * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
310 * with the corresponding {@link StatisticalMeasure statistical measure} "maximum" and
311 * belonging to <i>this</i> quantitative data. Returns <code>null</code> if no such
312 * statistical measurement value instance exists.
313 */
314 @Transient
315 public BigDecimal getMax(){
316 return getSpecificStatisticalValue(StatisticalMeasure.MAX());
317 }
318
319 /**
320 * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
321 * with the corresponding {@link StatisticalMeasure statistical measure}
322 * "typical lower boundary" and belonging to <i>this</i> quantitative data.
323 * Returns <code>null</code> if no such statistical measurement value instance exists.
324 */
325 @Transient
326 public BigDecimal getTypicalLowerBoundary(){
327 return getSpecificStatisticalValue(StatisticalMeasure.TYPICAL_LOWER_BOUNDARY());
328 }
329
330 @Transient
331 public Set<BigDecimal> getExactValues(){
332 return getSpecificStatisticalValues(StatisticalMeasure.EXACT_VALUE());
333 }
334
335 /**
336 * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
337 * with the corresponding {@link StatisticalMeasure statistical measure}
338 * "average" and belonging to <i>this</i> quantitative data.
339 * Returns <code>null</code> if no such statistical measurement value instance exists.
340 */
341 @Transient
342 public BigDecimal getAverage(){
343 return getSpecificStatisticalValue(StatisticalMeasure.AVERAGE());
344 }
345
346 /**
347 * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
348 * with the corresponding {@link StatisticalMeasure statistical measure}
349 * "standard deviation" and belonging to <i>this</i> quantitative data.
350 * Returns <code>null</code> if no such statistical measurement value instance exists.
351 */
352 @Transient
353 public BigDecimal getStandardDeviation(){
354 return getSpecificStatisticalValue(StatisticalMeasure.STANDARD_DEVIATION());
355 }
356
357 /**
358 * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
359 * with the corresponding {@link StatisticalMeasure statistical measure}
360 * "sample size" and belonging to <i>this</i> quantitative data.
361 * Returns <code>null</code> if no such statistical measurement value instance exists.
362 */
363 @Transient
364 public BigDecimal getSampleSize(){
365 return getSpecificStatisticalValue(StatisticalMeasure.SAMPLE_SIZE());
366 }
367
368 /**
369 * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
370 * with the corresponding {@link StatisticalMeasure statistical measure}
371 * "typical upper boundary" and belonging to <i>this</i> quantitative data.
372 * Returns <code>null</code> if no such statistical measurement value instance exists.
373 */
374 @Transient
375 public BigDecimal getTypicalUpperBoundary(){
376 return getSpecificStatisticalValue(StatisticalMeasure.TYPICAL_UPPER_BOUNDARY());
377 }
378
379 /**
380 * Returns the statistical value of type <code>type</code>.
381 * If no such value exists <code>null</code> is returned. If multiple such
382 * values exist an arbitrary one is returned.
383 * @param type
384 * @return the value
385 */
386 public BigDecimal getSpecificStatisticalValue(StatisticalMeasure type){
387 BigDecimal result = null;
388 for (StatisticalMeasurementValue value : statisticalValues){
389 if (type.equals(value.getType())){
390 result = value.getValue();
391 break;
392 }
393 }
394 return result;
395 }
396
397 public StatisticalMeasurementValue getSpecificStatisticalValueAsSMV(StatisticalMeasure type){
398 StatisticalMeasurementValue result = null;
399 for (StatisticalMeasurementValue value : statisticalValues){
400 if (type.equals(value.getType())){
401 result = value;
402 break;
403 }
404 }
405 return result;
406 }
407
408 public Set<BigDecimal> getSpecificStatisticalValues(StatisticalMeasure type){
409 Set<BigDecimal> result = new HashSet<>();
410 for (StatisticalMeasurementValue value : statisticalValues){
411 if (type.equals(value.getType())){
412 result.add(value.getValue());
413 }
414 }
415 return result;
416 }
417
418
419 /**
420 * Sets the statistical value for the minimum.
421 * If such value exists the old value is replaced by the new value.
422 * The new value is returned.
423 * @param type
424 * @param value
425 * @return the newValue
426 */
427 @Transient
428 public StatisticalMeasurementValue setMinimum(BigDecimal value, Set<DefinedTerm> modifiers){
429 return setSpecificStatisticalValue(value, modifiers, StatisticalMeasure.MIN());
430 }
431
432
433 /**
434 * Sets the statistical value for the maximum.
435 * If such value exists the old value is replaced by the new value.
436 * The new value is returned.
437 * @param type
438 * @param value
439 * @return the newValue
440 */
441 @Transient
442 public StatisticalMeasurementValue setMaximum(BigDecimal value, Set<DefinedTerm> modifiers){
443 return setSpecificStatisticalValue(value, modifiers, StatisticalMeasure.MAX());
444 }
445
446
447 /**
448 * Sets the statistical value for the average.
449 * If such value exists the old value is replaced by the new value.
450 * The new value is returned.
451 * @param type
452 * @param value
453 * @return the newValue
454 */
455 @Transient
456 public StatisticalMeasurementValue setAverage(BigDecimal value, Set<DefinedTerm> modifiers){
457 return setSpecificStatisticalValue(value, modifiers, StatisticalMeasure.AVERAGE());
458 }
459
460 /**
461 * Sets the statistical value for the standard deviation.
462 * If such value exists the old value is replaced by the new value.
463 * The new value is returned.
464 * @param type
465 * @param value
466 * @return the newValue
467 */
468 @Transient
469 public StatisticalMeasurementValue setStandardDeviation(BigDecimal value, Set<DefinedTerm> modifiers){
470 return setSpecificStatisticalValue(value, modifiers, StatisticalMeasure.STANDARD_DEVIATION());
471 }
472
473 /**
474 * Sets the statistical value for the sample size.
475 * If such value exists the old value is replaced by the new value.
476 * The new value is returned.
477 * @param type
478 * @param value
479 * @return the newValue
480 */
481 @Transient
482 public StatisticalMeasurementValue setSampleSize(BigDecimal value, Set<DefinedTerm> modifiers){
483 return setSpecificStatisticalValue(value, modifiers, StatisticalMeasure.SAMPLE_SIZE());
484 }
485
486
487 /**
488 * Sets the statistical value for the typical lower boundary.
489 * If such value exists the old value is replaced by the new value.
490 * The new value is returned.
491 * @param type
492 * @param value
493 * @return the newValue
494 */
495 @Transient
496 public StatisticalMeasurementValue setTypicalLowerBoundary(BigDecimal value, Set<DefinedTerm> modifiers){
497 return setSpecificStatisticalValue(value, modifiers, StatisticalMeasure.TYPICAL_LOWER_BOUNDARY());
498 }
499
500
501 /**
502 * Sets the statistical value for the typical upper boundary.
503 * If such value exists the old value is replaced by the new value.
504 * The new value is returned.
505 * @param type
506 * @param value
507 * @return the newValue
508 */
509 @Transient
510 public StatisticalMeasurementValue setTypicalUpperBoundary(BigDecimal value, Set<DefinedTerm> modifiers){
511 return setSpecificStatisticalValue(value, modifiers, StatisticalMeasure.TYPICAL_UPPER_BOUNDARY());
512 }
513
514 /**
515 * Sets the statistical value of type <code>type</code>.
516 * If such value exists the old value is replaced by the new value.
517 * The new value is returned.
518 * @param type
519 * @param value
520 * @return the newValue
521 */
522 public StatisticalMeasurementValue setSpecificStatisticalValue(BigDecimal value,
523 Set<DefinedTerm> modifiers, StatisticalMeasure type){
524
525 StatisticalMeasurementValue result = null;
526 StatisticalMeasurementValue existingSmValue = null;
527
528 for (StatisticalMeasurementValue existingValue : statisticalValues){
529 if (type.equals(existingValue.getType())){
530 existingSmValue = existingValue;
531 break;
532 }
533 }
534 if (value == null && existingSmValue == null){
535 return null;
536 }else if (value == null && existingSmValue != null){
537 this.removeStatisticalValue(existingSmValue);
538 return null;
539 }else if (value != null && existingSmValue == null){
540 result = StatisticalMeasurementValue.NewInstance(type, value);
541 if (modifiers != null){
542 for (DefinedTerm modifier : modifiers){
543 result.addModifier(modifier);
544 }
545 }
546 this.addStatisticalValue(result);
547 } else if (value != null && existingSmValue != null){
548 result = existingSmValue;
549 result.setValue(value);
550 //remove existing modifiers
551 Iterator<DefinedTerm> it = result.getModifiers().iterator();
552 while (it.hasNext()){
553 it.remove();
554 }
555 //add new modifiers
556 if (modifiers != null){
557 for (DefinedTerm modifier : modifiers){
558 result.addModifier(modifier);
559 }
560 }
561 }
562 return result;
563 }
564
565 // public StatisticalMeasurementValue setSpecificStatisticalValue_old(Float value, Set<DefinedTerm> modifiers, StatisticalMeasure type){
566 // StatisticalMeasurementValue result = null;
567 // if (value != null){
568 // StatisticalMeasurementValue newValue = StatisticalMeasurementValue.NewInstance();
569 // newValue.setValue(value);
570 // if (modifiers != null){
571 // newValue.getModifiers().addAll(modifiers);
572 // }
573 // newValue.setType(type);
574 // result = newValue;
575 // }
576 // for (StatisticalMeasurementValue existingValue : statisticalValues){
577 // if (type.equals(existingValue.getType())){
578 // result = existingValue;
579 // statisticalValues.remove(existingValue);
580 // break;
581 // }
582 // }
583 // if (result != null){
584 // statisticalValues.add(result);
585 // }
586 // return result;
587 // }
588
589 @Deprecated //will be replaced by #noDataStatus
590 public Boolean getUnknownData() {
591 return unknownData;
592 }
593 @Deprecated //will be replaced by #noDataStatus
594 public void setUnknownData(Boolean unknownData) {
595 this.unknownData = unknownData;
596 }
597
598 //no data status, #2975
599 public NoDescriptiveDataStatus getNoDataStatus() {
600 return noDataStatus;
601 }
602 public void setNoDataStatus(NoDescriptiveDataStatus noDataStatus) {
603 this.noDataStatus = noDataStatus;
604 }
605
606 //
607 // public BigDecimal getMinimum() {
608 // return minimum;
609 // }
610 //
611 // public void setMinimum(BigDecimal minimum) {
612 // this.minimum = minimum;
613 // }
614 //
615 // public BigDecimal getMaximum() {
616 // return maximum;
617 // }
618 //
619 // public void setMaximum(BigDecimal maximum) {
620 // this.maximum = maximum;
621 // }
622 //
623 // public BigDecimal getVariance() {
624 // return variance;
625 // }
626 //
627 // public void setVariance(BigDecimal variance) {
628 // this.variance = variance;
629 // }
630 //
631 // public BigDecimal getSingleValue() {
632 // return singleValue;
633 // }
634 //
635 // public void setSingleValue(BigDecimal singleValue) {
636 // this.singleValue = singleValue;
637 // }
638
639 //
640 // public void setAverage(BigDecimal average) {
641 // this.average = average;
642 // }
643 //
644 // public void setStandardDeviation(BigDecimal standardDeviation) {
645 // this.standardDeviation = standardDeviation;
646 // }
647 //
648 // public void setSampleSize(Integer sampleSize) {
649 // this.sampleSize = sampleSize;
650 // }
651
652
653 @Transient
654 @XmlTransient
655 @Override
656 public boolean isCharacterData() {
657 return true;
658 }
659
660
661 //*********************************** CLONE *****************************************/
662
663 /**
664 * Clones <i>this</i> quantitative data. This is a shortcut that enables to create
665 * a new instance that differs only slightly from <i>this</i> quantitative data by
666 * modifying only some of the attributes.
667 *
668 * @see eu.etaxonomy.cdm.model.description.DescriptionElementBase#clone()
669 * @see java.lang.Object#clone()
670 */
671 @Override
672 public QuantitativeData clone() {
673
674 QuantitativeData result = (QuantitativeData)super.clone();
675
676 //states
677 result.statisticalValues = new HashSet<>();
678 for (StatisticalMeasurementValue data : getStatisticalValues()){
679 StatisticalMeasurementValue newData = data.clone();
680 result.addStatisticalValue(newData);
681 }
682
683 //no changes to: unit
684
685 return result;
686 }
687
688 //********************** TO STRING **************************************/
689
690 @Override
691 public String toString() {
692 return (getFeature()!=null ? getFeature().getLabel(): "") +
693 "[" + statisticalValues +
694 (unit!=null ? ", unit=" + unit : "") +
695 (noDataStatus != null ? ", noDataStatus=" + noDataStatus.getLabel() :"")
696 + "]";
697 }
698 }