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;
017
018import java.io.Serializable;
019
020/**
021 * Identifies a duration field, such as years or minutes, in a chronology-neutral way.
022 * <p>
023 * A duration field type defines the type of the field, such as hours.
024 * If does not directly enable any calculations, however it does provide a
025 * {@link #getField(Chronology)} method that returns the actual calculation engine
026 * for a particular chronology.
027 * <p>
028 * Instances of <code>DurationFieldType</code> are singletons.
029 * They can be compared using <code>==</code>.
030 * <p>
031 * If required, you can create your own field, for example a quarters.
032 * You must create a subclass of <code>DurationFieldType</code> that defines the field type.
033 * This class returns the actual calculation engine from {@link #getField(Chronology)}.
034 *
035 * @author Stephen Colebourne
036 * @author Brian S O'Neill
037 * @since 1.0
038 */
039public abstract class DurationFieldType implements Serializable {
040
041    /** Serialization version */
042    private static final long serialVersionUID = 8765135187319L;
043
044    // Ordinals for standard field types.
045    static final byte
046        ERAS = 1,
047        CENTURIES = 2,
048        WEEKYEARS = 3,
049        YEARS = 4,
050        MONTHS = 5,
051        WEEKS = 6,
052        DAYS = 7,
053        HALFDAYS = 8,
054        HOURS = 9,
055        MINUTES = 10,
056        SECONDS = 11,
057        MILLIS = 12;
058
059    /** The eras field type. */
060    static final DurationFieldType ERAS_TYPE = new StandardDurationFieldType("eras", ERAS);
061    /** The centuries field type. */
062    static final DurationFieldType CENTURIES_TYPE = new StandardDurationFieldType("centuries", CENTURIES);
063    /** The weekyears field type. */
064    static final DurationFieldType WEEKYEARS_TYPE = new StandardDurationFieldType("weekyears", WEEKYEARS);
065    /** The years field type. */
066    static final DurationFieldType YEARS_TYPE = new StandardDurationFieldType("years", YEARS);
067    /** The months field type. */
068    static final DurationFieldType MONTHS_TYPE = new StandardDurationFieldType("months", MONTHS);
069    /** The weeks field type. */
070    static final DurationFieldType WEEKS_TYPE = new StandardDurationFieldType("weeks", WEEKS);
071    /** The days field type. */
072    static final DurationFieldType DAYS_TYPE = new StandardDurationFieldType("days", DAYS);
073    /** The halfdays field type. */
074    static final DurationFieldType HALFDAYS_TYPE = new StandardDurationFieldType("halfdays", HALFDAYS);
075    /** The hours field type. */
076    static final DurationFieldType HOURS_TYPE = new StandardDurationFieldType("hours", HOURS);
077    /** The minutes field type. */
078    static final DurationFieldType MINUTES_TYPE = new StandardDurationFieldType("minutes", MINUTES);
079    /** The seconds field type. */
080    static final DurationFieldType SECONDS_TYPE = new StandardDurationFieldType("seconds", SECONDS);
081    /** The millis field type. */
082    static final DurationFieldType MILLIS_TYPE = new StandardDurationFieldType("millis", MILLIS);
083
084    /** The name of the field type. */
085    private final String iName;
086
087    //-----------------------------------------------------------------------
088    /**
089     * Constructor.
090     * 
091     * @param name  the name to use, which by convention, are plural.
092     */
093    protected DurationFieldType(String name) {
094        super();
095        iName = name;
096    }
097
098    //-----------------------------------------------------------------------
099    /**
100     * Get the millis field type.
101     * 
102     * @return the DateTimeFieldType constant
103     */
104    public static DurationFieldType millis() {
105        return MILLIS_TYPE;
106    }
107
108    /**
109     * Get the seconds field type.
110     * 
111     * @return the DateTimeFieldType constant
112     */
113    public static DurationFieldType seconds() {
114        return SECONDS_TYPE;
115    }
116
117    /**
118     * Get the minutes field type.
119     * 
120     * @return the DateTimeFieldType constant
121     */
122    public static DurationFieldType minutes() {
123        return MINUTES_TYPE;
124    }
125
126    /**
127     * Get the hours field type.
128     * 
129     * @return the DateTimeFieldType constant
130     */
131    public static DurationFieldType hours() {
132        return HOURS_TYPE;
133    }
134
135    /**
136     * Get the halfdays field type.
137     * 
138     * @return the DateTimeFieldType constant
139     */
140    public static DurationFieldType halfdays() {
141        return HALFDAYS_TYPE;
142    }
143
144    //-----------------------------------------------------------------------
145    /**
146     * Get the days field type.
147     * 
148     * @return the DateTimeFieldType constant
149     */
150    public static DurationFieldType days() {
151        return DAYS_TYPE;
152    }
153
154    /**
155     * Get the weeks field type.
156     * 
157     * @return the DateTimeFieldType constant
158     */
159    public static DurationFieldType weeks() {
160        return WEEKS_TYPE;
161    }
162
163    /**
164     * Get the weekyears field type.
165     * 
166     * @return the DateTimeFieldType constant
167     */
168    public static DurationFieldType weekyears() {
169        return WEEKYEARS_TYPE;
170    }
171
172    /**
173     * Get the months field type.
174     * 
175     * @return the DateTimeFieldType constant
176     */
177    public static DurationFieldType months() {
178        return MONTHS_TYPE;
179    }
180
181    /**
182     * Get the years field type.
183     * 
184     * @return the DateTimeFieldType constant
185     */
186    public static DurationFieldType years() {
187        return YEARS_TYPE;
188    }
189
190    /**
191     * Get the centuries field type.
192     * 
193     * @return the DateTimeFieldType constant
194     */
195    public static DurationFieldType centuries() {
196        return CENTURIES_TYPE;
197    }
198
199    /**
200     * Get the eras field type.
201     * 
202     * @return the DateTimeFieldType constant
203     */
204    public static DurationFieldType eras() {
205        return ERAS_TYPE;
206    }
207
208    //-----------------------------------------------------------------------
209    /**
210     * Get the name of the field.
211     * By convention, names are plural.
212     * 
213     * @return field name
214     */
215    public String getName() {
216        return iName;
217    }
218
219    /**
220     * Gets a suitable field for this type from the given Chronology.
221     *
222     * @param chronology  the chronology to use, null means ISOChronology in default zone
223     * @return a suitable field
224     */
225    public abstract DurationField getField(Chronology chronology);
226
227    /**
228     * Checks whether this field supported in the given Chronology.
229     *
230     * @param chronology  the chronology to use, null means ISOChronology in default zone
231     * @return true if supported
232     */
233    public boolean isSupported(Chronology chronology) {
234        return getField(chronology).isSupported();
235    }
236
237    /**
238     * Get a suitable debug string.
239     * 
240     * @return debug string
241     */
242    public String toString() {
243        return getName();
244    }
245
246    private static class StandardDurationFieldType extends DurationFieldType {
247        /** Serialization version */
248        private static final long serialVersionUID = 31156755687123L;
249
250        /** The ordinal of the standard field type, for switch statements */
251        private final byte iOrdinal;
252
253        /**
254         * Constructor.
255         * 
256         * @param name  the name to use
257         */
258        StandardDurationFieldType(String name, byte ordinal) {
259            super(name);
260            iOrdinal = ordinal;
261        }
262
263        /** @inheritdoc */
264        @Override
265        public boolean equals(Object obj) {
266            if (this == obj) {
267                return true;
268            }
269            if (obj instanceof StandardDurationFieldType) {
270                return iOrdinal == ((StandardDurationFieldType) obj).iOrdinal;
271            }
272            return false;
273        }
274
275        /** @inheritdoc */
276        @Override
277        public int hashCode() {
278            return (1 << iOrdinal);
279        }
280
281        public DurationField getField(Chronology chronology) {
282            chronology = DateTimeUtils.getChronology(chronology);
283            
284            switch (iOrdinal) {
285                case ERAS:
286                    return chronology.eras();
287                case CENTURIES:
288                    return chronology.centuries();
289                case WEEKYEARS:
290                    return chronology.weekyears();
291                case YEARS:
292                    return chronology.years();
293                case MONTHS:
294                    return chronology.months();
295                case WEEKS:
296                    return chronology.weeks();
297                case DAYS:
298                    return chronology.days();
299                case HALFDAYS:
300                    return chronology.halfdays();
301                case HOURS:
302                    return chronology.hours();
303                case MINUTES:
304                    return chronology.minutes();
305                case SECONDS:
306                    return chronology.seconds();
307                case MILLIS:
308                    return chronology.millis();
309                default:
310                    // Shouldn't happen.
311                    throw new InternalError();
312            }
313        }
314
315        /**
316         * Ensure a singleton is returned.
317         * 
318         * @return the singleton type
319         */
320        private Object readResolve() {
321            switch (iOrdinal) {
322                case ERAS:
323                    return ERAS_TYPE;
324                case CENTURIES:
325                    return CENTURIES_TYPE;
326                case WEEKYEARS:
327                    return WEEKYEARS_TYPE;
328                case YEARS:
329                    return YEARS_TYPE;
330                case MONTHS:
331                    return MONTHS_TYPE;
332                case WEEKS:
333                    return WEEKS_TYPE;
334                case DAYS:
335                    return DAYS_TYPE;
336                case HALFDAYS:
337                    return HALFDAYS_TYPE;
338                case HOURS:
339                    return HOURS_TYPE;
340                case MINUTES:
341                    return MINUTES_TYPE;
342                case SECONDS:
343                    return SECONDS_TYPE;
344                case MILLIS:
345                    return MILLIS_TYPE;
346                default:
347                    // Shouldn't happen.
348                    return this;
349            }
350        }
351    }
352}