view backend/src/main/java/org/dive4elements/river/importer/sinfo/parsers/ChannelParser.java @ 9653:3b3c7513472e

Importer (s/u-info) extensions: support of multiple channel data series, check for non-overlapping year ranges
author mschaefer
date Mon, 23 Mar 2020 15:06:26 +0100
parents ae76f618d990
children
line wrap: on
line source
/* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
 * Software engineering by
 *  Björnsen Beratende Ingenieure GmbH
 *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
 *
 * This file is Free Software under the GNU AGPL (>=v3)
 * and comes with ABSOLUTELY NO WARRANTY! Check out the
 * documentation coming with Dive4Elements River for details.
 */

package org.dive4elements.river.importer.sinfo.parsers;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;
import org.dive4elements.river.importer.Config;
import org.dive4elements.river.importer.ImportRiver;
import org.dive4elements.river.importer.common.AbstractParser;
import org.dive4elements.river.importer.common.ParsingState;
import org.dive4elements.river.importer.sinfo.importitem.ChannelKmLineImport;
import org.dive4elements.river.importer.sinfo.importitem.ChannelSeriesImport;
import org.dive4elements.river.model.sinfo.Channel;
import org.dive4elements.river.model.sinfo.ChannelValue;

/**
 * Reads and parses a channel size file
 *
 * @author Matthias Schäfer
 *
 */
public class ChannelParser extends AbstractParser<Channel, ChannelValue, ChannelKmLineImport, ChannelSeriesImport> {

    /***** FIELDS *****/

    private static final Logger log = Logger.getLogger(ChannelParser.class);

    private static final Pattern IMPORT_FILENAME = Pattern.compile("Fahrrinne.*\\.csv", Pattern.CASE_INSENSITIVE);

    private static final Pattern META_FIRST = Pattern.compile("^#\\sFahrrinne.*", Pattern.CASE_INSENSITIVE);

    private static final Pattern META_YEARS = Pattern.compile("^#\\sZeitraum:\\s*([12]\\d\\d\\d)*\\s*-\\s*([12]\\d\\d\\d)*.*", Pattern.CASE_INSENSITIVE);

    private static final Pattern WIDTH_COLUMNTITLE = Pattern.compile("Sollbreite\\s*\\[(.*)\\].*", Pattern.CASE_INSENSITIVE);

    private static final Pattern DEPTH_COLUMNTITLE = Pattern.compile("Solltiefe\\s*\\[(.*)\\].*", Pattern.CASE_INSENSITIVE);

    private int widthColIndex;

    private int depthColIndex;


    /***** CONSTRUCTORS *****/

    public ChannelParser(final File importPath, final File rootRelativePath, final ImportRiver river) {
        super(importPath, rootRelativePath, river);
        this.widthColIndex = -1;
        this.depthColIndex = -1;
    }


    /***** METHODS *****/

    @Override
    protected Logger getLog() {
        return log;
    }

    /**
     * Whether this import type shall be skipped
     */
    public static boolean shallSkip() {
        return Config.INSTANCE.skipSInfoChannel();
    }

    /**
     * Creates a list of parsers for all channel import files in a directory
     */
    public static List<ChannelParser> createParsers(final File importDir, final File relativeDir, final ImportRiver river) {
        final List<ChannelParser> parsers = new ArrayList<>();
        if (importDir.exists())
            for (final File file : listFiles(importDir, IMPORT_FILENAME))
                parsers.add(new ChannelParser(file, new File(relativeDir, file.getName()), river));
        return parsers;
    }

    @Override
    protected boolean handleMetaOther() {
        if (handleMetaFirst())
            return true;
        else if (handleMetaYears())
            return true;
        else
            return false;
    }

    private boolean handleMetaFirst() {
        final Matcher m = META_FIRST.matcher(this.currentLine);
        if (m.matches()) {
            this.metaPatternsMatched.add(META_FIRST);
            return true;
        }
        return false;
    }

    private boolean handleMetaYears() {
        final Matcher m = META_YEARS.matcher(this.currentLine);
        if (m.matches()) {
            this.metaPatternsMatched.add(META_YEARS);
            try {
                if (m.group(1) != null)
                    this.seriesHeader.setYear_from(Integer.valueOf(m.group(1)));
                else
                    throw new NumberFormatException();
                if (m.group(2) != null)
                    this.seriesHeader.setYear_to(Integer.valueOf(m.group(2)));
                else
                    throw new NumberFormatException();
            }
            catch (final Exception e) {
                logLineError("Invalid or missing start and/or end year");
                this.headerParsingState = ParsingState.STOP;
            }
            return true;
        }
        return false;
    }

    @Override
    protected boolean handleMetaColumnTitles() {
        if (super.handleMetaColumnTitles()) {
            for (int i = 1; i <= this.columnTitles.size() - 1; i++) {
                if (DEPTH_COLUMNTITLE.matcher(this.columnTitles.get(i)).matches())
                    this.depthColIndex = i;
                else if (WIDTH_COLUMNTITLE.matcher(this.columnTitles.get(i)).matches())
                    this.widthColIndex = i;
            }
            if ((this.widthColIndex < 0) || (this.depthColIndex < 0)) {
                logLineError("Columns of width and/or depth values could not be identified, missing column title 'Sollbreite...'/'Sollhöhe...'");
                this.headerParsingState = ParsingState.STOP;
            }
            return true;
        }
        else
            return false;
    }

    @Override
    protected ChannelSeriesImport createSeriesImport(final String filename) {
        return new ChannelSeriesImport(filename);
    }

    @Override
    protected ChannelKmLineImport createKmLineImport(final Double km, final String[] values) {
        final Number width = parseDoubleCheckNull(values, this.widthColIndex);
        if ((width == null) || Double.isNaN(width.doubleValue())) {
            logLineError(INVALID_VALUE_ERROR_FORMAT, "width");
            return null;
        }
        final Number depth = parseDoubleCheckNull(values, this.depthColIndex);
        if ((depth == null) || Double.isNaN(depth.doubleValue())) {
            logLineError(INVALID_VALUE_ERROR_FORMAT, "depth");
            return null;
        }
        return new ChannelKmLineImport(km, width.doubleValue(), depth.doubleValue());
    }
}

http://dive4elements.wald.intevation.org