001/*
002 *  Copyright 2001-2005 Stephen Colebourne
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.joda.time.field;
017
018import org.joda.time.Chronology;
019import org.joda.time.DateTimeField;
020import org.joda.time.DateTimeFieldType;
021import org.joda.time.IllegalFieldValueException;
022
023/**
024 * Wraps another field such that a certain value is skipped.
025 * <p>
026 * This is most useful for years where you want to skip zero, so the
027 * sequence runs ...,2,1,-1,-2,...
028 * <p>
029 * SkipDateTimeField is thread-safe and immutable.
030 *
031 * @author Brian S O'Neill
032 * @author Stephen Colebourne
033 * @since 1.0
034 */
035public final class SkipDateTimeField extends DelegatedDateTimeField {
036
037    /** Serialization version. */
038    private static final long serialVersionUID = -8869148464118507846L;
039
040    /** The chronology to wrap. */
041    private final Chronology iChronology;
042    /** The value to skip. */
043    private final int iSkip;
044    /** The calculated minimum value. */
045    private transient int iMinValue;
046
047    /**
048     * Constructor that skips zero.
049     * 
050     * @param chronology  the chronoogy to use
051     * @param field  the field to skip zero on
052     */
053    public SkipDateTimeField(Chronology chronology, DateTimeField field) {
054        this(chronology, field, 0);
055    }
056
057    /**
058     * Constructor.
059     * 
060     * @param chronology  the chronoogy to use
061     * @param field  the field to skip zero on
062     * @param skip  the value to skip
063     */
064    public SkipDateTimeField(Chronology chronology, DateTimeField field, int skip) {
065        super(field);
066        iChronology = chronology;
067        int min = super.getMinimumValue();
068        if (min < skip) {
069            iMinValue = min - 1;
070        } else if (min == skip) {
071            iMinValue = skip + 1;
072        } else {
073            iMinValue = min;
074        }
075        iSkip = skip;
076    }
077
078    //-----------------------------------------------------------------------
079    public int get(long millis) {
080        int value = super.get(millis);
081        if (value <= iSkip) {
082            value--;
083        }
084        return value;
085    }
086
087    public long set(long millis, int value) {
088        FieldUtils.verifyValueBounds(this, value, iMinValue, getMaximumValue());
089        if (value <= iSkip) {
090            if (value == iSkip) {
091                throw new IllegalFieldValueException
092                    (DateTimeFieldType.year(), Integer.valueOf(value), null, null);
093            }
094            value++;
095        }
096        return super.set(millis, value);
097    }
098
099    public int getMinimumValue() {
100        return iMinValue;
101    }
102
103    private Object readResolve() {
104        return getType().getField(iChronology);
105    }
106
107}