/* * FEWS Menyanthes serializer * * (c) HKV lijn in water */ package nl.wldelft.timeseriesserializers; import nl.wldelft.util.Properties; import nl.wldelft.util.SystemUtils; import nl.wldelft.util.TextUtils; import nl.wldelft.util.TimeZoneUtils; import nl.wldelft.util.coverage.Geometry; import nl.wldelft.util.io.LineWriter; import nl.wldelft.util.io.TextSerializer; import nl.wldelft.util.timeseries.TimeSeriesContent; import nl.wldelft.util.timeseries.TimeSeriesHeader; import org.apache.log4j.Logger; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; /** * Export * @author ansink */ public class MenyanthesTimeSeriesSerializer implements TextSerializer { private static final Logger log = Logger.getLogger(MenyanthesTimeSeriesSerializer.class); public static final String LOCATION_ATTRIBUTE_MAAIVELD_NAP = "LOCATION_ATTRIBUTE_MAAIVELD_NAP"; public static final String LOCATION_ATTRIBUTE_MEETPUNT_NAP = "LOCATION_ATTRIBUTE_MEETPUNT_NAP"; public static final String LOCATION_ATTRIBUTE_BOVENKANT_FILTER = "LOCATION_ATTRIBUTE_BOVENKANT_FILTER"; public static final String LOCATION_ATTRIBUTE_ONDERKANT_FILTER = "LOCATION_ATTRIBUTE_ONDERKANT_FILTER"; private boolean missingAttributeWarningGiven = false; private LineWriter writer = null; private TimeSeriesContent content = null; private char decimalSeparator = '.'; private char lineSeparator = ','; // editable for unit test private long now = System.currentTimeMillis(); private String userName = TextUtils.left(SystemUtils.USER_NAME, 30); private static final String DATE_FORMAT_NOW = "yyyy/MM/dd"; private static final String[] REEKS_LINE = { "LOCATIE", "FILTERNUMMER", "EXTERNE AANDUIDING", "X COORDINAAT", "Y COORDINAAT", "MAAIVELD NAP", "GESCHAT", "MEETPUNT NAP", "BOVENKANT FILTER", "ONDERKANT FILTER", "START DATUM", "EINDE DATUM"}; private static final String[] EVENTS_LINE = { "LOCATIE", "FILTERNUMMER", "PEIL DATUM TIJD", "STAND (NAP)", "BIJZONDERHEID"}; @Override public void serialize(TimeSeriesContent content, LineWriter writer, String virtualFileName) throws Exception { this.content = content; this.writer = writer; content.setUnreliablesAsMissings(true); writeHeader(); writeReeksen(); writeEvents(); } /** * Schrijf header * @throws java.io.IOException */ private void writeHeader() throws IOException { SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT_NOW); sdf.setTimeZone(TimeZoneUtils.GMT); writer.writeLine("TITEL: FEWS Menyanthes Export"); writer.writeLine("GEBRUIKERSNAAM: " + userName); writer.writeLine("PERIODE: " + sdf.format(content.getContentPeriod().getStartDate()) + "-" + sdf.format(content.getContentPeriod().getEndDate())); writer.writeLine("DATUM:" + now("yyyy/MM/dd HH:mm:ss")); writer.writeLine("REFERENTIE: NAP"); writer.newLine(); } /** * Haal systeem tijd * @param dateFormat * @return */ public String now(String dateFormat) { SimpleDateFormat sdf = new SimpleDateFormat(dateFormat); sdf.setTimeZone(TimeZoneUtils.GMT); return sdf.format(new Date(now)); } /** * Schrijf lijst met * @throws java.io.IOException kopgegevens van de verschillende reeksen */ private void writeReeksen() throws IOException { writer.writeLine(REEKS_LINE, lineSeparator); SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT_NOW); sdf.setTimeZone(TimeZoneUtils.GMT); String[] line = new String[12]; for (int i = 0, n = content.getTimeSeriesCount(); i < n; i++) { content.setTimeSeriesIndex(i); TimeSeriesHeader header = content.getTimeSeriesHeader(); Properties attributes = header.getAttributes(); Geometry geometry = header.getGeometry(); // Locatie line[0] = header.getLocationId(); // Filternummer Qualifiers can be entered or not. If not then enter default 1 line[1] = header.getQualifierCount() >= 1 ? header.getQualifierId(0) : "1"; // Externe aanduiding line[2] = "n/a"; // X Coordinaat line[3] = geometry == null ? "0" : Double.toString(geometry.getX(0)); // Y Coordinaat line[4] = geometry == null ? "0" : Double.toString(geometry.getY(0)); // Maaiveld NAP line[5] = getMaaiveldNap(header, attributes, geometry); // Geschat line[6] = ""; // Meetpunt NAP double meetPuntNap = getDoubleAttribute(header, attributes, LOCATION_ATTRIBUTE_MEETPUNT_NAP); line[7] = Double.isNaN(meetPuntNap) ? "" : String.valueOf(meetPuntNap); // Bovenkant filter double bovenkantFilter = getDoubleAttribute(header, attributes, LOCATION_ATTRIBUTE_BOVENKANT_FILTER); line[8] = Double.isNaN(bovenkantFilter) ? "" : String.valueOf(bovenkantFilter); // Onderkant filter double onderkantFilter = getDoubleAttribute(header, attributes, LOCATION_ATTRIBUTE_ONDERKANT_FILTER); line[9] = Double.isNaN(onderkantFilter) ? "" : String.valueOf(onderkantFilter); // Start datum line[10] = sdf.format(content.getContentPeriod().getStartDate()); // Eind datum line[11] = sdf.format(content.getContentPeriod().getEndDate()); writer.writeLine(line, lineSeparator); } writer.newLine(); } private String getMaaiveldNap(TimeSeriesHeader header, Properties attributes, Geometry geometry) { double maaiveldNapDouble = getDoubleAttribute(header, attributes, LOCATION_ATTRIBUTE_MAAIVELD_NAP); return String.valueOf(Double.isNaN(maaiveldNapDouble) ? geometry == null || Double.isNaN(geometry.getZ(0)) ? "0" : String.valueOf(geometry.getZ(0)) : maaiveldNapDouble); } private double getDoubleAttribute(TimeSeriesHeader header, Properties attributes, String locationAttribute) { if (attributes == null) return Double.NaN; int attributeIndex = attributes.indexOf(locationAttribute); if (attributeIndex == -1) return Double.NaN; double aDouble = attributes.getDouble(attributeIndex); if (!Double.isNaN(aDouble)) return aDouble; if (!missingAttributeWarningGiven) { missingAttributeWarningGiven = true; log.warn("Export.Warn: Location attribute: " + locationAttribute + " defined for Menyanthes export but not found for location: " + header.getLocationId() + ". This warning is only given once, see debug for other attributes, locations and time steps"); } else { if (log.isDebugEnabled()) log.debug("Location attribute: " + locationAttribute + " defined for Menyanthes export but not found for location: " + header.getLocationId()); } return Double.NaN; } /** * Write events * @throws java.io.IOException */ private void writeEvents() throws IOException { writer.writeLine(EVENTS_LINE, lineSeparator); //Loop over all timesteps and over all series, pick the level series String[] line = new String[5]; for (int i = 0, n = content.getTimeSeriesCount(); i < n; i++) { content.setTimeSeriesIndex(i); TimeSeriesHeader header = content.getTimeSeriesHeader(); for (int j = 0, m = content.getContentTimeCount(); j < m; j++) { content.setContentTimeIndex(j); if (!content.isTimeAvailable()) { continue; } line[0] = header.getLocationId(); //Qualifiers can be entered or not. If not then enter default 1 line[1] = header.getQualifierCount() >= 1 ? header.getQualifierId(0) : "1"; line[2] = content.getTime(content.getDefaultTimeZone(), "yyyy/MM/dd HH:mm:ss"); line[3] = content.getValue(decimalSeparator); line[4] = content.getStringFlag(); writer.writeLine(line, lineSeparator); } } } /** * Editable for unit tests */ public void setNow(long now) { this.now = now; } /** * Editable for unit tests */ public void setUserName(String userName) { this.userName = userName; } }