gernotbelger@8942: /** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde gernotbelger@8942: * Software engineering by gernotbelger@8942: * Björnsen Beratende Ingenieure GmbH gernotbelger@8942: * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt gernotbelger@8942: * gernotbelger@8942: * This file is Free Software under the GNU AGPL (>=v3) gernotbelger@8942: * and comes with ABSOLUTELY NO WARRANTY! Check out the gernotbelger@8942: * documentation coming with Dive4Elements River for details. gernotbelger@8942: */ gernotbelger@8942: package org.dive4elements.river.artifacts.sinfo.tkhstate; gernotbelger@8942: gernotbelger@8942: import java.io.File; gernotbelger@8942: import java.io.IOException; gernotbelger@8942: import java.io.InputStreamReader; gernotbelger@8942: import java.nio.charset.StandardCharsets; gernotbelger@8942: import java.nio.file.Files; gernotbelger@8942: import java.util.ArrayList; gernotbelger@8942: import java.util.Arrays; gernotbelger@8942: import java.util.Collection; gernotbelger@8942: import java.util.Collections; gernotbelger@8942: import java.util.List; gernotbelger@8942: import java.util.Properties; gernotbelger@8942: gernotbelger@8942: import org.apache.commons.lang.ArrayUtils; gernotbelger@8942: import org.apache.commons.lang.StringUtils; gernotbelger@8942: import org.apache.commons.lang.math.NumberRange; gernotbelger@8942: import org.dive4elements.artifacts.common.utils.Config; gernotbelger@8942: import org.dive4elements.river.artifacts.model.Calculation; gernotbelger@8942: import org.dive4elements.river.model.BedHeight; gernotbelger@8942: import org.dive4elements.river.model.Range; gernotbelger@8942: import org.dive4elements.river.model.River; gernotbelger@8942: gernotbelger@8942: /** gernotbelger@8942: * This class knows how to find the default bed heights defined for tkh calculation gernotbelger@8942: * gernotbelger@8942: * @author Gernot Belger gernotbelger@8942: */ gernotbelger@8942: final class DefaultBedHeights { gernotbelger@8942: private static final String CONFIG_FILE = "sinfo_tkh_bedheights.properties"; gernotbelger@8942: private final River river; gernotbelger@8942: gernotbelger@8942: public DefaultBedHeights(final River river) { gernotbelger@8942: this.river = river; gernotbelger@8942: } gernotbelger@8942: gernotbelger@8942: public List getBedHeights(final Calculation problems) { gernotbelger@8942: final Collection bedHeightNames = loadBedHeightDefaultsForRiver(this.river, problems); gernotbelger@8942: gernotbelger@8942: final List defaultBedHeights = loadBedHeightsByName(this.river, bedHeightNames, problems); gernotbelger@8942: gernotbelger@8942: final List validBedHeights = new ArrayList<>(defaultBedHeights.size()); gernotbelger@8942: gernotbelger@8942: // REMARK: check for bad ranges because db schema allow for incomplete ranges, and ignore if this is the case gernotbelger@8942: for (final BedHeight bedHeight : defaultBedHeights) { gernotbelger@8942: gernotbelger@8942: final Range range = bedHeight.getRange(); gernotbelger@8942: gernotbelger@8942: if (range.getA() == null || range.getB() == null) gernotbelger@8942: problems.addProblem("sinfo.bedheightsfinder.badrange", bedHeight.getDescription()); gernotbelger@8942: else gernotbelger@8942: validBedHeights.add(bedHeight); gernotbelger@8942: } gernotbelger@8942: gernotbelger@8942: /* check for overlapping ranges, N2-search, but we expect only have small numbers of bed heights */ gernotbelger@8942: final List result = new ArrayList<>(defaultBedHeights.size()); gernotbelger@8942: gernotbelger@8942: for (int i = 0; i < defaultBedHeights.size(); i++) { gernotbelger@8942: final BedHeight bedHeight = validBedHeights.get(i); gernotbelger@8942: gernotbelger@8942: final Range range = bedHeight.getRange(); gernotbelger@8942: final NumberRange bedRange = new NumberRange(range.getA(), range.getB()); gernotbelger@8942: gernotbelger@8942: if (overlapsRange(bedRange, validBedHeights, i + 1)) { gernotbelger@8942: problems.addProblem("sinfo.bedheightsfinder.overlappingrange", bedHeight.getDescription()); gernotbelger@8942: } else gernotbelger@8942: result.add(bedHeight); gernotbelger@8942: } gernotbelger@8942: gernotbelger@8942: return result; gernotbelger@8942: } gernotbelger@8942: gernotbelger@8942: private static Collection loadBedHeightDefaultsForRiver(final River river, final Calculation problems) { gernotbelger@8942: final File configDir = Config.getConfigDirectory(); gernotbelger@8942: final File configFile = new File(configDir, CONFIG_FILE); gernotbelger@8942: gernotbelger@8942: final Properties properties = new Properties(); gernotbelger@8942: try (final InputStreamReader reader = new InputStreamReader(Files.newInputStream(configFile.toPath()), StandardCharsets.ISO_8859_1)) { gernotbelger@8942: properties.load(reader); gernotbelger@8942: gernotbelger@8942: final String value = properties.getProperty(river.getName()); gernotbelger@8942: final String[] split = StringUtils.split(StringUtils.trim(value), ','); gernotbelger@8942: if (ArrayUtils.isEmpty(split)) { gernotbelger@8942: problems.addProblem("sinfo.bedheightsfinder.configfile.missingriver", CONFIG_FILE, river.getName()); gernotbelger@8942: return Collections.emptyList(); gernotbelger@8942: } gernotbelger@8942: gernotbelger@8942: return Arrays.asList(split); gernotbelger@8942: } gernotbelger@8942: catch (final IOException e) { gernotbelger@8942: e.printStackTrace(); gernotbelger@8942: problems.addProblem("sinfo.bedheightsfinder.configfile.loaderror", CONFIG_FILE, e.getMessage()); gernotbelger@8942: return Collections.emptyList(); gernotbelger@8942: } gernotbelger@8942: } gernotbelger@8942: gernotbelger@8942: private static List loadBedHeightsByName(final River shouldBeRiver, final Collection bedHeightNames, final Calculation problems) { gernotbelger@8942: gernotbelger@8942: final List bedHeights = new ArrayList<>(bedHeightNames.size()); gernotbelger@8942: gernotbelger@8942: for (final String name : bedHeightNames) { gernotbelger@8942: try { gernotbelger@8942: final BedHeight bedHeight = BedHeight.getBedHeightByDescription(name); gernotbelger@8942: if (bedHeight == null) gernotbelger@8942: problems.addProblem("sinfo.bedheightsfinder.missingdescription", name); gernotbelger@8942: else { gernotbelger@8942: final River river = bedHeight.getRiver(); gernotbelger@8942: if (!shouldBeRiver.getId().equals(river.getId())) gernotbelger@8942: problems.addProblem("sinfo.bedheightsfinder.wrongriver", name, shouldBeRiver.getName()); gernotbelger@8942: else gernotbelger@8942: bedHeights.add(bedHeight); gernotbelger@8942: } gernotbelger@8942: } gernotbelger@8942: catch (final Exception e) { gernotbelger@8942: e.printStackTrace(); gernotbelger@8942: problems.addProblem("sinfo.bedheightsfinder.missingdescription", name); gernotbelger@8942: } gernotbelger@8942: } gernotbelger@8942: gernotbelger@8942: return bedHeights; gernotbelger@8942: } gernotbelger@8942: gernotbelger@8942: private static boolean overlapsRange(final NumberRange bedRange, final List result, final int startIndex) { gernotbelger@8942: gernotbelger@8942: for (int i = startIndex; i < result.size(); i++) { gernotbelger@8942: gernotbelger@8942: final BedHeight compareBed = result.get(i); gernotbelger@8942: final Range range = compareBed.getRange(); gernotbelger@8942: final NumberRange compareRange = new NumberRange(range.getA(), range.getB()); gernotbelger@8942: gernotbelger@8942: if (compareRange.overlapsRange(bedRange)) gernotbelger@8942: return true; gernotbelger@8942: } gernotbelger@8942: gernotbelger@8942: return false; gernotbelger@8942: } gernotbelger@8942: }