PhenologicalResource.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.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import fr.inrae.agroclim.indicators.model.data.Resource;
import fr.inrae.agroclim.indicators.model.indicator.CompositeIndicator;
import fr.inrae.agroclim.indicators.model.indicator.Indicator;
import fr.inrae.agroclim.indicators.model.indicator.IndicatorCategory;
import fr.inrae.agroclim.indicators.util.DateUtils;
import lombok.extern.log4j.Log4j2;

/**
 * Storage of phenological daily data.
 *
 * Last change $Date$
 *
 * @author $Author$
 * @version $Revision$
 */
@Log4j2
public final class PhenologicalResource extends Resource<AnnualStageData> {
    /**
     * UUID for Serializable.
     */
    private static final long serialVersionUID = 4872847709393688048L;
    /**
     * Separator for tag of pheno phase.
     */
    private static final String PHENO_PHASE_SEPARATOR = "-";
    /**
     * Prefix for tag of pheno phase.
     */
    private static final String PHENO_PHASE_PREFIX = "pheno" + PHENO_PHASE_SEPARATOR;

    /**
     * Phases.
     */
    private List<CompositeIndicator> phases;

    /**
     * Phenological stages.
     */
    private List<String> stages;

    /**
     * List all AnnualStageData as dates.
     *
     * @param datas list of stages data
     * @return dates of phenological stages
     */
    public static List<Date> asDates(final List<AnnualStageData> datas) {
        final List<Date> dates = new ArrayList<>();
        datas.forEach(data -> {
            int year = data.getYear();
            for (final Stage stage : data.getStages()) {
                int doy = stage.getValue();
                Date date = DateUtils.getDate(year, doy);
                dates.add(date);
            }
        });
        return dates;
    }

    @Override
    public PhenologicalResource clone() throws CloneNotSupportedException {
        PhenologicalResource clone = (PhenologicalResource) super.clone();
        if (getData() != null) {
            List<AnnualStageData> dest = new ArrayList<>();
            for (final AnnualStageData data : getData()) {
                dest.add(data.clone());
            }
            clone.setData(dest);
        }
        if (getMissingVariables() != null) {
            List<String> dest = new ArrayList<>();
            Collections.copy(dest, getMissingVariables());
            clone.setMissingVariables(dest);
        }
        if (phases != null) {
            clone.phases = new ArrayList<>(phases);
        }
        if (stages != null) {
            clone.stages = new ArrayList<>(stages);
        }
        if (getYears() != null) {
            getYears().forEach(clone::addYear);
        }
        return clone;
    }

    /**
     * List all AnnualStageData as dates.
     *
     * @return dates of phenological stages
     */
    public List<Date> getDates() {
        return asDates(getData());
    }

    /**
     * @return available phases
     */
    public List<CompositeIndicator> getPhases() {
        return phases;
    }

    /**
     * List all phases starting by the stage.
     *
     * @param stage start stage
     * @return all stages with starting stage
     */
    public List<Indicator> getPhasesByStage(final String stage) {
        return phases.stream()
                // RDM9713
                .filter(phase -> phase.getTag().startsWith(PHENO_PHASE_PREFIX + stage + PHENO_PHASE_SEPARATOR))
                .collect(Collectors.toList());
    }

    /**
     * @return Phenological stages for GUI
     */
    public List<String> getStages() {
        return stages;
    }

    /**
     * @param list all data for the resource
     */
    public void setData(final List<AnnualStageData> list) {
        getYears().clear();
        for (final AnnualStageData data : list) {
            getYears().add(data.getYear());
        }
        getData().clear();
        getData().addAll(list);
    }

    /**
     * Initialize the stages and phases used by the GUI.
     *
     * @param userHeader
     *            Headers of CSV file.
     */
    public void setUserHeader(final String[] userHeader) {
        LOGGER.trace("start");
        if (userHeader == null) {
            throw new IllegalArgumentException("userHeader must not be null!");
        }
        List<Indicator> stageIndicators = new ArrayList<>();
        phases = new ArrayList<>();
        stages = new ArrayList<>();

        for (String column : userHeader) {
            if (column.equalsIgnoreCase(PhenologyFileLoader.YEAR_COLUMN)) {
                continue;
            }
            stages.add(column);
            CompositeIndicator stageIndicator = new CompositeIndicator();
            stageIndicator.setName("en", column);
            stageIndicator.setId("pheno_" + column);
            stageIndicator.setCategory(IndicatorCategory.PHENO_PHASES.getTag());
            stageIndicators.add(stageIndicator);
        }

        /*
         * Création d'un composite phase phéno à partir de 2 stades phéno
         * Création de toutes les combinaisons possibles
         */
        stageIndicators.forEach(stage -> {
            List<Indicator> nextStages = stageIndicators.subList(
                    stageIndicators.indexOf(stage) + 1, stages.size());
            for (Indicator nextStage : nextStages) {
                CompositeIndicator phenoIndicator = new CompositeIndicator();
                phenoIndicator.setName("en", nextStage.getName());
                phenoIndicator.setId(stage.getName() + nextStage.getName());
                phenoIndicator.setTag(PHENO_PHASE_PREFIX + stage.getName() + PHENO_PHASE_SEPARATOR
                        + nextStage.getName());
                phenoIndicator.setCategory(IndicatorCategory.PHENO_PHASES
                        .getTag());
                phenoIndicator.setNormalizationFunction(null);
                phenoIndicator.add(stage);
                phases.add(phenoIndicator);
            }
        });
    }
}