view artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/BedQualityD50TimeRangeConfig.java @ 9559:ba0561906f81

Uinfo inundation duration workflow (vegetation zones, scenario), wms-config changed
author gernotbelger
date Wed, 24 Oct 2018 18:40:38 +0200
parents 8e6b9cb9486a
children
line wrap: on
line source
/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
 * Software engineering by
 *  Björnsen Beratende Ingenieure GmbH
 *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
 *
 * This file is Free Software under the GNU AGPL (>=v3)
 * and comes with ABSOLUTELY NO WARRANTY! Check out the
 * documentation coming with Dive4Elements River for details.
 */
package org.dive4elements.river.artifacts.sinfo.tkhstate;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;

import org.dive4elements.river.artifacts.model.Calculation;
import org.dive4elements.river.artifacts.model.DateRange;
import org.dive4elements.river.artifacts.sinfo.tkhcalculation.BedQualityD50KmValueFinder;
import org.dive4elements.river.artifacts.sinfo.tkhstate.TsvHelper.TsvReaderException;
import org.dive4elements.river.model.River;

/**
 * Represents the contents of the 'bedheights.properties' files.
 *
 * @author Gernot Belger
 */
public final class BedQualityD50TimeRangeConfig {

    private static final String CONFIG_FILE = "d50_sohlkorndurchmesser_%s.tsv";

    private final Map<String, CalRange[]> cache = new HashMap<>();

    private static BedQualityD50TimeRangeConfig INSTANCE = new BedQualityD50TimeRangeConfig();

    private static class BedQualityParseException extends Exception {

        private static final long serialVersionUID = 1L;

        public BedQualityParseException(final String message, final Throwable cause) {
            super(message, cause);
        }
    }

    public static synchronized DateRange getDefaults(final River river, final int soundingYear, final Calculation problems) {
        return INSTANCE.getBedHeightDefaultsForRiver(river, soundingYear, problems);
    }

    private synchronized DateRange getBedHeightDefaultsForRiver(final River river, final int soundingYear, final Calculation problems) {

        final String rivername = river.getName();

        final CalRange[] ranges = getRanges(rivername, problems);
        if (ranges == null)
            return null;

        for (final CalRange range : ranges) {
            if (range.isSoundingYearInRange(soundingYear))
                return new DateRange(range.getStartTimeQuery(), range.getEndTimeQuery());
        }

        // Message for admin, not translated
        final File file = TsvHelper.makeFile2(CONFIG_FILE, rivername);
        final String message = "Die angegebene d50-Sohlkorndurchmesser Konfigurationsdatei enthält keinen gültigen Bereich für das konfigurierte Peiljahr."; //$NON-NLS-1$
        problems.addProblem("sinfo.bedqualityd50config.configfile.loaderror", file.getPath(), message);
        return null;
    }

    private CalRange[] getRanges(final String rivername, final Calculation problems) {

        if (this.cache.containsKey(rivername))
            return this.cache.get(rivername);

        final CalRange[] ranges = loadRanges(rivername, problems);
        if (ranges == null) {
            /* do not cache so we always get the problem message again */
            return null;
        }

        this.cache.put(rivername, ranges);
        return ranges;
    }

    private CalRange[] loadRanges(final String rivername, final Calculation problems) {
        final File file = TsvHelper.makeFile2(CONFIG_FILE, rivername);
        final File fileCheck = TsvHelper.checkFile(file);
        if (fileCheck == null)
            return new CalRange[] { new CalRange(null, null, null, null) }; // automatically dateRange min/max will be taken

        try {
            final List<String[]> results = TsvHelper.readTsv(file, 4);

            final Collection<CalRange> ranges = new ArrayList<>(results.size());

            for (final String[] line : results) {
                if (line != null && line.length == 4)
                    ranges.add(new CalRange(parseInput(line[0]), parseInput(line[1]), parseInput(line[2]), parseInput(line[3])));
            }
            return ranges.toArray(new CalRange[ranges.size()]);
        }
        catch (final TsvReaderException | IOException | BedQualityParseException e) {
            problems.addProblem("sinfo.bedqualityd50config.configfile.loaderror", file.getPath(), e.getLocalizedMessage());
            return null;
        }
    }

    private static Integer parseInput(final String raw) throws BedQualityParseException {

        final String value = raw.trim();
        if (value.toUpperCase().equals("MIN") || value.toUpperCase().equals("MAX"))
            return null;

        try {
            return Integer.valueOf(value);
        }
        catch (final NumberFormatException e) {
            throw new BedQualityParseException("Invalid input; should be year ('yyyy') or 'MIN' or 'MAX'", e);
        }
    }

    private static final class CalRange {
        private final long startTimeSounding;
        private final long endTimeSounding;

        private final long startTimeQuery;
        private final long endTimeQuery;

        public Date getStartTimeQuery() {
            return new Date(this.startTimeQuery);
        }

        public Date getEndTimeQuery() {
            return new Date(this.endTimeQuery);
        }

        public CalRange(final Integer startYearSounding, final Integer endYearSounding, final Integer startYearQuery, final Integer endYearQuery) {

            this.startTimeSounding = (startYearSounding != null) ? getLongValForYear(startYearSounding, 0, 1) : BedQualityD50KmValueFinder.MIN_DATE.getTime();
            this.startTimeQuery = (startYearQuery != null) ? getLongValForYear(startYearQuery, 0, 1) : BedQualityD50KmValueFinder.MIN_DATE.getTime();
            this.endTimeSounding = (endYearSounding != null) ? getLongValForYear(endYearSounding, 11, 31) : BedQualityD50KmValueFinder.MAX_DATE.getTime();
            this.endTimeQuery = (endYearQuery != null) ? getLongValForYear(endYearQuery, 11, 31) : BedQualityD50KmValueFinder.MAX_DATE.getTime();
        }

        private static long getLongValForYear(final int year, final int month0based, final int dayOfMonth) {
            final Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT+1"));
            cal.clear();
            cal.set(year, month0based, dayOfMonth);

            return cal.getTimeInMillis();
        }

        public boolean isSoundingYearInRange(final int soundingYear) {

            final long time = getLongValForYear(soundingYear, 5, 5); // random date in the middle of the year
            if (time > this.startTimeSounding && time < this.endTimeSounding)
                return true;

            return false;
        }
    }
}

http://dive4elements.wald.intevation.org