1 /*
2  *  Copyright 2001-2014 Stephen Colebourne
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  */

16 package org.joda.time.chrono;
17
18 import java.text.DateFormatSymbols;
19 import java.util.Locale;
20 import java.util.TreeMap;
21 import java.util.concurrent.ConcurrentHashMap;
22 import java.util.concurrent.ConcurrentMap;
23
24 import org.joda.time.DateTimeFieldType;
25 import org.joda.time.DateTimeUtils;
26 import org.joda.time.IllegalFieldValueException;
27
28 /**
29  * Utility class used by a few of the GJDateTimeFields.
30  *
31  * @author Brian S O'Neill
32  * @since 1.0
33  */

34 class GJLocaleSymbols {
35
36     private static ConcurrentMap<Locale, GJLocaleSymbols> cCache = new ConcurrentHashMap<Locale, GJLocaleSymbols>();
37
38     /**
39      * Obtains the symbols for a locale.
40      * 
41      * @param locale  the locale, null returns default
42      * @return the symbols, not null
43      */

44     static GJLocaleSymbols forLocale(Locale locale) {
45         if (locale == null) {
46             locale = Locale.getDefault();
47         }
48         GJLocaleSymbols symbols = cCache.get(locale);
49         if (symbols == null) {
50             symbols = new GJLocaleSymbols(locale);
51             GJLocaleSymbols oldSymbols = cCache.putIfAbsent(locale, symbols);
52             if (oldSymbols != null) {
53                 symbols = oldSymbols;
54             }
55         }
56         return symbols;
57     }
58
59     private static String[] realignMonths(String[] months) {
60         String[] a = new String[13];
61         for (int i=1; i<13; i++) {
62             a[i] = months[i - 1];
63         }
64         return a;
65     }
66
67     private static String[] realignDaysOfWeek(String[] daysOfWeek) {
68         String[] a = new String[8];
69         for (int i=1; i<8; i++) {
70             a[i] = daysOfWeek[(i < 7) ? i + 1 : 1];
71         }
72         return a;
73     }
74
75     private static void addSymbols(TreeMap<String, Integer> map, String[] symbols, Integer[] integers) {
76         for (int i=symbols.length; --i>=0; ) {
77             String symbol = symbols[i];
78             if (symbol != null) {
79                 map.put(symbol, integers[i]);
80             }
81         }
82     }
83
84     private static void addNumerals(TreeMap<String, Integer> map, int start, int end, Integer[] integers) {
85         for (int i=start; i<=end; i++) {
86             map.put(String.valueOf(i).intern(), integers[i]);
87         }
88     }
89
90     private static int maxLength(String[] a) {
91         int max = 0;
92         for (int i=a.length; --i>=0; ) {
93             String s = a[i];
94             if (s != null) {
95                 int len = s.length();
96                 if (len > max) {
97                     max = len;
98                 }
99             }
100         }
101         return max;
102     }
103
104     private final String[] iEras;
105     private final String[] iDaysOfWeek;
106     private final String[] iShortDaysOfWeek;
107     private final String[] iMonths;
108     private final String[] iShortMonths;
109     private final String[] iHalfday;
110
111     private final TreeMap<String, Integer> iParseEras;
112     private final TreeMap<String, Integer> iParseDaysOfWeek;
113     private final TreeMap<String, Integer> iParseMonths;
114
115     private final int iMaxEraLength;
116     private final int iMaxDayOfWeekLength;
117     private final int iMaxShortDayOfWeekLength;
118     private final int iMaxMonthLength;
119     private final int iMaxShortMonthLength;
120     private final int iMaxHalfdayLength;
121
122     /**
123      * @param locale must not be null
124      */

125     private GJLocaleSymbols(Locale locale) {
126         DateFormatSymbols dfs = DateTimeUtils.getDateFormatSymbols(locale);
127         
128         iEras = dfs.getEras();
129         iDaysOfWeek = realignDaysOfWeek(dfs.getWeekdays());
130         iShortDaysOfWeek = realignDaysOfWeek(dfs.getShortWeekdays());
131         iMonths = realignMonths(dfs.getMonths());
132         iShortMonths = realignMonths(dfs.getShortMonths());
133         iHalfday = dfs.getAmPmStrings();
134
135         Integer[] integers = new Integer[13];
136         for (int i=0; i<13; i++) {
137             integers[i] = Integer.valueOf(i);
138         }
139
140         iParseEras = new TreeMap<String, Integer>(String.CASE_INSENSITIVE_ORDER);
141         addSymbols(iParseEras, iEras, integers);
142         if ("en".equals(locale.getLanguage())) {
143             // Include support for parsing "BCE" and "CE" if the language is
144             // English. At some point Joda-Time will need an independent set of
145             // localized symbols and not depend on java.text.DateFormatSymbols.
146             iParseEras.put("BCE", integers[0]);
147             iParseEras.put("CE", integers[1]);
148         }
149
150         iParseDaysOfWeek = new TreeMap<String, Integer>(String.CASE_INSENSITIVE_ORDER);
151         addSymbols(iParseDaysOfWeek, iDaysOfWeek, integers);
152         addSymbols(iParseDaysOfWeek, iShortDaysOfWeek, integers);
153         addNumerals(iParseDaysOfWeek, 1, 7, integers);
154
155         iParseMonths = new TreeMap<String, Integer>(String.CASE_INSENSITIVE_ORDER);
156         addSymbols(iParseMonths, iMonths, integers);
157         addSymbols(iParseMonths, iShortMonths, integers);
158         addNumerals(iParseMonths, 1, 12, integers);
159
160         iMaxEraLength = maxLength(iEras);
161         iMaxDayOfWeekLength = maxLength(iDaysOfWeek);
162         iMaxShortDayOfWeekLength = maxLength(iShortDaysOfWeek);
163         iMaxMonthLength = maxLength(iMonths);
164         iMaxShortMonthLength = maxLength(iShortMonths);
165         iMaxHalfdayLength = maxLength(iHalfday);
166     }
167
168     public String eraValueToText(int value) {
169         return iEras[value];
170     }
171
172     public int eraTextToValue(String text) {
173         Integer era = iParseEras.get(text);
174         if (era != null) {
175             return era.intValue();
176         }
177         throw new IllegalFieldValueException(DateTimeFieldType.era(), text);
178     }
179
180     public int getEraMaxTextLength() {
181         return iMaxEraLength;
182     }
183
184     public String monthOfYearValueToText(int value) {
185         return iMonths[value];
186     }
187
188     public String monthOfYearValueToShortText(int value) {
189         return iShortMonths[value];
190     }
191
192     public int monthOfYearTextToValue(String text) {
193         Integer month = iParseMonths.get(text);
194         if (month != null) {
195             return month.intValue();
196         }
197         throw new IllegalFieldValueException(DateTimeFieldType.monthOfYear(), text);
198     }
199
200     public int getMonthMaxTextLength() {
201         return iMaxMonthLength;
202     }
203
204     public int getMonthMaxShortTextLength() {
205         return iMaxShortMonthLength;
206     }
207
208     public String dayOfWeekValueToText(int value) {
209         return iDaysOfWeek[value];
210     }
211
212     public String dayOfWeekValueToShortText(int value) {
213         return iShortDaysOfWeek[value];
214     }
215
216     public int dayOfWeekTextToValue(String text) {
217         Integer day = iParseDaysOfWeek.get(text);
218         if (day != null) {
219             return day.intValue();
220         }
221         throw new IllegalFieldValueException(DateTimeFieldType.dayOfWeek(), text);
222     }
223
224     public int getDayOfWeekMaxTextLength() {
225         return iMaxDayOfWeekLength;
226     }
227
228     public int getDayOfWeekMaxShortTextLength() {
229         return iMaxShortDayOfWeekLength;
230     }
231
232     public String halfdayValueToText(int value) {
233         return iHalfday[value];
234     }
235
236     public int halfdayTextToValue(String text) {
237         String[] halfday = iHalfday;
238         for (int i = halfday.length; --i>=0; ) {
239             if (halfday[i].equalsIgnoreCase(text)) {
240                 return i;
241             }
242         }
243         throw new IllegalFieldValueException(DateTimeFieldType.halfdayOfDay(), text);
244     }
245
246     public int getHalfdayMaxTextLength() {
247         return iMaxHalfdayLength;
248     }
249 }
250