mschaefer@8971: /* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde mschaefer@8971: * Software engineering by mschaefer@8971: * Björnsen Beratende Ingenieure GmbH mschaefer@8971: * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt mschaefer@8971: * mschaefer@8971: * This file is Free Software under the GNU AGPL (>=v3) mschaefer@8971: * and comes with ABSOLUTELY NO WARRANTY! Check out the mschaefer@8971: * documentation coming with Dive4Elements River for details. mschaefer@8971: */ mschaefer@8971: mschaefer@8971: package org.dive4elements.river.importer.sinfo.parsers; mschaefer@8971: mschaefer@8971: import java.io.File; mschaefer@8971: import java.text.DateFormat; mschaefer@8971: import java.text.SimpleDateFormat; mschaefer@8971: import java.util.ArrayList; mschaefer@8971: import java.util.Date; mschaefer@8971: import java.util.List; mschaefer@8971: import java.util.regex.Matcher; mschaefer@8971: import java.util.regex.Pattern; mschaefer@8971: mschaefer@8971: import org.apache.log4j.Logger; mschaefer@8971: import org.dive4elements.river.importer.Config; mschaefer@8971: import org.dive4elements.river.importer.ImportRiver; mschaefer@8971: import org.dive4elements.river.importer.common.AbstractParser; mschaefer@8971: import org.dive4elements.river.importer.common.ParsingState; mschaefer@8971: import org.dive4elements.river.importer.sinfo.importitem.DailyDischargeDayLineImport; mschaefer@8971: import org.dive4elements.river.importer.sinfo.importitem.DailyDischargeSeriesImport; mschaefer@8971: import org.dive4elements.river.model.sinfo.DailyDischarge; mschaefer@8971: import org.dive4elements.river.model.sinfo.DailyDischargeValue; mschaefer@8971: mschaefer@8971: /** mschaefer@8971: * Reads and parses a daily discharge file mschaefer@8971: * mschaefer@8971: * @author Matthias Schäfer mschaefer@8971: * mschaefer@8971: */ mschaefer@8971: public class DailyDischargeParser extends AbstractParser { mschaefer@8971: mschaefer@8971: /***** FIELDS *****/ mschaefer@8971: mschaefer@8971: private static final Logger log = Logger.getLogger(DailyDischargeParser.class); mschaefer@8971: mschaefer@9658: static final Pattern IMPORT_FILENAME = Pattern.compile("^(.+)_mittlerer_Tagesabfluss\\.csv", Pattern.CASE_INSENSITIVE); mschaefer@8971: mschaefer@8971: private static final Pattern META_GAUGENAME = Pattern.compile("^#\\s*Stations-*Name:\\s*(\\S[^;]*).*", Pattern.CASE_INSENSITIVE); mschaefer@8971: mschaefer@9658: // private static final Pattern META_GAUGENUMBER = Pattern.compile("^#\\s*Stations-*Nummer:\\s*(\\S[^;]*).*", mschaefer@9658: // Pattern.CASE_INSENSITIVE); mschaefer@8971: mschaefer@9658: private static final Pattern META_BETREIBER = Pattern.compile("^#\\s*Betreiber:.*", Pattern.CASE_INSENSITIVE); mschaefer@9658: private static final Pattern META_PARAMETER = Pattern.compile("^#\\s*Parameter-Name:.*", Pattern.CASE_INSENSITIVE); mschaefer@9658: private static final Pattern META_ZEITREIHE = Pattern.compile("^#\\s*# Zeitreihe.*", Pattern.CASE_INSENSITIVE); mschaefer@9658: private static final Pattern META_REIHEBEGINN = Pattern.compile("^#\\s*Beginn der Zeitreihe:.*", Pattern.CASE_INSENSITIVE); mschaefer@9658: private static final Pattern META_REIHEENDE = Pattern.compile("^#\\s*Ende der Zeitreihe:.*", Pattern.CASE_INSENSITIVE); mschaefer@9658: mschaefer@9658: private static final Pattern META_COLUMNTITLES = Pattern.compile("^#*\\s*(Datum)\\s*;\\s*(Q[^;]*)", Pattern.CASE_INSENSITIVE); mschaefer@8971: mschaefer@8971: private static final DateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy"); mschaefer@8971: mschaefer@9658: private final List dates; mschaefer@9658: mschaefer@8971: mschaefer@8971: /***** CONSTRUCTORS *****/ mschaefer@8971: mschaefer@8971: public DailyDischargeParser(final File importPath, final File rootRelativePath, final ImportRiver river) { mschaefer@8971: super(importPath, rootRelativePath, river); mschaefer@9658: this.dates = new ArrayList<>(); mschaefer@8971: } mschaefer@8971: mschaefer@8971: mschaefer@8971: /***** METHODS *****/ mschaefer@8971: mschaefer@8971: @Override mschaefer@8971: protected Logger getLog() { mschaefer@8971: return log; mschaefer@8971: } mschaefer@8971: mschaefer@8971: /** mschaefer@8971: * Whether this import type shall be skipped mschaefer@8971: */ mschaefer@8971: public static boolean shallSkip() { mschaefer@8971: return Config.INSTANCE.skipSInfoDailyDischarge(); mschaefer@8971: } mschaefer@8971: mschaefer@8971: /** mschaefer@8971: * Creates a list of parsers for all daily discharge import files in a directory mschaefer@8971: */ mschaefer@8971: public static List createParsers(final File importDir, final File relativeDir, final ImportRiver river) { mschaefer@8971: final List parsers = new ArrayList<>(); mschaefer@8988: if (importDir.exists()) { mschaefer@9658: for (final File file : listFiles(importDir, IMPORT_FILENAME)) mschaefer@8988: parsers.add(new DailyDischargeParser(file, new File(relativeDir, file.getName()), river)); mschaefer@8988: } mschaefer@8971: return parsers; mschaefer@8971: } mschaefer@8971: mschaefer@8971: @Override mschaefer@9012: protected KmMode kmMode() { mschaefer@9012: return KmMode.NONE; mschaefer@8971: } mschaefer@8971: mschaefer@8971: @Override mschaefer@8971: protected DailyDischargeSeriesImport createSeriesImport(final String filename) { mschaefer@8971: return new DailyDischargeSeriesImport(filename); mschaefer@8971: } mschaefer@8971: mschaefer@8971: @Override mschaefer@8971: protected DailyDischargeDayLineImport createKmLineImport(final Double km, final String[] values) { mschaefer@8971: Date day = null; mschaefer@8971: try { mschaefer@8971: day = dateFormat.parse(values[0]); mschaefer@8971: } mschaefer@8971: catch (final Exception e) { mschaefer@9658: logLineWarning("Invalid date"); mschaefer@8971: return null; mschaefer@8971: } mschaefer@9658: final Number q = parseDoubleCheckNull(values, 1); mschaefer@9658: if ((q == null) || Double.isNaN(q.doubleValue())) { mschaefer@9658: logLineWarning(INVALID_VALUE_ERROR_FORMAT, "discharge"); mschaefer@8971: return null; mschaefer@8971: } mschaefer@9658: if (this.dates.contains(day)) { mschaefer@9658: logLineWarning("Duplicate date"); mschaefer@9658: return null; mschaefer@9658: } mschaefer@9658: this.dates.add(day); mschaefer@9658: return new DailyDischargeDayLineImport(day, q.doubleValue()); mschaefer@8971: } mschaefer@8971: mschaefer@8971: @Override mschaefer@8971: protected boolean handleMetaOther() { mschaefer@8971: if (handleMetaGaugeName()) mschaefer@8971: return true; mschaefer@9658: // else if (handleMetaGaugeNumber()) mschaefer@9658: // return true; mschaefer@9658: else if (META_BETREIBER.matcher(this.currentLine).matches()) mschaefer@9658: return true; mschaefer@9658: else if (META_PARAMETER.matcher(this.currentLine).matches()) mschaefer@9658: return true; mschaefer@9658: else if (META_ZEITREIHE.matcher(this.currentLine).matches()) mschaefer@9658: return true; mschaefer@9658: else if (META_REIHEBEGINN.matcher(this.currentLine).matches()) mschaefer@9658: return true; mschaefer@9658: else if (META_REIHEENDE.matcher(this.currentLine).matches()) mschaefer@8971: return true; mschaefer@8971: else mschaefer@8971: return false; mschaefer@8971: } mschaefer@8971: mschaefer@8971: private boolean handleMetaGaugeName() { mschaefer@8971: final Matcher m = META_GAUGENAME.matcher(this.currentLine); mschaefer@8971: if (m.matches()) { mschaefer@8971: this.metaPatternsMatched.add(META_GAUGENAME); mschaefer@8971: this.seriesHeader.setGaugeName(m.group(1).trim()); mschaefer@8971: return true; mschaefer@8971: } mschaefer@8971: return false; mschaefer@8971: } mschaefer@8971: mschaefer@9658: // private boolean handleMetaGaugeNumber() { mschaefer@9658: // final Matcher m = META_GAUGENUMBER.matcher(this.currentLine); mschaefer@9658: // if (m.matches()) { mschaefer@9658: // this.metaPatternsMatched.add(META_GAUGENUMBER); mschaefer@9658: // this.seriesHeader.setGaugeNumber(Long.parseLong(m.group(1))); mschaefer@9658: // return true; mschaefer@9658: // } mschaefer@9658: // return false; mschaefer@9658: // } mschaefer@8971: mschaefer@8971: @Override mschaefer@8971: protected boolean handleMetaColumnTitles() { mschaefer@9658: final Matcher m = META_COLUMNTITLES.matcher(this.currentLine); mschaefer@9658: if (!m.matches()) { mschaefer@8971: return false; mschaefer@9658: } mschaefer@8971: this.metaPatternsMatched.add(META_COLUMNTITLES); mschaefer@8971: this.columnTitles.clear(); mschaefer@9658: this.columnTitles.add(m.group(1)); mschaefer@9658: this.columnTitles.add(m.group(2)); mschaefer@9658: return true; mschaefer@9658: } mschaefer@9658: mschaefer@9658: /** mschaefer@9658: * Check meta data after all meta lines (#) have been read mschaefer@9658: */ mschaefer@9658: @Override mschaefer@9658: protected boolean checkMetaData() { mschaefer@9658: if (!super.checkRiverExists()) mschaefer@9658: return false; mschaefer@8971: this.seriesHeader.setGauge(this.river.getPeer().findGauge(this.seriesHeader.getGaugeNumber(), this.seriesHeader.getGaugeName())); mschaefer@8971: if (this.seriesHeader.getGauge() == null) { mschaefer@9658: logError("Gauge not found (%s)", this.seriesHeader.getGaugeName()); mschaefer@8971: this.headerParsingState = ParsingState.STOP; mschaefer@9658: return false; mschaefer@9658: } mschaefer@9658: if (super.checkMetaData() == false) mschaefer@9658: return false; mschaefer@9658: if (this.columnTitles.size() <= 1) { mschaefer@9658: logError("No valid column title line (Datum, Q) found"); mschaefer@9658: this.headerParsingState = ParsingState.STOP; mschaefer@9658: return false; mschaefer@8971: } mschaefer@8971: return true; mschaefer@8971: } mschaefer@9658: mschaefer@8971: }