Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

/* ================================================================
* 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() {}
}