teichmann@5844: /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde teichmann@5844: * Software engineering by Intevation GmbH teichmann@5844: * teichmann@5992: * This file is Free Software under the GNU AGPL (>=v3) teichmann@5844: * and comes with ABSOLUTELY NO WARRANTY! Check out the teichmann@5992: * documentation coming with Dive4Elements River for details. teichmann@5844: */ teichmann@5844: teichmann@5829: package org.dive4elements.river.importer.parsers; ingo@2811: ingo@2811: import java.io.File; ingo@2811: ingo@2811: import java.math.BigDecimal; ingo@2811: ingo@2811: import java.text.NumberFormat; ingo@2811: import java.text.ParseException; ingo@2811: ingo@2811: import java.util.ArrayList; ingo@2811: import java.util.Date; ingo@2811: import java.util.List; tom@6273: import java.util.TreeSet; ingo@2811: import java.util.Locale; ingo@2811: ingo@2811: import java.util.regex.Matcher; ingo@2811: import java.util.regex.Pattern; ingo@2811: ingo@2811: import java.io.IOException; ingo@2811: import java.io.LineNumberReader; ingo@2811: import java.io.FileInputStream; ingo@2811: import java.io.InputStreamReader; ingo@2811: ingo@2811: import org.apache.log4j.Logger; ingo@2811: tom@8559: import org.dive4elements.river.importer.ImportBedHeight; tom@8559: import org.dive4elements.river.importer.ImportBedHeightValue; teichmann@5829: import org.dive4elements.river.importer.ImportBedHeightType; teichmann@5829: import org.dive4elements.river.importer.ImportElevationModel; teichmann@5829: import org.dive4elements.river.importer.ImportLocationSystem; teichmann@5829: import org.dive4elements.river.importer.ImportRange; teichmann@5829: import org.dive4elements.river.importer.ImportTimeInterval; teichmann@5829: import org.dive4elements.river.importer.ImportUnit; teichmann@5829: import org.dive4elements.river.model.BedHeightType; teichmann@5829: import org.dive4elements.river.importer.ImporterSession; teichmann@8187: import org.dive4elements.river.backend.utils.EpsilonComparator; teichmann@8187: import org.dive4elements.river.backend.utils.DateUtil; ingo@2811: tom@8557: public class BedHeightParser { ingo@2811: ingo@2811: private static final Logger log = ingo@2811: Logger.getLogger(BedHeightParser.class); ingo@2811: ingo@2811: public static final String ENCODING = "ISO-8859-1"; ingo@2811: ingo@2811: public static final Locale DEFAULT_LOCALE = Locale.GERMAN; ingo@2811: ingo@2811: public static final String START_META_CHAR = "#"; ingo@2811: public static final String SEPERATOR_CHAR = ";"; ingo@2811: ingo@2811: public static final Pattern META_YEAR = felix@3960: Pattern.compile("^Jahr: [^0-9]*(\\d*).*"); ingo@2811: ingo@2811: public static final Pattern META_TIMEINTERVAL = ingo@2811: Pattern.compile("^Zeitraum: Epoche (\\d*)-(\\d*).*"); ingo@2811: ingo@2811: public static final Pattern META_TYPE = ingo@2811: Pattern.compile("^Aufnahmeart: (.*).*"); ingo@2811: ingo@2811: public static final Pattern META_LOCATION_SYSTEM = ingo@2811: Pattern.compile("^Lagesystem: (.*).*"); ingo@2811: ingo@2811: public static final Pattern META_CUR_ELEVATION_SYSTEM = ingo@2811: Pattern.compile("^H.hensystem:\\s(\\w++) (.* )??\\[(.*)\\].*"); ingo@2811: ingo@2811: public static final Pattern META_OLD_ELEVATION_SYSTEM = ingo@2811: Pattern.compile("^urspr.ngliches H.hensystem:\\s(\\w++) (.* )??\\[(.*)\\].*"); ingo@2811: ingo@2811: public static final Pattern META_RANGE = tom@5484: Pattern.compile("^Strecke:\\D*(\\d++.?\\d*) ?- ?(\\d++.?\\d*).*"); ingo@2811: ingo@2811: public static final Pattern META_EVALUATION_BY = ingo@2811: Pattern.compile("^Auswerter: (.*).*"); ingo@2811: ingo@2811: public static final Pattern META_COMMENTS = ingo@2811: Pattern.compile("^Weitere Bemerkungen: (.*).*"); ingo@2811: ingo@2811: ingo@2811: protected static NumberFormat nf = NumberFormat.getInstance(DEFAULT_LOCALE); ingo@2811: ingo@2811: tom@8559: protected List bedHeights; ingo@2811: ingo@2811: tom@8559: protected ImportBedHeight newImportBedHeight(String description) { tom@8559: return new ImportBedHeight(description); tom@8557: } ingo@2811: ingo@2811: tom@6273: protected TreeSet kmExists; ingo@2811: ingo@2811: public BedHeightParser() { tom@8559: bedHeights = new ArrayList(); tom@6273: kmExists = new TreeSet(EpsilonComparator.CMP); ingo@2811: } ingo@2811: ingo@2811: tom@8559: public List getBedHeights() { ingo@2811: return bedHeights; ingo@2811: } ingo@2811: ingo@2811: ingo@2811: public void parse(File file) throws IOException { ingo@2811: log.info("Parsing bed height single file '" + file + "'"); ingo@2811: tom@8559: ImportBedHeight obj = newImportBedHeight(file.getName().replaceAll("\\.csv", "")); ingo@2811: tom@6273: kmExists.clear(); teichmann@6285: ingo@2811: LineNumberReader in = null; ingo@2811: try { ingo@2811: in = ingo@2811: new LineNumberReader( ingo@2811: new InputStreamReader( ingo@2811: new FileInputStream(file), ENCODING)); ingo@2811: ingo@2811: String line = null; ingo@2811: while ((line = in.readLine()) != null) { ingo@2811: if ((line = line.trim()).length() == 0) { ingo@2811: continue; ingo@2811: } ingo@2811: ingo@2811: if (line.startsWith(START_META_CHAR)) { ingo@2811: handleMetaLine(obj, line); ingo@2811: } ingo@2811: else { ingo@2811: handleDataLine(obj, line); ingo@2811: } ingo@2811: } ingo@2811: ingo@2811: log.info("File contained " + obj.getValueCount() + " values."); ingo@2811: bedHeights.add(obj); ingo@2811: } ingo@2811: finally { ingo@2811: if (in != null) { ingo@2811: in.close(); ingo@2811: } ingo@2811: } ingo@2811: } ingo@2811: ingo@2811: ingo@2811: protected static String stripMetaLine(String line) { ingo@2811: String tmp = line.substring(1, line.length()); ingo@2811: ingo@2811: if (tmp.startsWith(" ")) { ingo@2811: return tmp.substring(1, tmp.length()); ingo@2811: } ingo@2811: else { ingo@2811: return tmp; ingo@2811: } ingo@2811: } ingo@2811: ingo@2811: tom@8559: protected void handleMetaLine(ImportBedHeight obj, String line) { ingo@2811: String meta = stripMetaLine(line); ingo@2811: ingo@2811: if (handleMetaYear(obj, meta)) { ingo@2811: return; ingo@2811: } ingo@2811: else if (handleMetaTimeInterval(obj, meta)) { ingo@2811: return; ingo@2811: } ingo@2811: else if (handleMetaComment(obj, meta)) { ingo@2811: return; ingo@2811: } ingo@2811: else if (handleMetaEvaluationBy(obj, meta)) { ingo@2811: return; ingo@2811: } ingo@2811: else if (handleMetaRange(obj, meta)) { ingo@2811: return; ingo@2811: } ingo@2811: else if (handleMetaType(obj, meta)) { ingo@2811: return; ingo@2811: } ingo@2811: else if (handleMetaLocationSystem(obj, meta)) { ingo@2811: return; ingo@2811: } ingo@2811: else if (handleMetaCurElevationModel(obj, meta)) { ingo@2811: return; ingo@2811: } ingo@2811: else if (handleMetaOldElevationModel(obj, meta)) { ingo@2811: return; ingo@2811: } ingo@2811: else { sascha@3662: log.warn("BHP: Meta line did not match any known type: " + line); ingo@2811: } ingo@2811: } ingo@2811: ingo@2811: tom@8559: protected boolean handleMetaYear(ImportBedHeight obj, String line) { ingo@2811: Matcher m = META_YEAR.matcher(line); ingo@2811: ingo@2811: if (m.matches()) { ingo@2811: String tmp = m.group(1); teichmann@5327: if (tmp.length() > 0) { teichmann@5327: obj.setYear(Integer.parseInt(tmp)); ingo@2811: } teichmann@5327: else { teichmann@5327: log.warn("BHP: No year given."); ingo@2811: } teichmann@5327: return true; ingo@2811: } ingo@2811: ingo@2811: return false; ingo@2811: } ingo@2811: ingo@2811: tom@8559: protected boolean handleMetaTimeInterval(ImportBedHeight obj, String line) { ingo@2811: Matcher m = META_TIMEINTERVAL.matcher(line); ingo@2811: ingo@2811: if (m.matches()) { ingo@2811: String lo = m.group(1); ingo@2811: String up = m.group(2); ingo@2811: ingo@2811: log.debug("Found time interval: " + lo + " - " + up); ingo@2811: ingo@2811: try { ingo@2811: int lower = Integer.valueOf(lo); ingo@2811: int upper = Integer.valueOf(up); ingo@2811: tom@7927: Date fromYear = DateUtil.getStartDateFromYear(lower); tom@7927: Date toYear = DateUtil.getEndDateFromYear(upper); ingo@2811: ingo@2811: obj.setTimeInterval(new ImportTimeInterval(fromYear, toYear)); ingo@2811: } ingo@2811: catch (NumberFormatException e) { tom@5489: log.warn("BHP: could not parse timeinterval", e); ingo@2811: } ingo@2811: ingo@2811: return true; ingo@2811: } ingo@2811: ingo@2811: return false; ingo@2811: } ingo@2811: ingo@2811: tom@8559: protected boolean handleMetaComment(ImportBedHeight obj, String line) { ingo@2811: Matcher m = META_COMMENTS.matcher(line); ingo@2811: ingo@2811: if (m.matches()) { ingo@2811: String tmp = m.group(1); ingo@2811: ingo@2811: obj.setDescription(tmp); ingo@2811: ingo@2811: return true; ingo@2811: } ingo@2811: ingo@2811: return false; ingo@2811: } ingo@2811: ingo@2811: ingo@2811: protected boolean handleMetaEvaluationBy( tom@8559: ImportBedHeight obj, ingo@2811: String line ingo@2811: ) { ingo@2811: Matcher m = META_EVALUATION_BY.matcher(line); ingo@2811: ingo@2811: if (m.matches()) { ingo@2811: String tmp = m.group(1); ingo@2811: tmp = tmp.replace(";", ""); ingo@2811: ingo@2811: obj.setEvaluationBy(tmp); ingo@2811: ingo@2811: return true; ingo@2811: } ingo@2811: ingo@2811: return false; ingo@2811: } ingo@2811: ingo@2811: tom@8559: protected boolean handleMetaRange(ImportBedHeight obj, String line) { ingo@2811: Matcher m = META_RANGE.matcher(line); ingo@2811: ingo@2811: if (m.matches() && m.groupCount() >= 2) { ingo@2811: String a = m.group(1).replace(";", ""); ingo@2811: String b = m.group(2).replace(";", ""); ingo@2811: ingo@2811: try { ingo@2811: BigDecimal lower = new BigDecimal(nf.parse(a).doubleValue()); ingo@2811: BigDecimal upper = new BigDecimal(nf.parse(b).doubleValue()); ingo@2811: ingo@2811: obj.setRange(new ImportRange(lower, upper)); ingo@2811: ingo@2811: return true; ingo@2811: } ingo@2811: catch (ParseException e) { tom@5489: log.warn("BHP: could not parse range", e); ingo@2811: } ingo@2811: } ingo@2811: ingo@2811: return false; ingo@2811: } ingo@2811: ingo@2811: tom@8559: protected boolean handleMetaType(ImportBedHeight obj, String line) { ingo@2811: Matcher m = META_TYPE.matcher(line); ingo@2811: ingo@2811: if (m.matches()) { tom@6235: String tmp = m.group(1).replace(";", "").trim(); ingo@2811: tom@5278: BedHeightType bht = BedHeightType.fetchBedHeightTypeForType( teichmann@7376: tmp, teichmann@7376: ImporterSession.getInstance().getDatabaseSession()); ingo@2811: teichmann@5273: if (bht != null) { teichmann@5273: obj.setType(new ImportBedHeightType(bht)); sascha@3798: return true; sascha@3798: } teichmann@5273: tom@5901: log.error("Unknown bed height type: '" + tmp + "'. File ignored."); ingo@2811: } ingo@2811: ingo@2811: return false; ingo@2811: } ingo@2811: ingo@2811: ingo@2811: protected boolean handleMetaLocationSystem( tom@8559: ImportBedHeight obj, ingo@2811: String line ingo@2811: ) { ingo@2811: Matcher m = META_LOCATION_SYSTEM.matcher(line); ingo@2811: ingo@2811: if (m.matches()) { ingo@2811: String tmp = m.group(1).replace(";", ""); ingo@2811: ingo@2811: obj.setLocationSystem(new ImportLocationSystem(tmp, tmp)); ingo@2811: ingo@2811: return true; ingo@2811: } ingo@2811: ingo@2811: return false; ingo@2811: } ingo@2811: ingo@2811: ingo@2811: protected boolean handleMetaCurElevationModel( tom@8559: ImportBedHeight obj, ingo@2811: String line ingo@2811: ) { ingo@2811: Matcher m = META_CUR_ELEVATION_SYSTEM.matcher(line); ingo@2811: ingo@2811: if (m.matches()) { ingo@2811: String name = m.group(1); ingo@2811: String num = m.group(2); ingo@2811: String unit = m.group(3); ingo@2811: ingo@2811: obj.setCurElevationModel(new ImportElevationModel( ingo@2811: name + " " + num, ingo@2811: new ImportUnit(unit) ingo@2811: )); ingo@2811: ingo@2811: return true; ingo@2811: } ingo@2811: ingo@2811: return false; ingo@2811: } ingo@2811: ingo@2811: ingo@2811: protected boolean handleMetaOldElevationModel( tom@8559: ImportBedHeight obj, ingo@2811: String line ingo@2811: ) { ingo@2811: Matcher m = META_OLD_ELEVATION_SYSTEM.matcher(line); ingo@2811: ingo@2811: if (m.matches()) { ingo@2811: String name = m.group(1); ingo@2811: String num = m.group(2); ingo@2811: String unit = m.group(3); ingo@2811: ingo@2811: obj.setOldElevationModel(new ImportElevationModel( ingo@2811: name + " " + num, ingo@2811: new ImportUnit(unit) ingo@2811: )); ingo@2811: ingo@2811: return true; ingo@2811: } ingo@2811: ingo@2811: return false; ingo@2811: } tom@8557: tom@8559: protected void handleDataLine(ImportBedHeight obj, String line) { tom@8557: String[] values = line.split(SEPERATOR_CHAR, -1); tom@8557: tom@8557: if (values == null) { tom@8557: log.warn("BSP: Error while parsing data line: '" + line + "'"); tom@8557: return; tom@8557: } tom@8557: tom@8557: Double km; tom@8557: tom@8557: try { tom@8557: km = new Double(nf.parse(values[0]).doubleValue()); tom@8557: tom@8557: Double key = Double.valueOf(km); tom@8557: tom@8557: if (kmExists.contains(key)) { tom@8557: log.warn("duplicate station '" + km + "': -> ignored"); tom@8557: return; tom@8557: } tom@8557: tom@8557: kmExists.add(key); tom@8557: } tom@8557: catch (ParseException e) { tom@8557: // We expect a lot of ";;;;;;" lines. tom@8557: return; tom@8557: } tom@8557: tom@8557: // Handle gaps like "10,0;;;;;". tom@8557: if (values.length <= 2) { tom@8557: // Do not import line without useful data tom@8557: if (values.length < 2) { tom@8557: return; tom@8557: } tom@8557: if (values[1].length() == 0) { tom@8557: return; tom@8557: } tom@8557: } tom@8557: tom@8557: Double height = null; tom@8557: if (values[1].length() > 0) { tom@8557: try { tom@8557: height = new Double(nf.parse(values[1]).doubleValue()); tom@8557: } tom@8557: catch (ParseException e) { tom@8557: log.warn("BSP: unparseable height " + values[1]); tom@8557: } tom@8557: } tom@8557: tom@8557: Double uncertainty = null; tom@8557: if (values[2].length() > 0) { tom@8557: try { tom@8557: uncertainty = new Double(nf.parse(values[2]).doubleValue()); tom@8557: } tom@8557: catch (ParseException e) { tom@8557: log.warn("BSP: unparseable uncertainty value " + values[2]); tom@8557: } tom@8557: } tom@8557: tom@8557: Double dataGap = null; tom@8557: if (values[3].length() > 0) { tom@8557: try { tom@8557: dataGap = new Double(nf.parse(values[3]).doubleValue()); tom@8557: } tom@8557: catch (ParseException e) { tom@8557: log.warn("BSP: unparseable data gap " + values[3]); tom@8557: } tom@8557: } tom@8557: tom@8557: Double soundingWidth = null; tom@8557: if (values[4].length() > 0) { tom@8557: try { tom@8557: soundingWidth = new Double(nf.parse(values[4]).doubleValue()); tom@8557: } tom@8557: catch (ParseException e) { tom@8557: log.warn("BSP: unparseable sounding width " + values[4]); tom@8557: } tom@8557: } tom@8557: tom@8559: ImportBedHeightValue value = new ImportBedHeightValue( tom@8559: (ImportBedHeight) obj, tom@8557: km, tom@8557: height, tom@8557: uncertainty, tom@8557: dataGap, tom@8557: soundingWidth); tom@8557: tom@8557: obj.addValue(value); tom@8557: } ingo@2811: } ingo@2811: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :