package nl.wldelft.util.timeseries; import nl.wldelft.util.Period; import nl.wldelft.util.coverage.Geometry; import nl.wldelft.util.coverage.NonGeoReferencedGridGeometry; import nl.wldelft.util.geodatum.GeoDatum; import java.util.TimeZone; import java.text.SimpleDateFormat; /** * The interface <code>TimeSeriesContentHandler</code> represents the classes * to handle the timeseries data that are supplied by the timeseries parsers. */ public interface TimeSeriesContentHandler { /** * Defines time zone which should be used while importing time series. * If time zone is defined in the file format - this TimeZone should not be used. * @return */ TimeZone getDefaultTimeZone(); /** * Adds a value that should be recognized as missing when calling {@link #setValue(float)}, {@link #setValue(char, String)} or {@link #setCoverageValues(float[])} * {@link Float#NaN} is always recognized as missing */ void addMissingValue(float missingValue); /** * Adds a alpha numeric tag that should be recognized as missing when calling {@link #setValue(char, String)} * These alphanemeric missings are not recognized when using {@link #setValue(float)} or {@link #setCoverageValues(float[])} * The missings added with {@link #addMissingValue(float)} and {@link #addMissingValueRange(float, float)} are also recognized * {@link Float#NaN} is always recognized as missing * */ void addMissingValue(String missingValue); /** * Adds a range of values that should be recognized as missing when calling {@link #setValue} or {@link #setCoverageValues(float[])} * NaN, null and an empty string, string with only spaces are always recognized as missing */ void addMissingValueRange(float minMissingValue, float maxMissingValue); /** * Creating an alias allows high speed switching between different headers * E.g. For files with multiple parameters per row, for every row multiple switches are required between different headers * This will not work properly without defining an alias for every column * The alias is ultimate fast in the range form 0 to 1000 * * @param alias, integer for ultimata speed, good practice is to use the parameter column index. * @param header */ void createTimeSeriesHeaderAlias(int alias, TimeSeriesHeader header); /** * Changes the header that will be used when calling {@link #applyCurrentFields()} * A call to this method will not consume any significant time * {@link #setTimeSeriesHeader(TimeSeriesHeader)} is relatively time consuming * @see #createTimeSeriesHeaderAlias(int, TimeSeriesHeader) * @param alias defined with {@link #createTimeSeriesHeaderAlias (int, TimeSeriesHeader)} * @throws IllegalArgumentException when alias is not created before */ void setTimeSeriesHeader(int alias); /** * Same as {@link #setTimeSeriesHeader(int)} , but slightly SLOWER * The second time this method is called for the SAME header, * there is NO new time series created but the first one is re-selected * This method is relatively time consuming. * When parsing multiple parameters per row use {@link #setTimeSeriesHeader (int)} */ void setTimeSeriesHeader(TimeSeriesHeader header); /** * Changes the time that will be used when calling {@link #applyCurrentFields()} * A NEW time series is created, with a new forecast time and new ensemble member index * A warning is logged when this method is called twice for the same header (historical non ensemlbe time series) */ void setNewTimeSeriesHeader(TimeSeriesHeader header); /** * The parser should call this method when it starts parsing time/values and has any idea of the period of the values that will come. * This information is only used by this content handler for OPTIMALISATION and * is never required and never results in an error when the real period is differs from the estimated period * @param period */ void setEstimatedPeriod(Period period); /** * Changes the time that will be used when calling {@link #applyCurrentFields()} * * @param time Represents the number of milliseconds since January 1, 1970, 00:00:00 GMT */ void setTime(long time); /** * Changes the time that will be used when calling {@link #applyCurrentFields()} * * In addition to simple date format 24h will be recognized as 0h the next day * * @param timeZone. When not known use {@link #getDefaultTimeZone()} * @param pattern see {@link SimpleDateFormat}, in addition for HH 24 will be recognized as 0:00 the next day * @param dateTime leading and trailing spaces are ignored */ void setTime(TimeZone timeZone, String pattern, String dateTime); /** * Changes the time that will be used when calling {@link #applyCurrentFields()} * * In addition to simple date format 24h will be recognized as 0h the next day * * @param timeZone. When not known use {@link #getDefaultTimeZone()} * @param datePattern see {@link SimpleDateFormat} * @param date leading and trailing spaces are ignored * @param timePattern see {@link SimpleDateFormat}, in addition for HH 24 will be recognized as 0:00 the next day * @param time leading and trailing spaces are ignored */ void setTime(TimeZone timeZone, String datePattern, String date, String timePattern, String time); /** * Return false if any value for the selected time series with {@link #setTimeSeriesHeader} is wanted * When true parsing of ALL values for this time series can be skipped */ boolean isCurrentTimeSeriesHeaderForAllTimesRejected(); /** * Return false if the value selected time {@link #setTimeSeriesHeader} and selected time {@link #setTime(long)} is wanted * When true parsing of the time and time series can be skipped */ boolean isCurrentTimeSeriesHeaderForCurrentTimeRejected(); /** * Changes the flag that will be used for when calling {@link #applyCurrentFields()} */ void setFlag(int flag); /** * Changes the flag that will be used for when calling {@link #applyCurrentFields()} */ void setFlag(String flag); /** * Changes the sample id that will be used for when calling {@link #applyCurrentFields()} */ void setSampleId(String sampleId); /** * Changes the out of detection range that will be used when calling {@link #applyCurrentFields()} */ void setOutOfDetectionRangeFlag(OutOfDetectionRangeFlag flag); /** * Changes the comment that will be used when calling {@link #applyCurrentFields()} */ void setComment(String comment); /** * When a overrullilng geometry is defined (in grids.xml) this geometry will overturn the geometry set with {@link #setGeometry(Geometry)} * When there is a overrullilng geometry the content handler will log an error when the number of rows and cols is not the same a set with {@link #setGeometry(Geometry)} * @return */ Geometry getOverrulingGeometry(); /** * Used by the parser to create a geometry when there is no geometry info available in the file */ GeoDatum getDefaultGeoDatum(); /** * Changes the geometry that will be used when calling {@link #applyCurrentFields()} * * When only the number of rows and cols are available use {@link NonGeoReferencedGridGeometry#create(int, int))))| * @see #getDefaultGeoDatum() */ void setGeometry(Geometry geometry); /** * Changes the value resolution that will be used when calling {@link #applyCurrentFields()} * Only be used when the file format don't uses IEEE floats to store the values * e.g. When there are only integers parsed the value resolution is 1.0 * e.g. When there at maximum to decimals the value resolution is 0.01; * e.g. When file format store the values as integers and devides the integers by 5 afterwards the value resolution is 0.2 * * @param valueResolution */ void setValueResolution(float valueResolution); /** * Changes the value that will be used when calling {@link #applyCurrentFields()} */ void setValue(float value); /** * Changes the value that will be used when calling {@link #applyCurrentFields()} * When the value can not be parsed an error will be logged, no excepton is thrown * Add missing value tags before calling this function {@link #addMissingValue(String)} * e.g. addMissingValue('?') * * @param value leading and trailing spaces are ignored */ void setValue(char decimalSeparator, String value); /** * Puts the coverage values for the last set time and and last set header with the last set flag and last set geometry * When {@link #getOverrulingGeometry ()} returns not null there is no need to to set the geometry * When the active geometry does not have the same number of rows and cols an error message is logged. * For performance reasons do not parse the values when {@link #isCurrentTimeSeriesHeaderForCurrentTimeRejected()} returns true * For performance reasons do no recreate the values array for every time step again */ void setCoverageValues(float[] values); /** * Saves the current fields for the current time series header and current time. * The current fields are not cleared so it is only required * to update the changed fields for the next calll to {@link #applyCurrentFields()} */ void applyCurrentFields(); }