/* * ----------------------------------------------------------------------- * Copyright © 2013-2015 Meno Hochschild, <http://www.menodata.de/> * ----------------------------------------------------------------------- * This file (NavigationOperator.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; import net.time4j.engine.ChronoElement; import net.time4j.engine.ChronoEntity; import net.time4j.engine.ChronoException; import net.time4j.engine.ChronoOperator; /** * <p>Spezialoperator zum Navigieren zu bestimmten Elementwerten. </p> * * @param <V> generic enum type of element values * @author Meno Hochschild * @concurrency <immutable> */ final class NavigationOperator<V extends Enum<V>> extends ElementOperator<PlainDate> { //~ Instanzvariablen -------------------------------------------------- private final V value; private final int len; private final ChronoOperator<PlainTimestamp> navTS; //~ Konstruktoren ----------------------------------------------------- /** * <p>Konstruiert eine neue Instanz. </p> * * @param element reference element * @param mode navigation mode * @param value target value of navigation */ NavigationOperator( ChronoElement<V> element, int mode, V value ) { super(element, mode); if (value == null) { throw new NullPointerException("Missing value."); } this.value = value; this.len = element.getType().getEnumConstants().length; this.navTS = this::doApply; } //~ Methoden ---------------------------------------------------------- @Override public PlainDate apply(PlainDate entity) { return this.doApply(entity); } @Override ChronoOperator<PlainTimestamp> onTimestamp() { return this.navTS; } private <T extends ChronoEntity<T>> T doApply(T entity) { if (entity.contains(PlainDate.CALENDAR_DATE)) { PlainDate date = entity.get(PlainDate.CALENDAR_DATE); Object enumValue = date.get(this.getElement()); int oldOrdinal = Enum.class.cast(enumValue).ordinal(); int newOrdinal = this.delta(oldOrdinal); if (newOrdinal == oldOrdinal) { return entity; } else { return entity.with( PlainDate.CALENDAR_DATE, date.plus( (newOrdinal - oldOrdinal), date.getChronology().getBaseUnit(this.getElement())) ); } } String navigation; switch (this.getType()) { case OP_NAV_NEXT: navigation = "setToNext"; break; case OP_NAV_PREVIOUS: navigation = "setToPrevious"; break; case OP_NAV_NEXT_OR_SAME: navigation = "setToNextOrSame"; break; case OP_NAV_PREVIOUS_OR_SAME: navigation = "setToPreviousOrSame"; break; default: throw new AssertionError("Unknown: " + this.getType()); } throw new ChronoException( navigation + "()-operation not supported on: " + this.getElement().name()); } private int delta(int oldOrdinal) { int newOrdinal = this.value.ordinal(); switch (this.getType()) { case OP_NAV_NEXT: if (newOrdinal <= oldOrdinal) { newOrdinal += this.len; } break; case OP_NAV_PREVIOUS: if (newOrdinal >= oldOrdinal) { newOrdinal -= this.len; } break; case OP_NAV_NEXT_OR_SAME: if (newOrdinal < oldOrdinal) { newOrdinal += this.len; } break; case OP_NAV_PREVIOUS_OR_SAME: if (newOrdinal > oldOrdinal) { newOrdinal -= this.len; } break; default: throw new AssertionError("Unknown: " + this.getType()); } return newOrdinal; } }