teichmann@8025: /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde teichmann@8025: * Software engineering by Intevation GmbH teichmann@8025: * teichmann@8025: * This file is Free Software under the GNU AGPL (>=v3) teichmann@8025: * and comes with ABSOLUTELY NO WARRANTY! Check out the teichmann@8025: * documentation coming with Dive4Elements River for details. teichmann@8025: */ teichmann@8025: teichmann@8025: package org.dive4elements.river.importer.parsers; teichmann@8025: teichmann@8025: import java.io.File; teichmann@8025: import java.io.IOException; teichmann@8025: teichmann@8025: import java.text.NumberFormat; teichmann@8025: import java.text.ParseException; teichmann@8025: teichmann@8025: import java.util.ArrayList; teichmann@8025: import java.util.List; teichmann@8025: import java.util.regex.Matcher; teichmann@8025: import java.util.regex.Pattern; teichmann@8025: teichmann@8025: import org.apache.log4j.Logger; teichmann@8025: tom@8032: import org.dive4elements.river.importer.ImporterSession; teichmann@8025: import org.dive4elements.river.importer.ImportGrainFraction; teichmann@8031: import org.dive4elements.river.importer.ImportSedimentLoadLS; teichmann@8025: import org.dive4elements.river.importer.ImportSedimentLoadLSValue; teichmann@8025: import org.dive4elements.river.importer.ImportTimeInterval; teichmann@8025: import org.dive4elements.river.importer.ImportUnit; tom@8032: teichmann@8025: import org.dive4elements.river.model.GrainFraction; tom@8032: teichmann@8025: import org.dive4elements.river.utils.DateUtil; tom@8032: import org.dive4elements.river.utils.EpsilonComparator; teichmann@8025: tom@8032: /** Parses sediment load longitudinal section files. */ teichmann@8025: public class SedimentLoadLSParser extends LineParser { teichmann@8025: teichmann@8025: private static final Logger log = teichmann@8025: Logger.getLogger(SedimentLoadLSParser.class); teichmann@8025: teichmann@8025: teichmann@8025: public static final NumberFormat nf = NumberFormat.getInstance(DEFAULT_LOCALE); teichmann@8025: teichmann@8025: teichmann@8025: public static final Pattern TIMEINTERVAL_SINGLE = teichmann@8025: Pattern.compile("\\D*([0-9]+?)\\D*"); teichmann@8025: teichmann@8025: public static final Pattern TIMEINTERVAL_EPOCH = teichmann@8025: Pattern.compile("\\D*([0-9]+?)\\s*-\\s*([0-9]+?)\\D*"); teichmann@8025: teichmann@8025: public static final Pattern META_FRACTION = teichmann@8025: Pattern.compile("^Fraktion: (.*)"); teichmann@8025: tom@8032: public static final Pattern META_FRACTION_NAME = tom@8032: Pattern.compile("^Fraktionsname: (.*)"); tom@8032: teichmann@8025: public static final Pattern META_UNIT = teichmann@8025: Pattern.compile("^Einheit: \\[(.*)\\].*"); teichmann@8025: teichmann@8025: public static final Pattern META_COLUMN_NAMES = teichmann@8025: Pattern.compile("^Fluss-km.*"); teichmann@8025: tom@8032: public static final Pattern META_GRAIN_SIZE = tom@8032: Pattern.compile("([0-9]*,*[0-9]+)-([0-9]*,*[0-9]+) *mm"); teichmann@8025: teichmann@8025: tom@8032: protected List sedimentLoadLSs; teichmann@8025: teichmann@8031: protected ImportSedimentLoadLS[] current; teichmann@8025: teichmann@8025: protected ImportGrainFraction grainFraction; teichmann@8025: teichmann@8025: protected ImportUnit unit; teichmann@8025: teichmann@8025: protected String description; teichmann@8025: teichmann@8025: protected String[] columnNames; teichmann@8025: tom@8032: private String upper; tom@8032: tom@8032: private String lower; tom@8032: teichmann@8025: teichmann@8025: public SedimentLoadLSParser() { tom@8032: sedimentLoadLSs = new ArrayList(); teichmann@8025: } teichmann@8025: teichmann@8025: teichmann@8025: @Override teichmann@8025: public void parse(File file) throws IOException { teichmann@8025: description = file.getName(); teichmann@8025: teichmann@8025: super.parse(file); teichmann@8025: } teichmann@8025: teichmann@8025: teichmann@8025: @Override teichmann@8025: protected void reset() { teichmann@8025: current = null; teichmann@8025: grainFraction = null; teichmann@8025: unit = null; teichmann@8025: } teichmann@8025: teichmann@8025: teichmann@8025: @Override teichmann@8025: protected void finish() { teichmann@8025: if (current != null) { teichmann@8031: for (ImportSedimentLoadLS isy: current) { tom@8032: sedimentLoadLSs.add(isy); teichmann@8025: } teichmann@8025: } teichmann@8025: teichmann@8025: description = null; teichmann@8025: } teichmann@8025: teichmann@8025: teichmann@8025: @Override teichmann@8042: protected void handleLine(int lineNum, String line) throws LineParserException { teichmann@8025: if (line.startsWith(START_META_CHAR)) { teichmann@8025: handleMetaLine(stripMetaLine(line)); teichmann@8025: } teichmann@8025: else { teichmann@8025: handleDataLine(line); teichmann@8025: } teichmann@8025: } teichmann@8025: teichmann@8025: teichmann@8042: protected void handleMetaLine(String line) throws LineParserException { teichmann@8025: if (handleMetaUnit(line)) { teichmann@8025: return; teichmann@8025: } teichmann@8042: if (handleMetaFraction(line)) { tom@8032: return; tom@8032: } teichmann@8042: if (handleMetaFractionName(line)) { teichmann@8025: return; teichmann@8025: } teichmann@8042: if (handleColumnNames(line)) { teichmann@8042: return; teichmann@8025: } teichmann@8042: log.warn("SLLSP: Unknown meta line: '" + line + "'"); teichmann@8025: } teichmann@8025: teichmann@8025: teichmann@8025: protected boolean handleMetaUnit(String line) { teichmann@8025: Matcher m = META_UNIT.matcher(line); teichmann@8025: teichmann@8025: if (m.matches()) { teichmann@8025: unit = new ImportUnit(m.group(1)); teichmann@8025: return true; teichmann@8025: } teichmann@8025: teichmann@8025: return false; teichmann@8025: } teichmann@8025: teichmann@8025: teichmann@8025: public boolean handleMetaFraction(String line) { teichmann@8025: Matcher m = META_FRACTION.matcher(line); teichmann@8025: teichmann@8025: if (m.matches()) { tom@8032: String interval = m.group(1); teichmann@8025: tom@8032: Matcher sizes = META_GRAIN_SIZE.matcher(interval); tom@8032: if (sizes.matches()) { tom@8032: lower = sizes.group(1); tom@8032: upper = sizes.group(2); teichmann@8025: teichmann@8025: return true; teichmann@8025: } tom@8032: tom@8032: log.warn("SLLSP: Unrecognized grain-size interval. Ignored."); tom@8032: return true; tom@8032: tom@8032: } tom@8032: tom@8032: return false; tom@8032: } tom@8032: tom@8032: tom@8032: public boolean handleMetaFractionName(String line) { tom@8032: Matcher m = META_FRACTION_NAME.matcher(line); tom@8032: tom@8032: if (m.matches()) { tom@8032: String name = m.group(1); tom@8032: tom@8032: tom@8032: GrainFraction gf = ImporterSession.getInstance().getGrainFraction(name); tom@8032: tom@8032: if (gf != null) { tom@8032: tom@8032: if (lower != null && upper != null) { tom@8032: // Validate grain size interval tom@8032: try { tom@8032: Double lowval = nf.parse(lower).doubleValue(); tom@8032: Double upval = nf.parse(upper).doubleValue(); tom@8032: tom@8032: if (EpsilonComparator.CMP.compare(lowval, tom@8032: gf.getLower()) != 0 || tom@8032: EpsilonComparator.CMP.compare(upval, tom@8032: gf.getUpper()) != 0) { tom@8032: log.warn("SLLSP: Invalid grain size for grain fraction '" + tom@8032: name + "'. Ignored."); tom@8032: } tom@8032: } tom@8032: catch (ParseException pe) { tom@8032: log.warn("SLLSP: Could not parse grain-size interval. Ignored."); tom@8032: } tom@8032: } tom@8032: tom@8032: grainFraction = new ImportGrainFraction(gf); tom@8032: return true; tom@8032: } tom@8032: tom@8032: log.error("SLLSP: Unknown grain fraction: '" + name + "'"); teichmann@8025: } teichmann@8025: teichmann@8025: return false; teichmann@8025: } teichmann@8025: teichmann@8025: teichmann@8042: public boolean handleColumnNames(String line) throws LineParserException { teichmann@8025: Matcher m = META_COLUMN_NAMES.matcher(line); teichmann@8025: teichmann@8025: if (m.matches()) { teichmann@8025: columnNames = line.split(SEPERATOR_CHAR); teichmann@8025: tom@8032: // 'Fluss-km', 'Hinweise' and at least one data column required tom@8032: if (columnNames.length < 3) { teichmann@8042: throw new LineParserException("SLLSP: missing columns."); tom@8032: } tom@8032: tom@8032: initializeSedimentLoadLSs(); teichmann@8025: teichmann@8025: return true; teichmann@8025: } teichmann@8025: teichmann@8025: return false; teichmann@8025: } teichmann@8025: teichmann@8025: teichmann@8025: protected void handleDataLine(String line) { teichmann@8025: String[] vals = line.split(SEPERATOR_CHAR); teichmann@8025: teichmann@8025: if (vals == null || vals.length < columnNames.length-1) { tom@8032: log.warn("SLLSP: skip invalid data line: '" + line + "'"); teichmann@8025: return; teichmann@8025: } teichmann@8025: teichmann@8025: try { teichmann@8025: Double km = nf.parse(vals[0]).doubleValue(); teichmann@8025: teichmann@8025: for (int i = 1, n = columnNames.length-1; i < n; i++) { teichmann@8025: String curVal = vals[i]; teichmann@8025: teichmann@8025: if (curVal != null && curVal.length() > 0) { teichmann@8025: current[i-1].addValue(new ImportSedimentLoadLSValue( teichmann@8025: km, nf.parse(vals[i]).doubleValue() teichmann@8025: )); teichmann@8025: } teichmann@8025: } teichmann@8025: } teichmann@8025: catch (ParseException pe) { tom@8032: log.warn("SLLSP: unparseable number in data row '" + line + "':", pe); teichmann@8025: } teichmann@8025: } teichmann@8025: teichmann@8025: tom@8032: /** Initialize SedimentLoadLSs from columns, set the kind teichmann@8025: * with respect to file location (offical epoch or not?) */ tom@8032: private void initializeSedimentLoadLSs() { teichmann@8025: // skip first column (Fluss-km) and last column (Hinweise) teichmann@8031: current = new ImportSedimentLoadLS[columnNames.length-2]; teichmann@8025: teichmann@8025: Integer kind; teichmann@8025: teichmann@8025: if (inputFile.getAbsolutePath().contains("amtliche Epochen")) { teichmann@8025: kind = new Integer(1); teichmann@8025: } teichmann@8025: else { teichmann@8025: kind = new Integer(0); teichmann@8025: } teichmann@8025: teichmann@8025: for (int i = 0, n = columnNames.length; i < n-2; i++) { teichmann@8031: current[i] = new ImportSedimentLoadLS(this.description); teichmann@8025: current[i].setTimeInterval(getTimeInterval(columnNames[i+1])); teichmann@8025: current[i].setUnit(unit); teichmann@8025: current[i].setGrainFraction(grainFraction); teichmann@8025: current[i].setKind(kind); teichmann@8025: } teichmann@8025: } teichmann@8025: teichmann@8025: teichmann@8025: private ImportTimeInterval getTimeInterval(String column) { teichmann@8025: try { teichmann@8025: Matcher a = TIMEINTERVAL_EPOCH.matcher(column); teichmann@8025: if (a.matches()) { teichmann@8025: int yearA = nf.parse(a.group(1)).intValue(); teichmann@8025: int yearB = nf.parse(a.group(2)).intValue(); teichmann@8025: teichmann@8025: return new ImportTimeInterval( teichmann@8025: DateUtil.getStartDateFromYear(yearA), teichmann@8025: DateUtil.getEndDateFromYear(yearB) teichmann@8025: ); teichmann@8025: } teichmann@8025: teichmann@8025: Matcher b = TIMEINTERVAL_SINGLE.matcher(column); teichmann@8025: if (b.matches()) { teichmann@8025: int year = nf.parse(b.group(1)).intValue(); teichmann@8025: teichmann@8025: return new ImportTimeInterval(DateUtil.getStartDateFromYear(year)); teichmann@8025: } teichmann@8025: tom@8032: log.warn("SLLSP: Unknown time interval string: '" + column + "'"); teichmann@8025: } teichmann@8025: catch (ParseException pe) { tom@8032: log.warn("SLLSP: Could not parse years: " + column, pe); teichmann@8025: } teichmann@8025: teichmann@8025: return null; teichmann@8025: } teichmann@8025: teichmann@8025: tom@8032: public List getSedimentLoadLSs() { tom@8032: return sedimentLoadLSs; teichmann@8025: } teichmann@8025: } teichmann@8025: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :