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.EnumMap; mschaefer@8971: import java.util.HashMap; 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@9578: import org.dive4elements.river.importer.ImporterSession; 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.CollisionKmLineImport; mschaefer@8971: import org.dive4elements.river.importer.sinfo.importitem.CollisionSeriesImport; mschaefer@8971: import org.dive4elements.river.importer.sinfo.importitem.CollisionTypeImport; mschaefer@8971: import org.dive4elements.river.model.sinfo.Collision; mschaefer@8971: import org.dive4elements.river.model.sinfo.CollisionType; mschaefer@8971: import org.dive4elements.river.model.sinfo.CollisionValue; mschaefer@9579: import org.hibernate.Session; mschaefer@8971: mschaefer@8971: /** mschaefer@8971: * Reads and parses a collision file mschaefer@8971: * mschaefer@8971: * @author Matthias Schäfer mschaefer@8971: * mschaefer@8971: */ mschaefer@8971: public class CollisionParser extends AbstractParser { mschaefer@8971: mschaefer@8971: /***** FIELDS *****/ mschaefer@8971: mschaefer@8971: private static final Logger log = Logger.getLogger(CollisionParser.class); mschaefer@8971: mschaefer@8971: private static final Pattern META_YEAR = Pattern.compile("^#\\sJahr:\\s*([12]\\d\\d\\d).*", Pattern.CASE_INSENSITIVE); mschaefer@8971: mschaefer@8971: private enum ColTitlePattern { mschaefer@8971: DATE("Datum.*"), // mschaefer@8971: GAUGE_W("Pegelstand\\s*\\[(.*)\\].*"), // mschaefer@8971: GAUGE_NAME("Bezugspegel.*"), // mschaefer@8971: TYPE("Unfallart.*"); mschaefer@8971: mschaefer@8971: private final Pattern pattern; mschaefer@8971: mschaefer@8971: ColTitlePattern(final String regexp) { mschaefer@8971: this.pattern = Pattern.compile(regexp, Pattern.CASE_INSENSITIVE); mschaefer@8971: } mschaefer@8971: mschaefer@8971: public Pattern getPattern() { mschaefer@8971: return this.pattern; mschaefer@8971: } mschaefer@8971: } mschaefer@8971: mschaefer@8971: private static final DateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy"); mschaefer@8971: mschaefer@8971: private final EnumMap cols = new EnumMap<>(ColTitlePattern.class); mschaefer@8971: mschaefer@8971: private final HashMap types; mschaefer@8971: mschaefer@8971: mschaefer@8971: /***** CONSTRUCTORS *****/ mschaefer@8971: mschaefer@8971: public CollisionParser(final File importPath, final File rootRelativePath, final ImportRiver river) { mschaefer@8971: super(importPath, rootRelativePath, river); mschaefer@9579: logDebug("CollisionParser.new: calling ImporterSession.getInstance"); mschaefer@9579: final Session session = ImporterSession.getInstance().getDatabaseSession(); mschaefer@8971: this.types = new HashMap<>(); mschaefer@9579: for (final CollisionType type : CollisionType.getTypes(session)) mschaefer@8971: this.types.put(type.getName().trim().toLowerCase(), new CollisionTypeImport(type.getName())); 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.skipSInfoCollision(); mschaefer@8971: } mschaefer@8971: mschaefer@8971: /** mschaefer@8971: * Creates a list of parsers for all collision 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 CollisionParser(file, new File(relativeDir, file.getName()), river)); mschaefer@8988: } mschaefer@8971: return parsers; mschaefer@8971: } mschaefer@8971: mschaefer@8971: @Override mschaefer@8971: protected CollisionSeriesImport createSeriesImport(final String filename) { mschaefer@8971: return new CollisionSeriesImport(filename); mschaefer@8971: } mschaefer@8971: mschaefer@8971: @Override mschaefer@9012: protected KmMode kmMode() { mschaefer@9012: return KmMode.DUPLICATES; mschaefer@8971: } mschaefer@8971: mschaefer@8971: @Override mschaefer@8971: protected boolean handleMetaOther() { mschaefer@8971: if (handleMetaYear()) mschaefer@8971: return true; mschaefer@8971: else mschaefer@8971: return false; mschaefer@8971: } mschaefer@8971: mschaefer@8971: private boolean handleMetaYear() { mschaefer@8971: final Matcher m = META_YEAR.matcher(this.currentLine); mschaefer@8971: if (m.matches()) { mschaefer@8971: this.metaPatternsMatched.add(META_YEAR); mschaefer@8971: this.seriesHeader.setYear(Integer.parseInt(m.group(1))); mschaefer@8971: return true; mschaefer@8971: } mschaefer@8971: return false; mschaefer@8971: } mschaefer@8971: mschaefer@8971: @Override mschaefer@8971: protected boolean handleMetaColumnTitles() { mschaefer@8971: if (!super.handleMetaColumnTitles()) mschaefer@8971: return false; mschaefer@8971: for (final ColTitlePattern col : ColTitlePattern.values()) mschaefer@8971: this.cols.put(col, -1); mschaefer@8971: for (int i = 1; i <= this.columnTitles.size() - 1; i++) { mschaefer@8971: for (final ColTitlePattern col : ColTitlePattern.values()) { mschaefer@8971: if (col.getPattern().matcher(this.columnTitles.get(i)).matches()) { mschaefer@8971: this.cols.put(col, i); mschaefer@8971: break; mschaefer@8971: } mschaefer@8971: } mschaefer@8971: } mschaefer@8971: if (this.cols.get(ColTitlePattern.DATE) < 0) mschaefer@8971: logWarning("Column of the event dates could not be identified, missing column title 'Datum'"); mschaefer@8971: if (this.cols.get(ColTitlePattern.TYPE) < 0) { mschaefer@8971: logError("Column of the collision types could not be identified, missing column title 'Unfallart'"); mschaefer@8971: this.headerParsingState = ParsingState.STOP; mschaefer@8971: return false; mschaefer@8971: } mschaefer@8971: if (!this.metaPatternsMatched.contains(META_YEAR)) { mschaefer@8971: logError("Required meta info for the year is missing"); mschaefer@8971: this.headerParsingState = ParsingState.STOP; mschaefer@8971: } mschaefer@8971: return true; mschaefer@8971: } mschaefer@8971: mschaefer@8971: @Override mschaefer@8971: protected CollisionKmLineImport createKmLineImport(final Double km, final String[] values) { mschaefer@8971: Date eventDate = null; mschaefer@8971: try { mschaefer@8971: eventDate = dateFormat.parse(values[this.cols.get(ColTitlePattern.DATE)]); mschaefer@8971: } mschaefer@8971: catch (final Exception e) { mschaefer@8971: logError("Invalid date in line " + this.in.getLineNumber()); mschaefer@8971: return null; mschaefer@8971: } mschaefer@8971: final String typeName = values[this.cols.get(ColTitlePattern.TYPE)].trim(); mschaefer@8971: final String typeKey = typeName.toLowerCase(); mschaefer@8971: CollisionTypeImport type = null; mschaefer@8971: if (this.types.containsKey(typeKey)) mschaefer@8971: type = this.types.get(typeKey); mschaefer@8971: else { mschaefer@8971: type = new CollisionTypeImport(typeName); mschaefer@8971: this.types.put(typeKey, type); mschaefer@8971: } mschaefer@8971: String gaugeName = null; mschaefer@8971: if (this.cols.get(ColTitlePattern.GAUGE_NAME) >= 0) mschaefer@8971: gaugeName = values[this.cols.get(ColTitlePattern.GAUGE_NAME)].trim(); mschaefer@8971: double gaugeW = Double.NaN; mschaefer@8971: if (this.cols.get(ColTitlePattern.GAUGE_W) >= 0) mschaefer@8971: gaugeW = parseDoubleWithNull(values[this.cols.get(ColTitlePattern.GAUGE_W)]).doubleValue(); mschaefer@8971: return new CollisionKmLineImport(km, type, eventDate, gaugeName, gaugeW); mschaefer@8971: } mschaefer@8971: }