package nl.wldelft.timeseriesparsers;

import nl.wldelft.util.TextUtils;
import nl.wldelft.util.coverage.PointGeometry;
import nl.wldelft.util.geodatum.GeoDatum;
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 java.io.IOException;
/**
 * TimeSeries reader for CS3xTidalSurge
 *
 * <p>
 * A detailed description can be found in JIRA issue FEWS-9719
 *<pre>
 *
 * The format starts with a parameter, internal location (not used by FEWS) and lat long values.
 * Following the param and location description, one or more lines containing the values will follows.
 * Every line of contains 14 columns. The first 12 columns contain values measured in increasing intervals of 1 hour.
 * Column 13 + 14 contains the time in DDMMYYY HH format.
 *
 * This pattern can be repeated for different parameters and locations.
 *
 * Example:
 *
 * Parameter Z: CS3 Location ( 79, 87) Lat 53.389 Lon  1.083
 * -0.12 -0.13 -0.14 -0.13 -0.13 -0.12 -0.10 -0.11 -0.10 -0.11 -0.08 -0.06 01012003 00
 * -0.05 -0.03 -0.02 -0.02  0.01  0.04  0.07  0.08  0.08  0.08  0.13  0.18 01012003 12
 *
 *</pre>
 */
public class CS3xTidalSurgeTimeSeriesParser implements TextParser<TimeSeriesContentHandler> {
    private TimeSeriesContentHandler contentHandler = null;
    private final static char COLUMN_SEPARATOR_CHAR = ' ';
    @Override
    public void parse(LineReader reader, String virtualFileName, TimeSeriesContentHandler contentHandler) throws IOException {
        this.contentHandler = contentHandler;
        char decimalSeparator = '.';
        while (true) {
            String[] buffer = reader.readLine(COLUMN_SEPARATOR_CHAR);
            if (buffer == null) {
                break;
            }
            if ("Parameter".equals(buffer[0])) {
                parseHeader(reader, contentHandler, buffer);
            } else {
                parseValues(reader, decimalSeparator, buffer);
            }
        }
    }
    private void parseValues(LineReader reader, char decimalSeparator, String[] buffer) throws IOException {
        //parse values for current header.
        // for values we expect exactly 12 columns
        if (buffer.length != 14) {
            throw new IOException("Value rows should contain 14 columns.\n" + reader.getFileAndLineNumber() + ' ' + buffer.length);
        }
        int hourBase = Integer.parseInt(buffer[13]);
        for (int i = 0; i < 12; i++) {
            //noinspection StringConcatenationMissingWhitespace
            this.contentHandler.setTime(this.contentHandler.getDefaultTimeZone(), "ddMMyyyyHH", buffer[12] + (hourBase + i));
            this.contentHandler.setValue(decimalSeparator, buffer[i]);
            this.contentHandler.applyCurrentFields();
        }
    }
    private void parseHeader(LineReader reader, TimeSeriesContentHandler contentHandler, String[] buffer) throws IOException {
        String parameter = TextUtils.leftFrom(buffer[1], ':');
        int i = 2;
        while (!"Lat".equals(buffer[i]) && i < buffer.length) {
            i++;
        }
        // next index is the latitude value
        i++;
        if (i >= buffer.length) {
            throw new IOException("Latitude not specified correctly for parameter\n" + reader.getFileAndLineNumber());
        }
        String latitude = buffer[i];
        i++;
        while (!"Lon".equals(buffer[i]) && i < buffer.length) {
            i++;
        }
        // next index is the longitued value
        i++;
        if (i >= buffer.length) {
            throw new IOException("Longitude not specified correctly for parameter\n" + reader.getFileAndLineNumber());
        }
        String longitude = buffer[i];
        GeoDatum geoDate = contentHandler.getDefaultGeoDatum();
        double x = TextUtils.tryParseDouble(longitude, Double.NaN);
        if (Double.isNaN(x)) throw new IOException("Number expected for y coordinate;" + longitude);
        double y = TextUtils.tryParseDouble(latitude, Double.NaN);
        if (Double.isNaN(y)) throw new IOException("Number expected for x coordinate;" + latitude);
        PointGeometry location = new PointGeometry(geoDate.createXYZ(x, y, 0d));
        // create a new header for this location and parameter.
        DefaultTimeSeriesHeader header = new DefaultTimeSeriesHeader();
        header.setGeometry(location);
        header.setParameterId(parameter);
        this.contentHandler.setTimeSeriesHeader(header);
    }
}
  • No labels