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.BufferedReader; gernotbelger@9469: import java.io.File; gernotbelger@9469: import java.io.FileReader; gernotbelger@9469: import java.util.Calendar; gernotbelger@9469: import java.util.Date; gernotbelger@9469: import java.util.HashMap; gernotbelger@9469: import java.util.Map; gernotbelger@9469: gernotbelger@9469: import org.dive4elements.artifacts.common.utils.Config; gernotbelger@9469: import org.dive4elements.river.artifacts.model.Calculation; gernotbelger@9469: import org.dive4elements.river.artifacts.model.DateRange; 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@9469: private static final String CONFIG_FILE = "d50_sohlkorndurchmesser_%s.properties"; gernotbelger@9469: gernotbelger@9469: private final Map cache = new HashMap<>(); gernotbelger@9469: gernotbelger@9469: private static BedQualityD50TimeRangeConfig INSTANCE = new BedQualityD50TimeRangeConfig(); gernotbelger@9469: gernotbelger@9469: public static synchronized DateRange getDefaults(final River river, final int soundingYear, final Calculation problems) { gernotbelger@9469: return INSTANCE.getBedHeightDefaultsForRiver(river, soundingYear, problems); gernotbelger@9469: } gernotbelger@9469: gernotbelger@9469: private synchronized DateRange getBedHeightDefaultsForRiver(final River river, final int soundingYear, final Calculation problems) { 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@9469: final DateRange range = loadBedHeightDefaultsForRiver(river, soundingYear, problems); gernotbelger@9469: this.cache.put(cacheKey, range); gernotbelger@9469: return range; gernotbelger@9469: } gernotbelger@9469: return this.cache.get(cacheKey); gernotbelger@9469: } gernotbelger@9469: gernotbelger@9469: private static DateRange loadBedHeightDefaultsForRiver(final River river, final int soundingYear, final Calculation problems) { gernotbelger@9469: final String rivername = river.getName(); gernotbelger@9469: final File configDir = Config.getModulesConfigDirectory(); gernotbelger@9469: gernotbelger@9469: final String filename = String.format(CONFIG_FILE, rivername); gernotbelger@9469: gernotbelger@9469: final File file = new File(configDir, filename); gernotbelger@9469: gernotbelger@9469: if (!file.canRead() && !file.isFile()) { gernotbelger@9469: return null; // no config-file specified or spelling mistake etc. (not necessarily an error) gernotbelger@9469: } gernotbelger@9469: gernotbelger@9469: try (final BufferedReader reader = new BufferedReader(new FileReader(file))) { gernotbelger@9469: gernotbelger@9469: String line; gernotbelger@9469: while ((line = reader.readLine()) != null) { gernotbelger@9469: if ((line = line.trim()).length() == 0 || line.startsWith("#")) { gernotbelger@9469: continue; gernotbelger@9469: } gernotbelger@9469: gernotbelger@9469: final String[] parts = line.split(";"); gernotbelger@9469: gernotbelger@9469: if (parts.length != 4) { gernotbelger@9469: throw new Exception("Invalid number of Tokens; should be 4!"); gernotbelger@9469: } gernotbelger@9469: gernotbelger@9469: final CalRange range = new CalRange(parseInput(parts[0]), parseInput(parts[1]), parseInput(parts[2]), parseInput(parts[3])); gernotbelger@9469: if (range.isSoundingYearInRange(soundingYear)) { gernotbelger@9469: return new DateRange(range.getStartTimeQuery(), range.getEndTimeQuery()); gernotbelger@9469: } gernotbelger@9469: } gernotbelger@9469: return null; gernotbelger@9469: } gernotbelger@9469: catch (final Exception e) { gernotbelger@9469: e.printStackTrace(); gernotbelger@9469: problems.addProblem("sinfo.bedqualityd50config.configfile.loaderror", CONFIG_FILE, e.getMessage()); gernotbelger@9469: return null; gernotbelger@9469: } gernotbelger@9469: } gernotbelger@9469: gernotbelger@9469: private static Integer parseInput(final String value) throws Exception { gernotbelger@9469: if (value.toUpperCase().equals("MIN") || value.toUpperCase().equals("MAX")) gernotbelger@9469: return null; gernotbelger@9469: try { gernotbelger@9469: return Integer.valueOf(value); gernotbelger@9469: } gernotbelger@9469: catch (final NumberFormatException e) { gernotbelger@9469: throw new Exception("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@9469: this.startTimeSounding = 1l;// (startYearSounding != null) ? getLongValForYear(startYearSounding, 0, 1) : gernotbelger@9469: // BedQualityD50KmValueFinder.MIN_DATE.getTime(); gernotbelger@9469: this.startTimeQuery = 1l;// (startYearQuery != null) ? getLongValForYear(startYearQuery, 0, 1) : BedQualityD50KmValueFinder.MIN_DATE.getTime(); gernotbelger@9469: this.endTimeSounding = 1l;// (endYearSounding != null) ? getLongValForYear(endYearSounding, 11, 31) : gernotbelger@9469: // BedQualityD50KmValueFinder.MAX_DATE.getTime(); gernotbelger@9469: 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: }