/*
* -----------------------------------------------------------------------
* Copyright © 2013-2016 Meno Hochschild, <http://www.menodata.de/>
* -----------------------------------------------------------------------
* This file (ElementRule.java) is part of project Time4J.
*
* Time4J is free software: You can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* Time4J is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Time4J. If not, see <http://www.gnu.org/licenses/>.
* -----------------------------------------------------------------------
*/
package net.time4j.engine;
/**
* <p>Represents the rule of a chronological element how to calculate or
* to manipulate its context-dependent temporal value. </p>
*
* <p>Element rules will be searched by Time4J according to following
* criteria: </p>
*
* <ol><li>An element rule will be registered in the {@code Chronology}
* together with its associated chronological element. For each chronology
* and each element instance there is exactly one rule instance. In most
* cases it is an inner class of the temporal type in question. </li>
* <li>If there is no registered rule for an element in a given chronology
* then Time4J checks if the associated element is a {@code BasicElement}
* and if the element supports the chronology. If yes then its internal
* rule will be evaluated. </li>
* <li>If the search did not yield any result then a
* {@link RuleNotFoundException} will be thrown. </li></ol>
*
* @param <T> generic type of time context compatible to {@code ChronoEntity}
* @param <V> generic type of elment value
* @author Meno Hochschild
* @see Chronology.Builder#appendElement(ChronoElement,ElementRule)
* @see BasicElement#derive(Chronology)
* @doctags.spec All implementations must be immutable.
*/
/*[deutsch]
* <p>Repräsentiert die Regel eines chronologischen Elements, indem
* ein zeitkontextabhängiger Wert berechnet oder gesetzt wird. </p>
*
* <p>Elementregeln werden von Time4J nach folgenden Kriterien zu einem
* gegebenen chronologischen Element gesucht, wenn ein {@code ChronoEntity}
* als chronologischer Typ vorliegt: </p>
*
* <ol><li>Eine Elementregel wird in der {@code Chronology} zusammen
* mit dem assoziierten chronologischen Element registriert. Pro Chronologie
* und pro Elementinstanz wird genau eine Regelinstanz registriert. Meist
* handelt es sich um eine innere Klasse eines Zeitpunkttyps. </li>
* <li>Gibt es zu einem Element keine registrierte Regel in der
* fraglichen Chronologie, dann wird geprüft, ob ein chronologisches
* Element des Typs {@code BasicElement} vorliegt und ob das Element
* die Chronologie unterstützt. Wenn ja, wird dessen interne Regel
* ausgewertet. Passt die Regel vom chronologischen Typ her, dann wird
* sie verwendet. </li>
* <li>Wenn die Suche letztlich nichts ergeben hat, wird eine
* {@link RuleNotFoundException} geworfen. </li></ol>
*
* @param <T> generic type of time context compatible to {@code ChronoEntity}
* @param <V> generic type of elment value
* @author Meno Hochschild
* @see Chronology.Builder#appendElement(ChronoElement,ElementRule)
* @see BasicElement#derive(Chronology)
* @doctags.spec All implementations must be immutable.
*/
public interface ElementRule<T, V> {
//~ Methoden ------------------------------------------------------
/**
* <p>Yields the current value of associated element in given
* chronological context. </p>
*
* <p>Will be called by {@link ChronoEntity#get(ChronoElement)}. </p>
*
* <p>If the element associated with this rule is a primary element
* which directly represents a part of the state of an entity then any
* implementation will request the value directly from the state,
* otherwise derive from context using a specific logic. The term
* <i>primary</i> refers to if the context itself stores the value. </p>
*
* @param context time context to be evaluated
* @return current element value as object (never {@code null})
* @throws ChronoException if the associated element value cannot be evaluated
*/
/*[deutsch]
* <p>Ermittelt den aktuellen Wert des assoziierten Elements
* im angegebenen Zeitwertkontext. </p>
*
* <p>Wird von {@link ChronoEntity#get(ChronoElement)} aufgerufen. </p>
*
* <p>Ist das mit dieser Regel assoziierte Element ein primäres
* Element, also ein Teil des Zustands einer Entität, dann wird
* eine Implementierung den Wert direkt vom entsprechenden Zustandsfeld
* im Kontext anfordern, sonst selbst nach eigener Logik aus dem Kontext
* ableiten. Der Begriff <i>primär</i> bezieht sich darauf, ob der
* Kontext selbst den Wert speichert. </p>
*
* @param context time context to be evaluated
* @return current element value as object (never {@code null})
* @throws ChronoException if the associated element value cannot be evaluated
*/
V getValue(T context);
/**
* <p>Yields the minimum value suitable for given chronological
* context. </p>
*
* <p>Will be called by {@link ChronoEntity#getMinimum(ChronoElement)}. </p>
*
* <p><strong>ATTENTION:</strong> Defining a minimum and maximum does
* not imply a continuum between minimum and maximum without any gaps,
* see for example summer time switches or hebrew leap months. Furthermore,
* a chronologically ascending order cannot be guaranteed. </p>
*
* @param context time context to be evaluated
* @return minimum legal and sometimes context-dependent value
* @throws ChronoException if the associated minimum value cannot be evaluated
* @see #getMaximum(Object) getMaximum(T)
*/
/*[deutsch]
* <p>Ermittelt den minimal zulässigen Wert passend zum angegebenen
* Zeitwertkontext. </p>
*
* <p>Wird von {@link ChronoEntity#getMinimum(ChronoElement)}
* aufgerufen. </p>
*
* <p><strong>VORSICHT:</strong> Mit der Definition eines Minimums und
* eines Maximums ist noch kein lückenloses Kontinuum zwischen
* Minimum und Maximum garantiert, siehe z.B. Sommerzeit-Umstellungen
* oder hebräische Schaltmonate. Auch ist nicht immer eine
* chronologisch aufsteigende Ordnung garantiert. </p>
*
* @param context time context to be evaluated
* @return minimum legal and sometimes context-dependent value
* @throws ChronoException if the associated minimum value cannot be evaluated
* @see #getMaximum(Object) getMaximum(T)
*/
V getMinimum(T context);
/**
* <p>Yields the maximum value suitable for given chronological
* context. </p>
*
* <p>Will be called by {@link ChronoEntity#getMaximum(ChronoElement)}. </p>
*
* <p><strong>ATTENTION:</strong> Defining a minimum and maximum does
* not imply a continuum between minimum and maximum without any gaps,
* see for example summer time switches or hebrew leap months. Furthermore,
* a chronologically ascending order cannot be guaranteed. </p>
*
* @param context time context to be evaluated
* @return maximum legal and sometimes context-dependent value
* @throws ChronoException if the associated maximum value cannot be evaluated
* @see #getMinimum(Object) getMinimum(T)
*/
/*[deutsch]
* <p>Ermittelt den maximal zulässigen Wert passend zum angegebenen
* Zeitwertkontext. </p>
*
* <p>Wird von {@link ChronoEntity#getMaximum(ChronoElement)}
* aufgerufen. </p>
*
* <p><strong>VORSICHT:</strong> Mit der Definition eines Minimums und
* eines Maximums ist noch kein lückenloses Kontinuum zwischen
* Minimum und Maximum garantiert, siehe z.B. Sommerzeit-Umstellungen
* oder hebräische Schaltmonate. Auch ist nicht immer eine
* chronologisch aufsteigende Ordnung garantiert. </p>
*
* @param context time context to be evaluated
* @return maximum legal and sometimes context-dependent value
* @throws ChronoException if the associated maximum value cannot be evaluated
* @see #getMinimum(Object) getMinimum(T)
*/
V getMaximum(T context);
/**
* <p>Queries if given value is valid for the element associated with this
* rule in given context. </p>
*
* <p>Will be called by {@link ChronoEntity#isValid(ChronoElement, Object)
* ChronoEntity.isValid(ChronoElement, V)}. A numerical overflow causing
* an {@code ArithmeticException} will usually not be checked. </p>
*
* @param context time context to be evaluated
* @param value candidate value to be validated (optional)
* @return {@code true} if valid else {@code false}
*/
/*[deutsch]
* <p>Ist der angegebene Wert zum mit dieser Regel assoziierten
* Element im angegebenen Kontext gültig? </p>
*
* <p>Wird von {@link ChronoEntity#isValid(ChronoElement, Object)
* ChronoEntity.isValid(ChronoElement, V)} aufgerufen. Eine numerische
* Überlaufsituation im Hinblick auf eine {@code ArithmeticException}
* wird in der Regel nicht geprüft. </p>
*
* @param context time context to be evaluated
* @param value candidate value to be validated (optional)
* @return {@code true} if valid else {@code false}
*/
boolean isValid(
T context,
V value
);
/**
* <p>Determines the new value of the associated element in given
* chronological context and yields the result. </p>
*
* <p>Will be called by {@link ChronoEntity#with(ChronoElement, Object)
* ChronoEntity.with(ChronoElement, V)}. The third parameter is in most
* cases only relevant if the value type is no enum type but for example
* an integer type. The lenient mode causes the tolerant interpretation
* of invalid values like 31st of April as 1st of May. This mode is only
* active if an element is either explicitly declared as lenient or if
* the method {@code StdOperator.setLenient()} is used. </p>
*
* @param context time context to be evaluated
* @param value new element value (optional)
* @param lenient leniency mode
* @return changed copy of context which itself remains unaffected
* @throws IllegalArgumentException if given value is out of range or
* not valid dependent on the given time context
* @throws ArithmeticException in case of numerical overflow
* @see #isValid(Object, Object) isValid(T, V)
* @see StdOperator#setLenient(Object, ChronoElement)
* @see ChronoElement#isLenient()
* @see net.time4j.ProportionalElement#setLenient(Number)
*/
/*[deutsch]
* <p>Bestimmt den neuen Wert des assoziierten Elements im
* angegebenen Zeitwertkontext und liefert das Ergebnis. </p>
*
* <p>Wird von {@link ChronoEntity#with(ChronoElement, Object)
* ChronoEntity.with(ChronoElement, V)} aufgerufen. Der dritte
* Parameter spielt meist nur eine Rolle, wenn der Werttyp kein Enum
* ist, sondern z.B. ein Integer. Dieser Nachsichtigkeitsmodus
* führt dazu, daß eigentlich ungültige Werte
* wie der 31. April als 1. Mai interpretiert werden. Aktiv ist
* dieser Modus nur bei Verwendung der einen Operator liefernden
* Methode {@code StdOperator.setLenient()} oder wenn das
* Element ausdrücklich als nachsichtig deklariert wird. </p>
*
* @param context time context to be evaluated
* @param value new element value (optional)
* @param lenient leniency mode
* @return changed copy of context which itself remains unaffected
* @throws IllegalArgumentException if given value is out of range or
* not valid dependent on the given time context
* @throws ArithmeticException in case of numerical overflow
* @see #isValid(Object, Object) isValid(T, V)
* @see StdOperator#setLenient(Object, ChronoElement)
* @see ChronoElement#isLenient()
* @see net.time4j.ProportionalElement#setLenient(Number)
*/
T withValue(
T context,
V value,
boolean lenient
);
/**
* <p>Yields the child element whose value is to be set to the minimum
* value. </p>
*
* <p>The access to this method only happens indirectly in the class
* {@code StdOperator}. </p>
*
* @param context time context to be evaluated
* @return child element or {@code null} if not available
* @see StdOperator#atFloor(ChronoElement)
*/
/*[deutsch]
* <p>Ermittelt das Kindselement, dessen Wert auf seinen unteren Randwert
* gesetzt wird. </p>
*
* <p>Der Zugriff erfolgt nur über die Klasse {@code StdOperator}. </p>
*
* @param context time context to be evaluated
* @return child element or {@code null} if not available
* @see StdOperator#atFloor(ChronoElement)
*/
ChronoElement<?> getChildAtFloor(T context);
/**
* <p>Yields the child element whose value is to be set to the maximum
* value. </p>
*
* <p>The access to this method only happens indirectly in the class
* {@code StdOperator}. </p>
*
* @param context time context to be evaluated
* @return child element or {@code null} if not available
* @see StdOperator#atCeiling(ChronoElement)
*/
/*[deutsch]
* <p>Ermittelt das Kindselement, dessen Wert auf seinen oberen Randwert
* gesetzt wird. </p>
*
* <p>Der Zugriff erfolgt nur über die Klasse {@code StdOperator}. </p>
*
* @param context time context to be evaluated
* @return child element or {@code null} if not available
* @see StdOperator#atCeiling(ChronoElement)
*/
ChronoElement<?> getChildAtCeiling(T context);
}