package nl.wldelft.fews.system.plugin.dataImport; import nl.wldelft.util.IOUtils; import nl.wldelft.util.TextUtils; import nl.wldelft.util.io.LineReader; import nl.wldelft.util.io.TextParser; import nl.wldelft.util.timeseries.DefaultTimeSeriesHeader; import nl.wldelft.util.timeseries.TimeSeriesContentHandler; import org.apache.log4j.Logger; import java.io.IOException; public class MswTimeSeriesParser implements TextParser<TimeSeriesContentHandler> { private static final Logger log = Logger.getLogger(MswTimeSeriesParser.class); private LineReader reader = null; private String virtualFileName = null; private TimeSeriesContentHandler contentHandler = null; private String fileUnit = null; private DefaultTimeSeriesHeader header = new DefaultTimeSeriesHeader(); @Override public void parse(LineReader reader, String virtualFileName, TimeSeriesContentHandler contentHandler) throws Exception { this.contentHandler = contentHandler; this.virtualFileName = virtualFileName; contentHandler.addMissingValue("-999"); this.reader = reader; this.reader.setCommentLinePrefix('#'); parseHeader(); if (contentHandler.isCurrentTimeSeriesHeaderForAllTimesRejected()) return; parseData(); } /** * Read exactly 6 header-lines and extract: * from line 2: location Id * from line 3: parameter Id */ private void parseHeader() throws Exception { String[] headerLines = IOUtils.readLines(reader, 6); if (headerLines.length < 6) { throw new Exception("Import.Error: Header of the file " + this.virtualFileName + " has unknown format."); } header.setLocationId(TextUtils.rightFrom(headerLines[1], '=')); header.setParameterId(TextUtils.rightFrom(headerLines[2], '=')); contentHandler.setTimeSeriesHeader(header); } /** * Reads the file and put read data to the TimeSeriesContentHandler * @return true if at least 1 line is read, otherwise false * @throws IOException if any unexpected error occur while reading the file */ private void parseData() throws Exception { //Read first data line String[] firstLine = this.reader.readLine(';'); if (firstLine == null ){ throw new Exception("File contains no lines with data: "+this.virtualFileName); } //Get the unit from the first data line if (firstLine.length < 4) { throw new Exception("File contains no unit specification : " + this.virtualFileName); } TextUtils.trimElements(firstLine); this.fileUnit = firstLine[3]; //Put unit to the header and ask if this header is wanted (i.e. are data from this file wanted ?) header.setUnit(this.fileUnit); this.contentHandler.setNewTimeSeriesHeader(header); if (this.contentHandler.isCurrentTimeSeriesHeaderForAllTimesRejected()) return; //Parse other data from this data line and put them to the timeseries handler parseDataLine(firstLine); //Read remaining lines, parse the data and put them to the timeseries handler for (String[] line; (line = this.reader.readLine(';')) != null;) { TextUtils.trimElements(line); parseDataLine(line); } } /** * Parse from each line the following data: * from column 1: date * from column 2: time * from column 4: unit * from column 5: flag * from column 6: value * * Unit must be the same in all records, i.e. equal to this.fileUnit that is read from the first data record. */ private void parseDataLine(String[] line) throws IOException { //Check whether the line contains the obligatory 6 columns if (line.length != 6) { log.warn("Import.Error: Line contains less than 6 columns at line "+ reader.getLineNumber()); return; } contentHandler.setTime(contentHandler.getDefaultTimeZone(), "yyyy/MM/dd", line[0], "HH:mm", line[1]); if (contentHandler.isCurrentTimeSeriesHeaderForCurrentTimeRejected()) return; //Check unit (only if the unit already read) if (!line[3].equals(this.fileUnit)) { log.warn("Import.Error: Line contains an unexpected unit at line " + reader.getLineNumber() + ", "+this.fileUnit+ " wil be used."); } this.contentHandler.setFlag(line[4]); this.contentHandler.setValue('.', line[5]); this.contentHandler.applyCurrentFields(); } }