Versions Compared

Key

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


Code Block
/* ================================================================

...


 * 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

...

 {
    /**

...

    void clearMissingValues();

...


     * 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[])}

...

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

...

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

    /**
     * Reject the last sample id set {@link #setSampleId(String)} The changes to the current sample are not saved.
     */
    void rejectSample();

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

    /**
     * This optional method flushes the time series to the storage and when successful writes a new  savePointInfoText. With the {@link #getLastSavePointInfoText()} the parser knows where to continue. The savePointInfo text can be any text that is usually only interpretable by a specific parser.
     */
    void createSavePoint(String savePointInfoText);

...


     *  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 true if the selected time series {@link #setTimeSeriesHeader} is alphanumeric
     */
    boolean isCurrentTimeSeriesAlphanumeric();

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

    /**
     * Reject the last sample id set {@link #setSampleId(String)} The changes to the current sample are not saved.
     */
    void rejectSample();

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

    /**
     * This optional method flushes the time series to the storage and when successful writes a new  savePointInfoText. With the {@link #getLastSavePointInfoText()} the parser knows where to continue. The savePointInfo text can be any text that is usually only interpretable by a specific parser.
     */
    void createSavePoint(String savePointInfoText);

    /**
     * Returns the last save point text so the parser knows where to continue
     */
    String getLastSavePointInfoText();
}