001/*
002 * Copyright (c) 2007-2013, Stephen Colebourne & Michael Nascimento Santos
003 *
004 * All rights reserved.
005 *
006 * Redistribution and use in source and binary forms, with or without
007 * modification, are permitted provided that the following conditions are met:
008 *
009 *  * Redistributions of source code must retain the above copyright notice,
010 *    this list of conditions and the following disclaimer.
011 *
012 *  * Redistributions in binary form must reproduce the above copyright notice,
013 *    this list of conditions and the following disclaimer in the documentation
014 *    and/or other materials provided with the distribution.
015 *
016 *  * Neither the name of JSR-310 nor the names of its contributors
017 *    may be used to endorse or promote products derived from this software
018 *    without specific prior written permission.
019 *
020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
021 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
022 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
023 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
024 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
025 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
026 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
027 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
028 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
029 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
030 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
031 */
032
033package org.threeten.bp.calendar;
034
035import static org.threeten.bp.temporal.ChronoField.EPOCH_DAY;
036
037import java.io.Serializable;
038import java.util.Arrays;
039import java.util.HashMap;
040import java.util.List;
041import java.util.Locale;
042
043import org.threeten.bp.DateTimeException;
044import org.threeten.bp.temporal.Chrono;
045import org.threeten.bp.temporal.ChronoField;
046import org.threeten.bp.temporal.ChronoLocalDate;
047import org.threeten.bp.temporal.Era;
048import org.threeten.bp.temporal.TemporalAccessor;
049import org.threeten.bp.temporal.ValueRange;
050
051/**
052 * The Hijrah calendar system.
053 * <p>
054 * This chronology defines the rules of the Hijrah calendar system.
055 * <p>
056 * The implementation follows the Freeman-Grenville algorithm (*1) and has following features.
057 * <p><ul>
058 * <li>A year has 12 months.</li>
059 * <li>Over a cycle of 30 years there are 11 leap years.</li>
060 * <li>There are 30 days in month number 1, 3, 5, 7, 9, and 11,
061 * and 29 days in month number 2, 4, 6, 8, 10, and 12.</li>
062 * <li>In a leap year month 12 has 30 days.</li>
063 * <li>In a 30 year cycle, year 2, 5, 7, 10, 13, 16, 18, 21, 24,
064 * 26, and 29 are leap years.</li>
065 * <li>Total of 10631 days in a 30 years cycle.</li>
066 * </ul><p>
067 * <P>
068 * The table shows the features described above.
069 * <blockquote>
070 * <table border="1">
071 *   <tbody>
072 *     <tr>
073 *       <th># of month</th>
074 *       <th>Name of month</th>
075 *       <th>Number of days</th>
076 *     </tr>
077 *     <tr>
078 *       <td>1</td>
079 *       <td>Muharram</td>
080 *       <td>30</td>
081 *     </tr>
082 *     <tr>
083 *       <td>2</td>
084 *       <td>Safar</td>
085 *       <td>29</td>
086 *     </tr>
087 *     <tr>
088 *       <td>3</td>
089 *       <td>Rabi'al-Awwal</td>
090 *       <td>30</td>
091 *     </tr>
092 *     <tr>
093 *       <td>4</td>
094 *       <td>Rabi'ath-Thani</td>
095 *       <td>29</td>
096 *     </tr>
097 *     <tr>
098 *       <td>5</td>
099 *       <td>Jumada l-Ula</td>
100 *       <td>30</td>
101 *     </tr>
102 *     <tr>
103 *       <td>6</td>
104 *       <td>Jumada t-Tania</td>
105 *       <td>29</td>
106 *     </tr>
107 *     <tr>
108 *       <td>7</td>
109 *       <td>Rajab</td>
110 *       <td>30</td>
111 *     </tr>
112 *     <tr>
113 *       <td>8</td>
114 *       <td>Sha`ban</td>
115 *       <td>29</td>
116 *     </tr>
117 *     <tr>
118 *       <td>9</td>
119 *       <td>Ramadan</td>
120 *       <td>30</td>
121 *     </tr>
122 *     <tr>
123 *       <td>10</td>
124 *       <td>Shawwal</td>
125 *       <td>29</td>
126 *     </tr>
127 *     <tr>
128 *       <td>11</td>
129 *       <td>Dhu 'l-Qa`da</td>
130 *       <td>30</td>
131 *     </tr>
132 *     <tr>
133 *       <td>12</td>
134 *       <td>Dhu 'l-Hijja</td>
135 *       <td>29, but 30 days in years 2, 5, 7, 10,<br>
136 * 13, 16, 18, 21, 24, 26, and 29</td>
137 *     </tr>
138 *   </tbody>
139 * </table>
140 * </blockquote>
141 * <p>
142 * (*1) The algorithm is taken from the book,
143 * The Muslim and Christian Calendars by G.S.P. Freeman-Grenville.
144 * <p>
145 *
146 * <h3>Specification for implementors</h3>
147 * This class is immutable and thread-safe.
148 */
149public final class HijrahChrono extends Chrono<HijrahChrono> implements Serializable {
150
151    /**
152     * Singleton instance of the Hijrah chronology.
153     */
154    public static final HijrahChrono INSTANCE = new HijrahChrono();
155
156    /**
157     * The singleton instance for the era before the current one - Before Hijrah -
158     * which has the value 0.
159     */
160    public static final Era<HijrahChrono> ERA_BEFORE_AH = HijrahEra.BEFORE_AH;
161    /**
162     * The singleton instance for the current era - Hijrah - which has the value 1.
163     */
164    public static final Era<HijrahChrono> ERA_AH = HijrahEra.AH;
165    /**
166     * Serialization version.
167     */
168    private static final long serialVersionUID = 3127340209035924785L;
169    /**
170     * Narrow names for eras.
171     */
172    private static final HashMap<String, String[]> ERA_NARROW_NAMES = new HashMap<>();
173    /**
174     * Short names for eras.
175     */
176    private static final HashMap<String, String[]> ERA_SHORT_NAMES = new HashMap<>();
177    /**
178     * Full names for eras.
179     */
180    private static final HashMap<String, String[]> ERA_FULL_NAMES = new HashMap<>();
181    /**
182     * Fallback language for the era names.
183     */
184    private static final String FALLBACK_LANGUAGE = "en";
185
186    /**
187     * Language that has the era names.
188     */
189    //private static final String TARGET_LANGUAGE = "ar";
190    /**
191     * Name data.
192     */
193    static {
194        ERA_NARROW_NAMES.put(FALLBACK_LANGUAGE, new String[]{"BH", "HE"});
195        ERA_SHORT_NAMES.put(FALLBACK_LANGUAGE, new String[]{"B.H.", "H.E."});
196        ERA_FULL_NAMES.put(FALLBACK_LANGUAGE, new String[]{"Before Hijrah", "Hijrah Era"});
197    }
198
199    /**
200     * Restrictive constructor.
201     */
202    private HijrahChrono() {
203    }
204
205    /**
206     * Resolve singleton.
207     *
208     * @return the singleton instance, not null
209     */
210    private Object readResolve() {
211        return INSTANCE;
212    }
213
214    //-----------------------------------------------------------------------
215    /**
216     * Gets the ID of the chronology - 'Hijrah'.
217     * <p>
218     * The ID uniquely identifies the {@code Chrono}.
219     * It can be used to lookup the {@code Chrono} using {@link #of(String)}.
220     *
221     * @return the chronology ID - 'Hijrah'
222     * @see #getCalendarType()
223     */
224    @Override
225    public String getId() {
226        return "Hijrah";
227    }
228
229    /**
230     * Gets the calendar type of the underlying calendar system - 'islamicc'.
231     * <p>
232     * The calendar type is an identifier defined by the
233     * <em>Unicode Locale Data Markup Language (LDML)</em> specification.
234     * It can be used to lookup the {@code Chrono} using {@link #of(String)}.
235     * It can also be used as part of a locale, accessible via
236     * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
237     *
238     * @return the calendar system type - 'islamicc'
239     * @see #getId()
240     */
241    @Override
242    public String getCalendarType() {
243        return "islamicc";
244    }
245
246    //-----------------------------------------------------------------------
247    @Override
248    public ChronoLocalDate<HijrahChrono> date(int prolepticYear, int month, int dayOfMonth) {
249        return HijrahDate.of(prolepticYear, month, dayOfMonth);
250    }
251
252    @Override
253    public ChronoLocalDate<HijrahChrono> dateYearDay(int prolepticYear, int dayOfYear) {
254        return HijrahDate.of(prolepticYear, 1, 1).plusDays(dayOfYear - 1);  // TODO better
255    }
256
257    @Override
258    public ChronoLocalDate<HijrahChrono> date(TemporalAccessor temporal) {
259        if (temporal instanceof HijrahDate) {
260            return (HijrahDate) temporal;
261        }
262        return HijrahDate.ofEpochDay(temporal.getLong(EPOCH_DAY));
263    }
264
265    //-----------------------------------------------------------------------
266    @Override
267    public boolean isLeapYear(long prolepticYear) {
268        return HijrahDate.isLeapYear(prolepticYear);
269    }
270
271    @Override
272    public int prolepticYear(Era<HijrahChrono> era, int yearOfEra) {
273        if (era instanceof HijrahEra == false) {
274            throw new DateTimeException("Era must be HijrahEra");
275        }
276        return (era == HijrahEra.AH ? yearOfEra : 1 - yearOfEra);
277    }
278
279    @Override
280    public Era<HijrahChrono> eraOf(int eraValue) {
281        switch (eraValue) {
282            case 0:
283                return HijrahEra.BEFORE_AH;
284            case 1:
285                return HijrahEra.AH;
286            default:
287                throw new DateTimeException("invalid Hijrah era");
288        }
289    }
290
291    @Override
292    public List<Era<HijrahChrono>> eras() {
293        return Arrays.<Era<HijrahChrono>>asList(HijrahEra.values());
294    }
295
296    //-----------------------------------------------------------------------
297    @Override
298    public ValueRange range(ChronoField field) {
299        return field.range();
300    }
301
302}