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     */
016    package org.joda.time.field;
017    
018    import org.joda.time.Chronology;
019    import org.joda.time.DateTimeField;
020    import org.joda.time.DateTimeFieldType;
021    import 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     */
035    public 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    }