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;
import java.util.ArrayList;
import java.util.List;
/**
 * TimeSeries reader for MetOffice WW3 Timeseries
 * <p>
 * A detailed description can be found in JIRA issue FEWS-11699
 *<pre>
 * Met Office WAVEWATCH III wave model hindcast data
 * Location:  52.876 N   0.334 E
 * YYYY MM DD HH MN    Wsm   Wdir
 * 2003 12 01 00 00   4.83 103.17
 * 2003 12 01 01 00   5.10 101.31
 * 2003 12 01 02 00   4.84  97.12
 * 2003 12 01 03 00   4.47 100.30
 * 2003 12 01 04 00   4.34  97.94
 *
 *  Current assumption are:
 *  Location is always specified in North and East coordinates.
 *  Parameters are always Wsm (windspeed) and Wdir (winddirection) specified in this order.
 *  Time notation is always: YYYY MM DD HH MN
 *
 *
 *</pre>
 */
public class MetOfficeWW3TimeSeriesParser implements TextParser<TimeSeriesContentHandler> {
    private LineReader reader = null;
    private TimeSeriesContentHandler contentHandler = null;
    private final static char COLUMN_SEPARATOR_CHAR = ' ';
    private final static int PARAM_COLUMN_INDEX = 5;
    @Override
    public void parse(LineReader reader, String virtualFileName, TimeSeriesContentHandler contentHandler) throws IOException {
        this.contentHandler = contentHandler;
        this.reader = reader;
        // First line is descriptive. We can skip it.
        reader.readLine();
        //Second line contains the location in lat long notation separated by spaces.
        String[] locationIdsLine = reader.readLine(COLUMN_SEPARATOR_CHAR);
        if (locationIdsLine == null || locationIdsLine.length != 5) {
            throw new IOException("Locations are not specified correctly\n" + reader.getFileAndLineNumber());
        }
        // Location:  52.876 N   0.334 E
        GeoDatum geoDate = contentHandler.getDefaultGeoDatum();
        double y = TextUtils.tryParseDouble(locationIdsLine[1], Double.NaN);
        if (Double.isNaN(y)) throw new IOException("Number expected for y coordinate;" + locationIdsLine[1]);
        double x = TextUtils.tryParseDouble(locationIdsLine[3], Double.NaN);
        if (Double.isNaN(x)) throw new IOException("Number expected for x coordinate;" + locationIdsLine[3]);
        PointGeometry location = new PointGeometry(geoDate.createXYZ(x, y, 0d));

        String[] dateFormatAndParams = reader.readLine(COLUMN_SEPARATOR_CHAR);
        List<DefaultTimeSeriesHeader> headerList = new ArrayList();
        // first 5 entries are date format. The rest are parameters
        int numberOfParams = dateFormatAndParams.length - PARAM_COLUMN_INDEX;
        for (int i = 0; i < numberOfParams; i++) {
            DefaultTimeSeriesHeader header = new DefaultTimeSeriesHeader();
            header.setGeometry(location);
            header.setParameterId(dateFormatAndParams[PARAM_COLUMN_INDEX + i]);
            contentHandler.createTimeSeriesHeaderAlias(i, header);
            headerList.add(header);
        }
        parseValues(headerList);
    }
    private void parseValues(List<DefaultTimeSeriesHeader>headers) throws IOException {
        char decimalSeparator = '.';
        for (String[] buffer = new String[5 + headers.size()]; this.reader.readLine(COLUMN_SEPARATOR_CHAR, buffer) != -1;) {
                // YYYY MM DD HH MN
                // 2003 12 01 00 00 4.83 103.17
                int paramIndex = 0;
                for (DefaultTimeSeriesHeader header: headers) {
                    String value = buffer[PARAM_COLUMN_INDEX + paramIndex];
                    this.contentHandler.setTimeSeriesHeader(header);
                    //noinspection StringConcatenationMissingWhitespace
                    this.contentHandler.setTime(this.contentHandler.getDefaultTimeZone(), "yyyyMMddHHmm", buffer[0] + buffer[1] + buffer[2] + buffer[3] + buffer[4]);
                    this.contentHandler.setValue(decimalSeparator, value);
                    this.contentHandler.applyCurrentFields();
                    paramIndex++;
                }
        }
    }
}
  • No labels