AnnualStageData.java
/*
* This file is part of Indicators.
*
* Indicators is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Indicators is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Indicators. If not, see <https://www.gnu.org/licenses/>.
*/
package fr.inrae.agroclim.indicators.model.data.phenology;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import fr.inrae.agroclim.indicators.model.data.Data;
import fr.inrae.agroclim.indicators.resources.Messages;
import fr.inrae.agroclim.indicators.util.DateUtils;
import lombok.Getter;
import lombok.Setter;
/**
* List of stages for a year.
*
* Last change $Date$
*
* @author $Author$
* @version $Revision$
*/
public class AnnualStageData implements Cloneable, Data, Serializable {
/**
* UUID for Serializable.
*/
private static final long serialVersionUID = 1367181411523509675L;
/**
* Name of required columns, used by GUI.
*/
public static final List<String> REQUIRED = Arrays.asList("year");
/**
* Name of all variables, used by GUI.
*/
public static final List<String> VAR_NAMES = Arrays.asList("year");
/**
* Error messages.
*/
private final List<String> errors = new ArrayList<>();
/**
* All stages are defined for the year.
*
* Ex.: false if phenological development does not ends (model was not able
* to compute all stages).
*/
@Getter
@Setter
private boolean isComplete = true;
/**
* Stage list.
*/
@Getter
@Setter
private List<Stage> stages;
/**
* Warning messages.
*/
private final List<String> warnings = new ArrayList<>();
/**
* Harvest year for the stage list.
*/
@Getter
@Setter
private Integer year;
/**
* Constructor.
*/
public AnnualStageData() {
super();
}
/**
* Constructor.
*
* @param y year of list
*/
public AnnualStageData(final Integer y) {
this.year = y;
stages = new ArrayList<>();
}
/**
* @param name stage name
* @param value doy
*/
public final void add(final String name, final int value) {
if (getStages() == null) {
stages = new ArrayList<>();
}
Stage myStage = new Stage(name, value);
getStages().add(myStage);
}
@Override
public final void check(final int line, final String path) {
if (year == 0) {
errors.add(Messages.format("error.year.null", path, line));
}
if (stages.size() < 2) {
errors.add(Messages.format("error.minimal.stages", path, line));
}
for (final Stage stage : stages) {
List<Stage> nextStages = stages.subList(stages.indexOf(stage),
stages.size());
for (final Stage nextStage : nextStages) {
// TODO ignorer les stades relatifs
if (stage.getValue() > nextStage.getValue()) {
errors.add(Messages.format(
"error.endstage.superiorto.startstage",
path, line));
}
}
}
}
@Override
public final AnnualStageData clone() throws CloneNotSupportedException {
AnnualStageData clone = (AnnualStageData) super.clone();
Collections.copy(clone.errors, errors);
if (stages != null) {
clone.stages = new ArrayList<>();
for (final Stage stage : stages) {
clone.stages.add(stage.clone());
}
}
Collections.copy(clone.warnings, warnings);
clone.year = year;
return clone;
}
@Override
public final boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
AnnualStageData other = (AnnualStageData) obj;
if (stages == null) {
if (other.stages != null) {
return false;
}
} else if (!stages.equals(other.stages)) {
return false;
}
if (year == null) {
if (other.year != null) {
return false;
}
} else if (!year.equals(other.year)) {
return false;
}
return true;
}
/**
* @return if a stage is in next year
*/
public final boolean existWinterCrop() {
final int nbOfDays = DateUtils.nbOfDays(year);
return stages.stream().anyMatch(
stage -> stage.getValue() > nbOfDays
);
}
@Override
public final List<String> getErrors() {
return errors;
}
/**
* @param name stage name
* @return DOY of stage or null
*/
public final Integer getStageValue(final String name) {
Integer value = null;
for (final Stage stage : stages) {
if (stage.getName().equals(name)) {
return stage.getValue();
}
}
// s1p1 => s1+1
final String relativeName = name.replace("m", "-").replace("p", "+");
for (final Stage stage : stages) {
if (stage.getName().equals(relativeName)) {
return stage.getValue();
}
}
return value;
}
@Override
public final List<String> getWarnings() {
return warnings;
}
@Override
public final int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Objects.hashCode(stages);
result = prime * result + Objects.hashCode(year);
return result;
}
/**
* @return short string representation
*/
public final String toShortString() {
final StringBuilder sb = new StringBuilder("AnnualStageData [year=").append(year).append(", stages=");
String out = stages.stream() //
.map(s -> s.getName().concat("=").concat(String.valueOf(s.getValue()))) //
.collect(Collectors.joining(", ", "[", "]"));
sb.append(out);
sb.append("]");
return sb.toString();
}
@Override
public final String toString() {
return "AnnualStageData [year=" + year + ", stages=" + stages + "]";
}
}