You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 4 Next »

/* ================================================================
* Delft FEWS
* ================================================================
*
* Project Info: http://www.wldelft.nl/soft/fews/index.html
* Project Lead: Karel Heynert (karel.heynert@wldelft.nl)
*
* (C) Copyright 2003, by WL | Delft Hydraulics
* P.O. Box 177
* 2600 MH Delft
* The Netherlands
* http://www.wldelft.nl
*
* DELFT-FEWS is a sophisticated collection of modules designed
* for building a FEWS customised to the specific requirements
* of individual agencies. An open modelling approach allows users
* to add their own modules in an efficient way.
*
* ----------------------------------------------------------------
* TimeSeriesContentHandler.java
* ----------------------------------------------------------------
* (C) Copyright 2003, by WL | Delft Hydraulics
*
* Original Author: Onno van den Akker
*/
package nl.wldelft.util.timeseries;

import nl.wldelft.util.ExternalFloatsReference;
import nl.wldelft.util.Missings;
import nl.wldelft.util.Period;
import nl.wldelft.util.Properties;
import nl.wldelft.util.Season;
import nl.wldelft.util.coverage.Geometry;
import nl.wldelft.util.geodatum.GeoDatum;
import nl.wldelft.util.ratingcurve.RatingCurveEquation;
import nl.wldelft.util.ratingcurve.RatingCurveInterpolationMethod;

import java.text.SimpleDateFormat;
import java.util.TimeZone;

/**
* The interface <code>TimeSeriesContentHandler</code> represents the classes
* to handle the time series data that are supplied by the time series 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();

void clearMissingValues();

/**
* 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 alphanumeric 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 ultimate 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 ensemble 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 OPTIMISATION 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()}
*
* @param time Represents the number of milliseconds since January 1, 1970, 00:00:00 GMT
* @param minTime Represents the number of milliseconds since January 1, 1970, 00:00:00 GMT
* @param maxTime Represents the number of milliseconds since January 1, 1970, 00:00:00 GMT
*/
void setTimeAndRange(long time, long startTime, long endTime);

/**
* Changes the time that will be used when calling {@link #applyCurrentFields()}
*
* @param timeZone
* @param year eg 1996
* @param oneBasedMonth 1 .. 12 (1==January)
* @param dayOfMonth 1 .. 31
* @param hourInDay 0 .. 23
* @param minute 0 .. 59
* @param second 0 .. 59
* @param millis 0 .. 999
*/
void setTime(TimeZone timeZone, int year, int oneBasedMonth, int dayOfMonth, int hourInDay, int minute, int second, int millis);


/**
* 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()}
* <p>
* 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
* @param startDateTime leading and trailing spaces are ignored
* @param endDateTime leading and trailing spaces are ignored
*/
void setTimeAndRange(TimeZone timeZone, String pattern, String dateTime, String startDateTime, String endDateTime);

/**
* 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();

/**
* Return tue if the selected time series {@link #setTimeSeriesHeader} is alphanumeric
*/
boolean isCurrentTimeSeriesAlphanumeric();

/**
* Return tue if the selected time series {@link #setTimeSeriesHeader} is of TimeSeriesType temporary
*/
boolean isCurrentTimeSeriesTemporary();

/**
* 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 flag that will be used for when calling {@link #applyCurrentFields()}
*/
void setFlag(Flag flag);


/**
* Changes the flag source that will be used for when calling {@link #applyCurrentFields()}
* When a flag is marked as manual the flag will be fixed until the value is changed
* An automatic flag can be changed on automatic revalidation (rate of change)
*/
void setFlagSource(String flag);

/**
* Clear all flag source columns.
*/
void clearFlagSourceColumns();

/**
* Adds a new flag source column
* The returned index should be used for {@link #setColumnFlagSource(int, String)}
*/
int addFlagSourceColumn(String flagSourceColumnId);

/**
* Set the flag source for the specified flag source column
* Use {@link #addFlagSourceColumn(String)} for the columnIndex
*/
void setColumnFlagSource(int columnIndex, String flagSource);

/**
* Changes the sample id that will be used for when calling {@link #applyCurrentFields()}
*/
void setSampleId(String sampleId);

void setModifierName(String modifierName);

/**
* Changes the out of detection range that will be used when calling {@link #applyCurrentFields()}
*/
void setOutOfDetectionRangeFlag(OutOfDetectionRangeFlag flag);

/**
* Changes the {@link State} that will be used when calling {@link #applyCurrentFields()}
*/
void setState(State state);

/**
* Changes the comment that will be used when calling {@link #applyCurrentFields()}
*/
void setComment(String comment);

/**
* Changes the user that will be used when calling {@link #applyCurrentFields()}
*/
void setUser(String user);

/**
* Changes the properties that will be used when calling {@link #applyCurrentFields()}
* The properties are used as extra tags, like comments, that is stored per value
*/
void setProperties(Properties properties);

/**
* When a overruling geometry is defined (in grids.xml) this geometry will overturn the geometry set with {@link #setGeometry(Geometry)}
* When there is a overruling 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 divides the integers by 5 afterwards the value resolution is 0.2
*
* @param valueResolution
*/
void setValueResolution(float valueResolution);

/**
* Changes the domain axes value resolutions 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 divides the integers by 5 afterwards the value resolution is 0.2
*
* @param valueResolutions
*/
void setDomainAxesValueResolutions(float... valueResolutions);

/**
* 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 is missing the minValue and maxValue should also be missing (and visa versa)
*/
void setValueAndRange(float value, float minValue, float maxValue);

/**
* Changes the value that will be used when calling {@link #applyCurrentFields()}
* When the value can not be parsed an error will be logged, no exception 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);

/**
* Changes the value that will be used when calling {@link #applyCurrentFields()}
* When the value can not be parsed an error will be logged, no exception is thrown
* Add missing value tags before calling this function {@link #addMissingValue(String)}
* e.g. addMissingValue('?')
* When the value is missing the minValue and maxValue should also be missing (and visa versa)
*
* @param value leading and trailing spaces are ignored
*/
void setValueAndRange(char decimalSeparator, String value, String minValue, String maxValue);

/**
* Puts the domain axes values. For a spectrum these are the frequencies. For directional spectrum the first domain axis is the frequency and the second domain axis is the direction.
* The domain axis index is zero based.
* 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
* When all values (e.g. all time steps) share the same domain axis values only call this method once
*
* @see #setValues
*/
void setDomainAxesValues(float[]... domainAxesValues);

/**
* Puts the values for the specified domains. eg. For a spectrum these are the energy values for all the frequency bands
* The number of values should equal the domain0.length * domain1.length * domain2.length etc {@link #setDomainAxesValues(float[]...)}
* The index of one value when having two domains is domain1Index + domain0Index * domain1.length.
* When having two domains the first domain axis represent the rows and the second domain axis represent the columns
* The size of each domain axis may change every time step
* For performance reasons do not parse the values when {@link #isCurrentTimeSeriesHeaderForCurrentTimeRejected()} returns true
* For performance reasons do not call when the domain axes values are not changes. Most of the time all time steps share the same domain values
* @see #setDomainAxesValues(float[]...)
*/
void setValues(float[] values);

/**
* Puts the string values for the specified domains. Equivalent of the function {@link #setValues(float[] values)}
* When one or more values can not be parsed an error will be logged, no exception is thrown
* Add missing value tags before calling this function {@link #addMissingValue(String)}
* e.g. addMissingValue('?')
*
* @param values leading and trailing spaces are ignored
*/
void setValues(char decimalSeparator, String[] values);

/**
* 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);

void setCoverageValues(ExternalFloatsReference externalFloatsReference, float minValue, float maxValue, Missings missings);

void setRatingCurveStageValues(float[] values);

void setRatingCurveDischargeValues(float[] values);

void setRatingCurveMinStageValue(float min);

void setRatingCurveMaxStageValue(float max);

void setRatingCurveInterpolationMethod(RatingCurveInterpolationMethod interpolationMethod);

void setRatingCurveLogScaleStraightLineStageOffsets(float[] values);

/**
* Sets the rating curve table flags for each row, null is allowed
*/
void setRatingCurveFlags(int[] flags);

default void addRatingCurveEquation(RatingCurveEquation equation) {

}

void setRatingCurveSeason(Season season);

void setRatingCurvePeriod(Period period);

/**
* When value is marked manual it can not be overwritten with an value that is marked automatic
*/
void setValueSource(ValueSource flag);

/**
* 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 call to {@link #applyCurrentFields()}
*/
void applyCurrentFields();

default void setImportState(String importState) {
// noop.
}

default String getImportState() {
return null;
}

default void rejectSample() {}
}
  • No labels