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.util.ArrayList; 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.DepthEvolutionKmLineImport; mschaefer@8971: import org.dive4elements.river.importer.sinfo.importitem.DepthEvolutionSeriesImport; mschaefer@8971: import org.dive4elements.river.model.sinfo.DepthEvolution; mschaefer@8971: import org.dive4elements.river.model.sinfo.DepthEvolutionValue; mschaefer@8971: mschaefer@8971: /** mschaefer@8971: * Reads and parses a depth evolution file mschaefer@8971: * mschaefer@8971: * @author Matthias Schäfer mschaefer@8971: * mschaefer@8971: */ mschaefer@8971: public class DepthEvolutionParser extends AbstractParser { mschaefer@8971: mschaefer@9657: /***** TYPES *****/ mschaefer@8971: mschaefer@9636: public enum GroupDirectory { mschaefer@9032: NONE(DepthEvolution.Group.NONE, ""), // mschaefer@9636: AKTUELL(DepthEvolution.Group.AKTUELL, "Bezug_aktueller_GlW"), // mschaefer@9636: ETAPPE(DepthEvolution.Group.ETAPPE, "GlW-Etappen"); mschaefer@9032: mschaefer@9032: private final DepthEvolution.Group group; mschaefer@9032: private final String dirname; mschaefer@9032: mschaefer@9032: GroupDirectory(final DepthEvolution.Group group, final String dirname) { mschaefer@9032: this.group = group; mschaefer@9032: this.dirname = dirname; mschaefer@9032: } mschaefer@9032: mschaefer@9032: public DepthEvolution.Group getGroup() { mschaefer@9032: return this.group; mschaefer@9032: } mschaefer@9032: mschaefer@9032: public String getDirName() { mschaefer@9032: return this.dirname; mschaefer@9032: } mschaefer@9032: mschaefer@9032: public static GroupDirectory forDirName(final String dirname) { mschaefer@9032: for (final GroupDirectory gd : GroupDirectory.values()) { mschaefer@9032: if (dirname.equalsIgnoreCase(gd.getDirName())) mschaefer@9032: return gd; mschaefer@9032: } mschaefer@9032: return NONE; mschaefer@9032: } mschaefer@9032: } mschaefer@9032: mschaefer@8971: mschaefer@9657: /***** FIELDS *****/ mschaefer@9657: mschaefer@9657: private static final Logger log = Logger.getLogger(DepthEvolutionParser.class); mschaefer@9657: mschaefer@9657: protected static final Pattern META_REFERENCE_YEAR = Pattern.compile("^#\\sBezugsjahr:\\s*([12]\\d{3}).*", Pattern.CASE_INSENSITIVE); mschaefer@9657: mschaefer@9657: protected static final Pattern META_START_YEAR = Pattern.compile("^#\\sAusgangsjahr:\\s*([12]\\d{3}).*", Pattern.CASE_INSENSITIVE); mschaefer@9657: mschaefer@9657: private static final Pattern META_CURR_SOUNDING = Pattern.compile("^#\\sAktuelle Peilung\\s*\\/\\s*Epoche:\\s*([^;]*([12]\\d{3})[^;]*).*", mschaefer@9657: Pattern.CASE_INSENSITIVE); mschaefer@9657: mschaefer@9657: private static final Pattern META_OLD_SOUNDING = Pattern.compile("^#\\sHistorische Peilung\\s*\\/\\s*Epoche:\\s*([^;]*([12]\\d{3})[^;]*).*", mschaefer@9657: Pattern.CASE_INSENSITIVE); mschaefer@9657: mschaefer@9657: private static final Pattern META_CURR_WSP = Pattern.compile("^#\\sAktuelle Wasserspiegellage:\\s*([^;]*([12]\\d{3})[^;]*).*", Pattern.CASE_INSENSITIVE); mschaefer@9657: mschaefer@9657: private static final Pattern META_OLD_WSP = Pattern.compile("^#\\sHistorische Wasserspiegellage:\\s*([^;]*([12]\\d{3})[^;]*).*", Pattern.CASE_INSENSITIVE); mschaefer@9657: mschaefer@9657: private static final Pattern COLUMN_TC_TITLE = Pattern.compile("Flie((.)|(ss))tiefenentwicklung\\s*\\[cm\\].*", Pattern.CASE_INSENSITIVE); mschaefer@9657: mschaefer@9657: private static final Pattern COLUMN_CPY_TITLE = Pattern.compile("Flie((.)|(ss))tiefenentwicklung\\s*\\[cm\\/a\\].*", Pattern.CASE_INSENSITIVE); mschaefer@9657: mschaefer@9657: private int currSoundingYear; mschaefer@9657: private int oldSoundingYear; mschaefer@9657: private int currWspYear; mschaefer@9657: private int oldWspYear; mschaefer@9657: mschaefer@9657: mschaefer@8971: /***** CONSTRUCTORS *****/ mschaefer@8971: mschaefer@8971: public DepthEvolutionParser(final File importPath, final File rootRelativePath, final ImportRiver river) { mschaefer@8971: super(importPath, rootRelativePath, river); 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.skipSInfoDepthEvolution(); mschaefer@8971: } mschaefer@8971: mschaefer@8971: /** mschaefer@8971: * Creates a list of parsers for all depth_evolution 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@8988: for (final File file : listFiles(importDir, ".csv")) mschaefer@8988: parsers.add(new DepthEvolutionParser(file, new File(relativeDir, file.getName()), river)); mschaefer@8971: return parsers; mschaefer@8971: } mschaefer@8971: mschaefer@8971: @Override mschaefer@8971: protected boolean handleMetaOther() { mschaefer@9657: if (handleMetaReferenceYear()) mschaefer@8971: return true; mschaefer@9657: else if (handleMetaStartYear()) mschaefer@8971: return true; mschaefer@8971: else if (handleMetaCurrSounding()) mschaefer@8971: return true; mschaefer@8971: else if (handleMetaOldSounding()) mschaefer@8971: return true; mschaefer@8971: else if (handleMetaCurrGlw()) mschaefer@8971: return true; mschaefer@8971: else if (handleMetaOldGlw()) mschaefer@8971: return true; mschaefer@8971: else mschaefer@8971: return false; mschaefer@8971: } mschaefer@8971: mschaefer@9657: private boolean handleMetaReferenceYear() { mschaefer@9657: final Matcher m = META_REFERENCE_YEAR.matcher(this.currentLine); mschaefer@9657: if (m.matches()) { mschaefer@9657: this.metaPatternsMatched.add(META_REFERENCE_YEAR); mschaefer@9657: this.seriesHeader.setReference_year(Integer.parseInt(m.group(1))); mschaefer@9657: return true; mschaefer@9657: } mschaefer@9657: return false; mschaefer@9657: } mschaefer@9657: mschaefer@8971: private boolean handleMetaStartYear() { mschaefer@8971: final Matcher m = META_START_YEAR.matcher(this.currentLine); mschaefer@8971: if (m.matches()) { mschaefer@8971: this.metaPatternsMatched.add(META_START_YEAR); mschaefer@8971: this.seriesHeader.setStart_year(Integer.parseInt(m.group(1))); mschaefer@8971: return true; mschaefer@8971: } mschaefer@8971: return false; mschaefer@8971: } mschaefer@8971: mschaefer@8971: private boolean handleMetaCurrSounding() { mschaefer@8971: final Matcher m = META_CURR_SOUNDING.matcher(this.currentLine); mschaefer@8971: if (m.matches()) { mschaefer@8971: this.metaPatternsMatched.add(META_CURR_SOUNDING); mschaefer@8971: this.seriesHeader.setCurr_sounding(parseMetaInfo(m.group(1).trim())); mschaefer@9657: this.currSoundingYear = Integer.valueOf(m.group(2)).intValue(); mschaefer@8971: return true; mschaefer@8971: } mschaefer@8971: return false; mschaefer@8971: } mschaefer@8971: mschaefer@8971: private boolean handleMetaOldSounding() { mschaefer@8971: final Matcher m = META_OLD_SOUNDING.matcher(this.currentLine); mschaefer@8971: if (m.matches()) { mschaefer@8971: this.metaPatternsMatched.add(META_OLD_SOUNDING); mschaefer@8971: this.seriesHeader.setOld_sounding(parseMetaInfo(m.group(1).trim())); mschaefer@9657: this.oldSoundingYear = Integer.valueOf(m.group(2)).intValue(); mschaefer@8971: return true; mschaefer@8971: } mschaefer@8971: return false; mschaefer@8971: } mschaefer@8971: mschaefer@8971: private boolean handleMetaCurrGlw() { mschaefer@8971: final Matcher m = META_CURR_WSP.matcher(this.currentLine); mschaefer@8971: if (m.matches()) { mschaefer@8971: this.metaPatternsMatched.add(META_CURR_WSP); mschaefer@8971: this.seriesHeader.setCurr_glw(parseMetaInfo(m.group(1).trim())); mschaefer@9657: this.currWspYear = Integer.valueOf(m.group(2)).intValue(); mschaefer@8971: return true; mschaefer@8971: } mschaefer@8971: return false; mschaefer@8971: } mschaefer@8971: mschaefer@8971: private boolean handleMetaOldGlw() { mschaefer@8971: final Matcher m = META_OLD_WSP.matcher(this.currentLine); mschaefer@8971: if (m.matches()) { mschaefer@8971: this.metaPatternsMatched.add(META_OLD_WSP); mschaefer@8971: this.seriesHeader.setOld_glw(parseMetaInfo(m.group(1).trim())); mschaefer@9657: this.oldWspYear = Integer.valueOf(m.group(2)).intValue(); mschaefer@8971: return true; mschaefer@8971: } mschaefer@8971: return false; mschaefer@8971: } mschaefer@8971: mschaefer@8971: @Override mschaefer@9657: protected boolean checkMetaData() { mschaefer@9657: if (super.checkMetaData() == false) mschaefer@9657: return false; mschaefer@9657: if (this.seriesHeader.getReference_year() == null) { mschaefer@9657: logError("Reference year is missing"); mschaefer@9657: this.headerParsingState = ParsingState.STOP; mschaefer@9657: return false; mschaefer@9657: } mschaefer@9657: if (this.seriesHeader.getStart_year() == null) { mschaefer@9657: logError("Start year is missing"); mschaefer@9657: this.headerParsingState = ParsingState.STOP; mschaefer@9657: return false; mschaefer@9657: } mschaefer@9657: if (this.seriesHeader.getReference_year() <= this.seriesHeader.getStart_year()) { mschaefer@9657: logError("Reference year not greater than start year"); mschaefer@9657: this.headerParsingState = ParsingState.STOP; mschaefer@9657: return false; mschaefer@9657: } mschaefer@9657: if (this.currSoundingYear <= this.oldSoundingYear) { mschaefer@9657: logError("Current sounding year not greater than historical sounding year"); mschaefer@9657: this.headerParsingState = ParsingState.STOP; mschaefer@9657: return false; mschaefer@9657: } mschaefer@9657: if (this.currWspYear != this.seriesHeader.getReference_year()) { mschaefer@9657: logError("Current waterlevel year differs from reference year"); mschaefer@9657: this.headerParsingState = ParsingState.STOP; mschaefer@9657: return false; mschaefer@9657: } mschaefer@9657: if (this.oldWspYear != this.seriesHeader.getStart_year()) { mschaefer@9657: logError("Historical waterlevel year differs from start year"); mschaefer@9657: this.headerParsingState = ParsingState.STOP; mschaefer@9657: return false; mschaefer@9657: } mschaefer@9657: if (!this.metaPatternsMatched.contains(META_START_YEAR) || !this.metaPatternsMatched.contains(META_REFERENCE_YEAR) mschaefer@9657: || !this.metaPatternsMatched.contains(META_CURR_SOUNDING) || !this.metaPatternsMatched.contains(META_OLD_SOUNDING) mschaefer@9657: || !this.metaPatternsMatched.contains(META_CURR_WSP) || !this.metaPatternsMatched.contains(META_OLD_WSP)) { mschaefer@9657: logError("One or more of the required meta infos are missing"); mschaefer@9657: this.headerParsingState = ParsingState.STOP; mschaefer@9657: } mschaefer@9657: return true; mschaefer@9657: } mschaefer@9657: mschaefer@9657: @Override mschaefer@8971: protected boolean handleMetaColumnTitles() { mschaefer@9657: if (!super.handleMetaColumnTitles()) mschaefer@9657: return false; mschaefer@9657: final Matcher tcm = COLUMN_TC_TITLE.matcher(this.columnTitles.get(1)); mschaefer@9657: if (!tcm.matches()) { mschaefer@9657: logLineError("Column 2: Invalid column title and/or unit"); mschaefer@9657: this.headerParsingState = ParsingState.STOP; mschaefer@8971: return true; mschaefer@8971: } mschaefer@9657: final Matcher cpym = COLUMN_CPY_TITLE.matcher(this.columnTitles.get(2)); mschaefer@9657: if (!cpym.matches()) { mschaefer@9657: logLineError("Column 3: Invalid column title and/or unit"); mschaefer@9657: this.headerParsingState = ParsingState.STOP; mschaefer@9657: } mschaefer@9657: return true; mschaefer@8971: } mschaefer@8971: mschaefer@8971: @Override mschaefer@8971: protected DepthEvolutionSeriesImport createSeriesImport(final String filename) { mschaefer@9032: final DepthEvolutionSeriesImport series = new DepthEvolutionSeriesImport(filename); mschaefer@9032: series.setGroup(GroupDirectory.forDirName(this.importPath.getParentFile().getName()).getGroup()); mschaefer@9032: return series; mschaefer@8971: } mschaefer@8971: mschaefer@8971: @Override mschaefer@8971: protected DepthEvolutionKmLineImport createKmLineImport(final Double km, final String[] values) { mschaefer@9657: final Number tc = parseDoubleCheckNull(values, 1); mschaefer@9657: if ((tc == null) || Double.isNaN(tc.doubleValue())) { mschaefer@9657: logLineWarning(INVALID_VALUE_ERROR_FORMAT, "total change"); mschaefer@8971: return null; mschaefer@8971: } mschaefer@9657: final Number cpy = parseDoubleCheckNull(values, 2); mschaefer@9657: if ((cpy == null) || Double.isNaN(cpy.doubleValue())) { mschaefer@9657: logLineWarning(INVALID_VALUE_ERROR_FORMAT, "change per year"); mschaefer@8971: return null; mschaefer@8971: } mschaefer@8971: // cm to m mschaefer@9657: return new DepthEvolutionKmLineImport(km, tc.doubleValue() / 100.0, cpy.doubleValue() / 100.0); mschaefer@8971: } mschaefer@8971: }