gernotbelger@9469: /** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde gernotbelger@9469: * Software engineering by gernotbelger@9469: * Björnsen Beratende Ingenieure GmbH gernotbelger@9469: * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt gernotbelger@9469: * gernotbelger@9469: * This file is Free Software under the GNU AGPL (>=v3) gernotbelger@9469: * and comes with ABSOLUTELY NO WARRANTY! Check out the gernotbelger@9469: * documentation coming with Dive4Elements River for details. gernotbelger@9469: */ gernotbelger@9469: package org.dive4elements.river.artifacts.sinfo.tkhstate; gernotbelger@9469: gernotbelger@9469: import java.io.File; gernotbelger@9481: import java.io.IOException; gernotbelger@9469: import java.util.Calendar; gernotbelger@9469: import java.util.Date; gernotbelger@9469: import java.util.HashMap; gernotbelger@9481: import java.util.List; gernotbelger@9469: import java.util.Map; gernotbelger@9469: gernotbelger@9469: import org.dive4elements.river.artifacts.model.Calculation; gernotbelger@9469: import org.dive4elements.river.artifacts.model.DateRange; gernotbelger@9481: import org.dive4elements.river.artifacts.sinfo.tkhstate.TsvHelper.TsvReaderException; gernotbelger@9469: import org.dive4elements.river.model.River; gernotbelger@9469: gernotbelger@9469: /** gernotbelger@9469: * Represents the contents of the 'bedheights.properties' files. gernotbelger@9469: * gernotbelger@9469: * @author Gernot Belger gernotbelger@9469: */ gernotbelger@9469: public final class BedQualityD50TimeRangeConfig { gernotbelger@9469: gernotbelger@9481: private static final String CONFIG_FILE = "d50_sohlkorndurchmesser_%s.tsv"; gernotbelger@9469: gernotbelger@9469: private final Map cache = new HashMap<>(); gernotbelger@9469: gernotbelger@9469: private static BedQualityD50TimeRangeConfig INSTANCE = new BedQualityD50TimeRangeConfig(); gernotbelger@9469: gernotbelger@9481: public static class BedQualityParseException extends Exception { gernotbelger@9481: gernotbelger@9481: private static final long serialVersionUID = 1L; gernotbelger@9481: gernotbelger@9481: private BedQualityParseException(final String string) { gernotbelger@9481: super(string); gernotbelger@9481: } gernotbelger@9481: } gernotbelger@9481: gernotbelger@9481: public static synchronized DateRange getDefaults(final River river, final int soundingYear, final Calculation problems) gernotbelger@9481: throws BedQualityParseException, IOException, TsvReaderException { gernotbelger@9469: return INSTANCE.getBedHeightDefaultsForRiver(river, soundingYear, problems); gernotbelger@9469: } gernotbelger@9469: gernotbelger@9481: private synchronized DateRange getBedHeightDefaultsForRiver(final River river, final int soundingYear, final Calculation problems) gernotbelger@9481: throws BedQualityParseException { gernotbelger@9469: final String rivername = river.getName(); gernotbelger@9469: final String cacheKey = new StringBuilder().append(rivername).append(";").append(soundingYear).toString(); gernotbelger@9469: if (!this.cache.containsKey(cacheKey)) { gernotbelger@9481: final File file = TsvHelper.makeFile2(CONFIG_FILE, rivername); gernotbelger@9481: final File fileCheck = TsvHelper.checkFile(file); gernotbelger@9481: if (fileCheck == null) gernotbelger@9481: return null; // automatically dateRange min/max wil be taken gernotbelger@9481: gernotbelger@9481: List results = null; gernotbelger@9481: try { gernotbelger@9481: results = TsvHelper.readTsv(file, 4); gernotbelger@9481: } gernotbelger@9481: catch (final TsvReaderException | IOException e) { gernotbelger@9481: problems.addProblem("sinfo.bedqualityd50config.configfile.loaderror", file.getPath(), e.getStackTrace()); gernotbelger@9481: } gernotbelger@9481: if (results != null) { gernotbelger@9481: for (final String[] line : results) { gernotbelger@9481: final CalRange range = new CalRange(parseInput(line[0]), parseInput(line[1]), parseInput(line[2]), parseInput(line[3])); gernotbelger@9481: if (range.isSoundingYearInRange(soundingYear)) { gernotbelger@9481: final DateRange dateRange = new DateRange(range.getStartTimeQuery(), range.getEndTimeQuery()); gernotbelger@9481: this.cache.put(cacheKey, dateRange); gernotbelger@9481: gernotbelger@9481: } gernotbelger@9481: } gernotbelger@9481: } gernotbelger@9481: problems.addProblem("sinfo.bedqualityd50config.configfile.loaderror", file.getPath(), gernotbelger@9481: " Die angegebene d50-sohlkorndurchmesser-config-file enthält keinen gültigen Bereich für das konfigurierte Peiljahr."); gernotbelger@9481: return null; gernotbelger@9469: } gernotbelger@9469: return this.cache.get(cacheKey); gernotbelger@9469: } gernotbelger@9469: gernotbelger@9481: private static Integer parseInput(final String raw) throws BedQualityParseException { gernotbelger@9481: final String value = raw.trim(); gernotbelger@9469: if (value.toUpperCase().equals("MIN") || value.toUpperCase().equals("MAX")) gernotbelger@9469: return null; gernotbelger@9469: try { gernotbelger@9481: gernotbelger@9469: return Integer.valueOf(value); gernotbelger@9469: } gernotbelger@9469: catch (final NumberFormatException e) { gernotbelger@9481: throw new BedQualityParseException("Invalid input; should be year ('yyyy') or 'MIN' or 'MAX'"); gernotbelger@9469: } gernotbelger@9469: } gernotbelger@9469: gernotbelger@9469: private static class CalRange { gernotbelger@9469: private final long startTimeSounding; gernotbelger@9469: private final long endTimeSounding; gernotbelger@9469: gernotbelger@9469: private final long startTimeQuery; gernotbelger@9469: private final long endTimeQuery; gernotbelger@9469: gernotbelger@9469: private final static Calendar cal = Calendar.getInstance(); gernotbelger@9469: gernotbelger@9469: private Date getStartTimeQuery() { gernotbelger@9469: return new Date(this.startTimeQuery); gernotbelger@9469: } gernotbelger@9469: gernotbelger@9469: private Date getEndTimeQuery() { gernotbelger@9469: return new Date(this.endTimeQuery); gernotbelger@9469: } gernotbelger@9469: gernotbelger@9469: private CalRange(final Integer startYearSounding, final Integer endYearSounding, final Integer startYearQuery, final Integer endYearQuery) { gernotbelger@9469: gernotbelger@9481: this.startTimeSounding = 1L;// (startYearSounding != null) ? getLongValForYear(startYearSounding, 0, 1) : gernotbelger@9469: // BedQualityD50KmValueFinder.MIN_DATE.getTime(); gernotbelger@9481: this.startTimeQuery = 1L;// (startYearQuery != null) ? getLongValForYear(startYearQuery, 0, 1) : BedQualityD50KmValueFinder.MIN_DATE.getTime(); gernotbelger@9481: this.endTimeSounding = 1L;// (endYearSounding != null) ? getLongValForYear(endYearSounding, 11, 31) : gernotbelger@9469: // BedQualityD50KmValueFinder.MAX_DATE.getTime(); gernotbelger@9481: this.endTimeQuery = 1L;// (endYearQuery != null) ? getLongValForYear(endYearQuery, 11, 31) : BedQualityD50KmValueFinder.MAX_DATE.getTime(); gernotbelger@9469: gernotbelger@9469: } gernotbelger@9469: gernotbelger@9469: private long getLongValForYear(final int year, final int month0based, final int dayOfMonth) { gernotbelger@9469: cal.clear(); gernotbelger@9469: cal.set(year, month0based, dayOfMonth); gernotbelger@9469: gernotbelger@9469: return cal.getTimeInMillis(); gernotbelger@9469: } gernotbelger@9469: gernotbelger@9469: private boolean isSoundingYearInRange(final int soundingYear) { gernotbelger@9469: cal.clear(); gernotbelger@9469: gernotbelger@9469: cal.set(soundingYear, 5, 5); // random date in the middle of the year gernotbelger@9469: gernotbelger@9469: final Long time = cal.getTimeInMillis(); gernotbelger@9469: gernotbelger@9469: if (time > this.startTimeSounding && time < this.endTimeSounding) gernotbelger@9469: return true; gernotbelger@9469: gernotbelger@9469: return false; gernotbelger@9469: } gernotbelger@9469: gernotbelger@9469: } gernotbelger@9469: gernotbelger@9469: }