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.chrono;
017    
018    import org.joda.time.Chronology;
019    import org.joda.time.DateTimeField;
020    import org.joda.time.DateTimeZone;
021    import org.joda.time.field.LenientDateTimeField;
022    
023    /**
024     * Wraps another Chronology, ensuring all the fields are lenient.
025     * <p>
026     * LenientChronology is thread-safe and immutable.
027     *
028     * @author Brian S O'Neill
029     * @since 1.0
030     * @see LenientDateTimeField
031     * @see StrictChronology
032     */
033    public final class LenientChronology extends AssembledChronology {
034    
035        /** Serialization lock */
036        private static final long serialVersionUID = -3148237568046877177L;
037    
038        /**
039         * Create a LenientChronology for any chronology.
040         *
041         * @param base the chronology to wrap
042         * @throws IllegalArgumentException if chronology is null
043         */
044        public static LenientChronology getInstance(Chronology base) {
045            if (base == null) {
046                throw new IllegalArgumentException("Must supply a chronology");
047            }
048            return new LenientChronology(base);
049        }
050    
051        private transient Chronology iWithUTC;
052    
053        /**
054         * Create a LenientChronology for any chronology.
055         *
056         * @param base the chronology to wrap
057         */
058        private LenientChronology(Chronology base) {
059            super(base, null);
060        }
061    
062        public Chronology withUTC() {
063            if (iWithUTC == null) {
064                if (getZone() == DateTimeZone.UTC) {
065                    iWithUTC = this;
066                } else {
067                    iWithUTC = LenientChronology.getInstance(getBase().withUTC());
068                }
069            }
070            return iWithUTC;
071        }
072    
073        public Chronology withZone(DateTimeZone zone) {
074            if (zone == null) {
075                zone = DateTimeZone.getDefault();
076            }
077            if (zone == DateTimeZone.UTC) {
078                return withUTC();
079            }
080            if (zone == getZone()) {
081                return this;
082            }
083            return LenientChronology.getInstance(getBase().withZone(zone));
084        }
085    
086        protected void assemble(Fields fields) {
087            fields.year = convertField(fields.year);
088            fields.yearOfEra = convertField(fields.yearOfEra);
089            fields.yearOfCentury = convertField(fields.yearOfCentury);
090            fields.centuryOfEra = convertField(fields.centuryOfEra);
091            fields.era = convertField(fields.era);
092            fields.dayOfWeek = convertField(fields.dayOfWeek);
093            fields.dayOfMonth = convertField(fields.dayOfMonth);
094            fields.dayOfYear = convertField(fields.dayOfYear);
095            fields.monthOfYear = convertField(fields.monthOfYear);
096            fields.weekOfWeekyear = convertField(fields.weekOfWeekyear);
097            fields.weekyear = convertField(fields.weekyear);
098            fields.weekyearOfCentury = convertField(fields.weekyearOfCentury);
099    
100            fields.millisOfSecond = convertField(fields.millisOfSecond);
101            fields.millisOfDay = convertField(fields.millisOfDay);
102            fields.secondOfMinute = convertField(fields.secondOfMinute);
103            fields.secondOfDay = convertField(fields.secondOfDay);
104            fields.minuteOfHour = convertField(fields.minuteOfHour);
105            fields.minuteOfDay = convertField(fields.minuteOfDay);
106            fields.hourOfDay = convertField(fields.hourOfDay);
107            fields.hourOfHalfday = convertField(fields.hourOfHalfday);
108            fields.clockhourOfDay = convertField(fields.clockhourOfDay);
109            fields.clockhourOfHalfday = convertField(fields.clockhourOfHalfday);
110            fields.halfdayOfDay = convertField(fields.halfdayOfDay);
111        }
112    
113        private final DateTimeField convertField(DateTimeField field) {
114            return LenientDateTimeField.getInstance(field, getBase());
115        }
116    
117        //-----------------------------------------------------------------------
118        /**
119         * A lenient chronology is only equal to a lenient chronology with the
120         * same base chronology.
121         * 
122         * @param obj  the object to compare to
123         * @return true if equal
124         * @since 1.4
125         */
126        public boolean equals(Object obj) {
127            if (this == obj) {
128                return true;
129            }
130            if (obj instanceof LenientChronology == false) {
131                return false;
132            }
133            LenientChronology chrono = (LenientChronology) obj;
134            return getBase().equals(chrono.getBase());
135        }
136    
137        /**
138         * A suitable hashcode for the chronology.
139         * 
140         * @return the hashcode
141         * @since 1.4
142         */
143        public int hashCode() {
144            return 236548278 + getBase().hashCode() * 7;
145        }
146    
147        /**
148         * A debugging string for the chronology.
149         * 
150         * @return the debugging string
151         */
152        public String toString() {
153            return "LenientChronology[" + getBase().toString() + ']';
154        }
155    
156    }