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);
}
}