net.time4j.engine.StdOperator Maven / Gradle / Ivy
/*
* -----------------------------------------------------------------------
* Copyright © 2013-2015 Meno Hochschild,
* -----------------------------------------------------------------------
* This file (StdOperator.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 .
* -----------------------------------------------------------------------
*/
package net.time4j.engine;
/**
* Factory for producing standard chronological operators which are applicable
* on most chronological entities.
*
* @param generic target type of operator
* @author Meno Hochschild
* @since 3.5/4.3
*/
/*[deutsch]
* Standard-Operator, der auf die meisten chronologischen Entitäten anwendbar ist.
*
* @param generic target type of operator
* @author Meno Hochschild
* @since 3.5/4.3
*/
public final class StdOperator>
implements ChronoOperator {
//~ Statische Felder/Initialisierungen --------------------------------
private static final int NEW_VALUE_MODE = 0;
private static final int MIN_MODE = 1;
private static final int MAX_MODE = 2;
private static final int FLOOR_MODE = 3;
private static final int CEILING_MODE = 4;
private static final int LENIENT_MODE = 5;
private static final int DECREMENTING_MODE = 6;
private static final int INCREMENTING_MODE = 7;
//~ Instanzvariablen ----------------------------------------------
private final int mode;
private final ChronoElement> element;
private final Object value;
//~ Konstruktoren -------------------------------------------------
private StdOperator(
int mode,
ChronoElement> element
) {
this(mode, element, null);
}
private StdOperator(
int mode,
ChronoElement> element,
Object value // optional
) {
super();
if (element == null) {
throw new NullPointerException("Missing chronological element.");
}
this.mode = mode;
this.element = element;
this.value = value;
}
//~ Methoden ------------------------------------------------------
@Override
public T apply(T entity) {
switch (this.mode) {
case NEW_VALUE_MODE:
return value(entity, this.element, this.value, false);
case MIN_MODE:
return min(entity, this.element);
case MAX_MODE:
return max(entity, this.element);
case FLOOR_MODE:
return floor(entity, this.element);
case CEILING_MODE:
return ceiling(entity, this.element);
case LENIENT_MODE:
return value(entity, this.element, this.value, true);
case DECREMENTING_MODE:
return this.move(entity, false);
case INCREMENTING_MODE:
return this.move(entity, true);
default:
throw new UnsupportedOperationException("Unknown mode: " + this.mode);
}
}
/**
* Yields a new operator which can set any entity to its minimum
* element value.
*
* @param generic type of target entity
* @param element associated chronological element
* @return operator
* @since 3.5/4.3
*/
/*[deutsch]
* Liefert einen Operator, der eine beliebige Entität auf
* das Elementminimum setzt.
*
* @param generic type of target entity
* @param element associated chronological element
* @return operator
* @since 3.5/4.3
*/
public static > ChronoOperator minimized(ChronoElement> element) {
return new StdOperator(MIN_MODE, element);
}
/**
* Yields a new operator which can set any entity to its maximum
* element value.
*
* @param generic type of target entity
* @param element associated chronological element
* @return operator
* @since 3.5/4.3
*/
/*[deutsch]
* Liefert einen Operator, der eine beliebige Entität auf
* das Elementmaximum setzt.
*
* @param generic type of target entity
* @param element associated chronological element
* @return operator
* @since 3.5/4.3
*/
public static > ChronoOperator maximized(ChronoElement> element) {
return new StdOperator(MAX_MODE, element);
}
/**
* Yields a new operator which can set any entity such that its
* actual element value gets the decremented value.
*
* @param generic type of target entity
* @param element associated chronological element
* @return operator
* @see TimeAxis#getBaseUnit(ChronoElement)
* @since 3.5/4.3
*/
/*[deutsch]
* Liefert einen Operator, der eine beliebige Entität so
* anpasst, daß dieses Element den vorherigen Wert bekommt.
*
* @param generic type of target entity
* @param element associated chronological element
* @return operator
* @see TimeAxis#getBaseUnit(ChronoElement)
* @since 3.5/4.3
*/
public static > ChronoOperator decremented(ChronoElement> element) {
return new StdOperator(DECREMENTING_MODE, element);
}
/**
* Yields a new operator which can set any entity such that its
* actual element value gets the incremented value.
*
* @param generic type of target entity
* @param element associated chronological element
* @return operator
* @see TimeAxis#getBaseUnit(ChronoElement)
* @since 3.5/4.3
*/
/*[deutsch]
* Liefert einen Operator, der eine beliebige Entität so
* anpasst, daß dieses Element den nächsten Wert bekommt.
*
* @param generic type of target entity
* @param element associated chronological element
* @return operator
* @see TimeAxis#getBaseUnit(ChronoElement)
* @since 3.5/4.3
*/
public static > ChronoOperator incremented(ChronoElement> element) {
return new StdOperator(INCREMENTING_MODE, element);
}
/**
* Yields an operator which rounds any entity down so that the child
* elements will be set to the minimum.
*
* @param generic type of target entity
* @param element associated chronological element
* @return operator
* @since 3.5/4.3
*/
/*[deutsch]
* Liefert einen Operator, der eine Entität abrundet, indem alle
* Kindselemente dieses Elements auf ihr Minimum gesetzt werden.
*
* @param generic type of target entity
* @param element associated chronological element
* @return operator
* @since 3.5/4.3
*/
public static > ChronoOperator atFloor(ChronoElement> element) {
return new StdOperator(FLOOR_MODE, element);
}
/**
* Yields an operator which rounds any entity up so that the child
* elements will be set to the maximum.
*
* @param generic type of target entity
* @param element associated chronological element
* @return operator
* @since 3.5/4.3
*/
/*[deutsch]
* Liefert einen Operator, der eine Entität aufrundet, indem alle
* Kindselemente dieses Elements auf ihr Maximum gesetzt werden.
*
* @param generic type of target entity
* @param element associated chronological element
* @return operator
* @since 3.5/4.3
*/
public static > ChronoOperator atCeiling(ChronoElement> element) {
return new StdOperator(CEILING_MODE, element);
}
/**
* Yields an operator which sets any entity such that its actual
* element value will be set in lenient mode to given value.
*
* @param generic type of target entity
* @param generic element value type
* @param value new element value
* @param element associated chronological element
* @return operator
* @since 3.5/4.3
*/
/*[deutsch]
* Liefert einen Operator, der eine beliebige Entität so
* anpasst, daß dieses Element auf den angegebenen Wert im
* Nachsichtigkeitsmodus gesetzt wird.
*
* @param generic type of target entity
* @param generic element value type
* @param value new element value
* @param element associated chronological element
* @return operator
* @since 3.5/4.3
*/
public static , V> ChronoOperator setLenient(
V value,
ChronoElement element
) {
return new StdOperator(LENIENT_MODE, element, value);
}
/**
* Yields an operator which sets any entity such that its actual
* element value will be set in normal mode to given value.
*
* @param generic type of target entity
* @param generic element value type
* @param value new element value
* @param element associated chronological element
* @return operator
* @since 3.5/4.3
*/
/*[deutsch]
* Liefert einen Operator, der eine beliebige Entität so
* anpasst, daß dieses Element auf den angegebenen Wert im
* Standardmodus gesetzt wird.
*
* @param generic type of target entity
* @param generic element value type
* @param value new element value
* @param element associated chronological element
* @return operator
* @since 3.5/4.3
*/
public static , V> ChronoOperator newValue(
V value,
ChronoElement element
) {
return new StdOperator(NEW_VALUE_MODE, element, value);
}
private T min(
ChronoEntity entity,
ChronoElement element
) {
return entity.with(element, entity.getMinimum(element));
}
private T max(
ChronoEntity entity,
ChronoElement element
) {
return entity.with(element, entity.getMaximum(element));
}
private T floor(
ChronoEntity entity,
ChronoElement element
) {
T ctx = entity.getContext();
ChronoElement> e = element;
while ((e = ctx.getChronology().getRule(e).getChildAtFloor(ctx)) != null) {
ctx = withFloor(ctx, e);
}
return ctx;
}
private T ceiling(
ChronoEntity entity,
ChronoElement element
) {
T ctx = entity.getContext();
ChronoElement> e = element;
while ((e = ctx.getChronology().getRule(e).getChildAtCeiling(ctx)) != null) {
ctx = withCeiling(ctx, e);
}
return ctx;
}
private T value(
ChronoEntity entity,
ChronoElement element,
Object value,
boolean lenient
) {
T ctx = entity.getContext();
return ctx.getChronology().getRule(element).withValue(
ctx,
element.getType().cast(value),
lenient
);
}
private T withFloor(
T context,
ChronoElement element
) {
ElementRule rule = context.getChronology().getRule(element);
return rule.withValue(
context,
rule.getMinimum(context),
element.isLenient()
);
}
private T withCeiling(
T context,
ChronoElement element
) {
ElementRule rule = context.getChronology().getRule(element);
return rule.withValue(
context,
rule.getMaximum(context),
element.isLenient()
);
}
private T move(
T entity,
boolean forward
) {
if (entity instanceof TimePoint) {
TimePoint, ?> tp = TimePoint.class.cast(entity);
Object answer = add(tp, this.element, forward);
return entity.getChronology().getChronoType().cast(answer);
} else {
throw new ChronoException(
"Base units not supported by: "
+ entity.getChronology().getChronoType());
}
}
// wildcard capture
private static > T add(
TimePoint context,
ChronoElement> element,
boolean forward
) {
U unit = context.getChronology().getBaseUnit(element);
if (forward) {
return context.plus(1, unit);
} else {
return context.minus(1, unit);
}
}
}