]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_4_2-src/main/classes/core/src/com/ibm/icu/util/Currency.java
go
[Dictionary.git] / jars / icu4j-4_4_2-src / main / classes / core / src / com / ibm / icu / util / Currency.java
1 /**\r
2  *******************************************************************************\r
3  * Copyright (C) 2001-2010, International Business Machines Corporation and    *\r
4  * others. All Rights Reserved.                                                *\r
5  *******************************************************************************\r
6  */\r
7 package com.ibm.icu.util;\r
8 \r
9 import java.io.Serializable;\r
10 import java.text.ParsePosition;\r
11 import java.util.ArrayList;\r
12 import java.util.Date;\r
13 import java.util.Iterator;\r
14 import java.util.List;\r
15 import java.util.Locale;\r
16 import java.util.Map;\r
17 import java.util.Vector;\r
18 \r
19 import com.ibm.icu.impl.ICUCache;\r
20 import com.ibm.icu.impl.ICUDebug;\r
21 import com.ibm.icu.impl.ICUResourceBundle;\r
22 import com.ibm.icu.impl.SimpleCache;\r
23 import com.ibm.icu.impl.TextTrieMap;\r
24 import com.ibm.icu.text.CurrencyDisplayNames;\r
25 import com.ibm.icu.text.CurrencyMetaInfo;\r
26 import com.ibm.icu.text.CurrencyMetaInfo.CurrencyDigits;\r
27 import com.ibm.icu.text.CurrencyMetaInfo.CurrencyFilter;\r
28 \r
29 /**\r
30  * A class encapsulating a currency, as defined by ISO 4217.  A\r
31  * <tt>Currency</tt> object can be created given a <tt>Locale</tt> or\r
32  * given an ISO 4217 code.  Once created, the <tt>Currency</tt> object\r
33  * can return various data necessary to its proper display:\r
34  *\r
35  * <ul><li>A display symbol, for a specific locale\r
36  * <li>The number of fraction digits to display\r
37  * <li>A rounding increment\r
38  * </ul>\r
39  *\r
40  * The <tt>DecimalFormat</tt> class uses these data to display\r
41  * currencies.\r
42  *\r
43  * <p>Note: This class deliberately resembles\r
44  * <tt>java.util.Currency</tt> but it has a completely independent\r
45  * implementation, and adds features not present in the JDK.\r
46  * @author Alan Liu\r
47  * @stable ICU 2.2\r
48  */\r
49 public class Currency extends MeasureUnit implements Serializable {\r
50     // using serialver from jdk1.4.2_05\r
51     private static final long serialVersionUID = -5839973855554750484L;\r
52     private static final boolean DEBUG = ICUDebug.enabled("currency");\r
53 \r
54     // Cache to save currency name trie\r
55     private static ICUCache<ULocale, Vector<TextTrieMap<CurrencyStringInfo>>> CURRENCY_NAME_CACHE =\r
56         new SimpleCache<ULocale, Vector<TextTrieMap<CurrencyStringInfo>>>();\r
57 \r
58     /**\r
59      * ISO 4217 3-letter code.\r
60      */\r
61     private String isoCode;\r
62 \r
63     /**\r
64      * Selector for getName() indicating a symbolic name for a\r
65      * currency, such as "$" for USD.\r
66      * @stable ICU 2.6\r
67      */\r
68     public static final int SYMBOL_NAME = 0;\r
69 \r
70     /**\r
71      * Selector for ucurr_getName indicating the long name for a\r
72      * currency, such as "US Dollar" for USD.\r
73      * @stable ICU 2.6\r
74      */\r
75     public static final int LONG_NAME = 1;\r
76    \r
77     /**\r
78      * Selector for getName() indicating the plural long name for a \r
79      * currency, such as "US dollar" for USD in "1 US dollar", \r
80      * and "US dollars" for USD in "2 US dollars".\r
81      * @stable ICU 4.2\r
82      */\r
83     public static final int PLURAL_LONG_NAME = 2;\r
84 \r
85     // begin registry stuff\r
86 \r
87     // shim for service code\r
88     /* package */ static abstract class ServiceShim {\r
89         abstract ULocale[] getAvailableULocales();\r
90         abstract Locale[] getAvailableLocales();\r
91         abstract Currency createInstance(ULocale l);\r
92         abstract Object registerInstance(Currency c, ULocale l);\r
93         abstract boolean unregister(Object f);\r
94     }\r
95 \r
96     private static ServiceShim shim;\r
97     private static ServiceShim getShim() {\r
98         // Note: this instantiation is safe on loose-memory-model configurations\r
99         // despite lack of synchronization, since the shim instance has no state--\r
100         // it's all in the class init.  The worst problem is we might instantiate\r
101         // two shim instances, but they'll share the same state so that's ok.\r
102         if (shim == null) {\r
103             try {\r
104                 Class<?> cls = Class.forName("com.ibm.icu.util.CurrencyServiceShim");\r
105                 shim = (ServiceShim)cls.newInstance();\r
106             }\r
107             catch (Exception e) {\r
108                 if(DEBUG){\r
109                     e.printStackTrace();\r
110                 }\r
111                 throw new RuntimeException(e.getMessage());\r
112             }\r
113         }\r
114         return shim;\r
115     }\r
116 \r
117     /**\r
118      * Returns a currency object for the default currency in the given\r
119      * locale.\r
120      * @param locale the locale\r
121      * @return the currency object for this locale\r
122      * @stable ICU 2.2\r
123      */\r
124     public static Currency getInstance(Locale locale) {\r
125         return getInstance(ULocale.forLocale(locale));\r
126     }\r
127 \r
128     /**\r
129      * Returns a currency object for the default currency in the given\r
130      * locale.\r
131      * @stable ICU 3.2\r
132      */\r
133     public static Currency getInstance(ULocale locale) {\r
134         String currency = locale.getKeywordValue("currency");\r
135         if (currency != null) {\r
136             return getInstance(currency);\r
137         }\r
138 \r
139         if (shim == null) {\r
140             return createCurrency(locale);\r
141         }\r
142 \r
143         return shim.createInstance(locale);\r
144     }\r
145 \r
146     /**\r
147      * Returns an array of Strings which contain the currency\r
148      * identifiers that are valid for the given locale on the \r
149      * given date.  If there are no such identifiers, returns null.\r
150      * Returned identifiers are in preference order.\r
151      * @param loc the locale for which to retrieve currency codes.\r
152      * @param d the date for which to retrieve currency codes for the given locale.\r
153      * @return The array of ISO currency codes.\r
154      * @stable ICU 4.0\r
155      */\r
156     public static String[] getAvailableCurrencyCodes(ULocale loc, Date d) {\r
157         CurrencyMetaInfo info = CurrencyMetaInfo.getInstance();\r
158         CurrencyFilter filter = CurrencyFilter.onDate(d).withRegion(loc.getCountry());\r
159         List<String> list = info.currencies(filter);\r
160         // Note: Prior to 4.4 the spec didn't say that we return null if there are no results, but \r
161         // the test assumed it did.  Kept the behavior and amended the spec.\r
162         if (list.isEmpty()) {\r
163             return null;\r
164         }\r
165         return list.toArray(new String[list.size()]);\r
166     }\r
167 \r
168     private static final String EUR_STR = "EUR";\r
169     \r
170     /**\r
171      * Instantiate a currency from resource data.\r
172      */\r
173     /* package */ static Currency createCurrency(ULocale loc) {\r
174         String variant = loc.getVariant();\r
175         if ("EURO".equals(variant)) {\r
176             return new Currency(EUR_STR);\r
177         }\r
178         \r
179         String country = loc.getCountry();\r
180         \r
181         CurrencyMetaInfo info = CurrencyMetaInfo.getInstance();\r
182         List<String> list = info.currencies(CurrencyFilter.onRegion(country));\r
183         if (list.size() > 0) {\r
184             String code = list.get(0);\r
185             boolean isPreEuro = "PREEURO".equals(variant);\r
186             if (isPreEuro && EUR_STR.equals(code)) {\r
187                 if (list.size() < 2) {\r
188                     return null;\r
189                 }\r
190                 code = list.get(1);\r
191             }\r
192             return new Currency(code);\r
193         }\r
194         return null;\r
195     }\r
196 \r
197     /**\r
198      * Returns a currency object given an ISO 4217 3-letter code.\r
199      * @param theISOCode the iso code\r
200      * @return the currency for this iso code\r
201      * @throws NullPointerException if <code>theISOCode</code> is null.\r
202      * @throws IllegalArgumentException if <code>theISOCode</code> is not a\r
203      *         3-letter alpha code.\r
204      * @stable ICU 2.2\r
205      */\r
206     public static Currency getInstance(String theISOCode) {\r
207         if (theISOCode == null) {\r
208             throw new NullPointerException("The input currency code is null.");\r
209         }\r
210         boolean is3alpha = true;\r
211         if (theISOCode.length() != 3) {\r
212             is3alpha = false;\r
213         } else {\r
214             for (int i = 0; i < 3; i++) {\r
215                 char ch = theISOCode.charAt(i);\r
216                 if (ch < 'A' || (ch > 'Z' && ch < 'a') || ch > 'z') {\r
217                     is3alpha = false;\r
218                     break;\r
219                 }\r
220             }\r
221         }\r
222         if (!is3alpha) {\r
223             throw new IllegalArgumentException(\r
224                     "The input currency code is not 3-letter alphabetic code.");\r
225         }\r
226         return new Currency(theISOCode.toUpperCase(Locale.US));\r
227     }\r
228 \r
229     /**\r
230      * Registers a new currency for the provided locale.  The returned object\r
231      * is a key that can be used to unregister this currency object.\r
232      * @param currency the currency to register\r
233      * @param locale the ulocale under which to register the currency\r
234      * @return a registry key that can be used to unregister this currency\r
235      * @see #unregister\r
236      * @stable ICU 3.2\r
237      */\r
238     public static Object registerInstance(Currency currency, ULocale locale) {\r
239         return getShim().registerInstance(currency, locale);\r
240     }\r
241 \r
242     /**\r
243      * Unregister the currency associated with this key (obtained from\r
244      * registerInstance).\r
245      * @param registryKey the registry key returned from registerInstance\r
246      * @see #registerInstance\r
247      * @stable ICU 2.6\r
248      */\r
249     public static boolean unregister(Object registryKey) {\r
250         if (registryKey == null) {\r
251             throw new IllegalArgumentException("registryKey must not be null");\r
252         }\r
253         if (shim == null) {\r
254             return false;\r
255         }\r
256         return shim.unregister(registryKey);\r
257     }\r
258 \r
259     /**\r
260      * Return an array of the locales for which a currency\r
261      * is defined.\r
262      * @return an array of the available locales\r
263      * @stable ICU 2.2\r
264      */\r
265     public static Locale[] getAvailableLocales() {\r
266         if (shim == null) {\r
267             return ICUResourceBundle.getAvailableLocales();\r
268         } else {\r
269             return shim.getAvailableLocales();\r
270         }\r
271     }\r
272 \r
273     /**\r
274      * Return an array of the ulocales for which a currency\r
275      * is defined.\r
276      * @return an array of the available ulocales\r
277      * @stable ICU 3.2\r
278      */\r
279     public static ULocale[] getAvailableULocales() {\r
280         if (shim == null) {\r
281             return ICUResourceBundle.getAvailableULocales();\r
282         } else {\r
283             return shim.getAvailableULocales();\r
284         }\r
285     }\r
286 \r
287     // end registry stuff\r
288 \r
289     /**\r
290      * Given a key and a locale, returns an array of values for the key for which data\r
291      * exists.  If commonlyUsed is true, these are the values that typically are used\r
292      * with this locale, otherwise these are all values for which data exists.  \r
293      * This is a common service API.\r
294      * <p>\r
295      * The only supported key is "currency", other values return an empty array.\r
296      * <p>\r
297      * Currency information is based on the region of the locale.  If the locale does not\r
298      * indicate a region, {@link ULocale#addLikelySubtags(ULocale)} is used to infer a region,\r
299      * except for the 'und' locale.\r
300      * <p>\r
301      * If commonlyUsed is true, only the currencies known to be in use as of the current date\r
302      * are returned.  When there are more than one, these are returned in preference order\r
303      * (typically, this occurs when a country is transitioning to a new currency, and the\r
304      * newer currency is preferred), see \r
305      * <a href="http://unicode.org/reports/tr35/#Supplemental_Currency_Data">Unicode TR#35 Sec. C1</a>.  \r
306      * If commonlyUsed is false, all currencies ever used in any locale are returned, in no\r
307      * particular order.\r
308      * \r
309      * @param key           key whose values to look up.  the only recognized key is "currency"\r
310      * @param locale        the locale\r
311      * @param commonlyUsed  if true, return only values that are currently used in the locale.\r
312      *                      Otherwise returns all values.\r
313      * @return an array of values for the given key and the locale.  If there is no data, the\r
314      *   array will be empty.\r
315      * @stable ICU 4.2\r
316      */\r
317     public static final String[] getKeywordValuesForLocale(String key, ULocale locale, \r
318             boolean commonlyUsed) {\r
319         \r
320         // The only keyword we recognize is 'currency'\r
321         if (!"currency".equals(key)) {\r
322             return EMPTY_STRING_ARRAY;\r
323         }\r
324         \r
325         CurrencyMetaInfo info = CurrencyMetaInfo.getInstance();\r
326         if (!commonlyUsed) {\r
327             // Behavior change from 4.3.3, no longer sort the currencies\r
328             List<String> result = info.currencies(null);\r
329             return result.toArray(new String[result.size()]);\r
330         }\r
331         \r
332         // Don't resolve region if the requested locale is 'und', it will resolve to US\r
333         // which we don't want.\r
334         String prefRegion = locale.getCountry();\r
335         if (prefRegion.length() == 0) {\r
336             if (UND.equals(locale)) {\r
337                 return EMPTY_STRING_ARRAY;\r
338             }\r
339             ULocale loc = ULocale.addLikelySubtags(locale);\r
340             prefRegion = loc.getCountry();\r
341        }\r
342 \r
343         CurrencyFilter filter = CurrencyFilter.now().withRegion(prefRegion);\r
344         \r
345         // currencies are in region's preferred order when we're filtering on region, which\r
346         // matches our spec\r
347         List<String> result = info.currencies(filter);\r
348         \r
349         // No fallback anymore (change from 4.3.3)\r
350         if (result.size() == 0) {\r
351             return EMPTY_STRING_ARRAY;\r
352         }\r
353 \r
354         return result.toArray(new String[result.size()]);\r
355     }\r
356     \r
357     private static final ULocale UND = new ULocale("und");\r
358     private static final String[] EMPTY_STRING_ARRAY = new String[0];\r
359 \r
360     /**\r
361      * Return a hashcode for this currency.\r
362      * @stable ICU 2.2\r
363      */\r
364     public int hashCode() {\r
365         return isoCode.hashCode();\r
366     }\r
367 \r
368     /**\r
369      * Return true if rhs is a Currency instance,\r
370      * is non-null, and has the same currency code.\r
371      * @stable ICU 2.2\r
372      */\r
373     public boolean equals(Object rhs) {\r
374         if (rhs == null) return false;\r
375         if (rhs == this) return true;\r
376         try {\r
377             Currency c = (Currency) rhs;\r
378             return isoCode.equals(c.isoCode);\r
379         }\r
380         catch (ClassCastException e) {\r
381             return false;\r
382         }\r
383     }\r
384 \r
385     /**\r
386      * Returns the ISO 4217 3-letter code for this currency object.\r
387      * @stable ICU 2.2\r
388      */\r
389     public String getCurrencyCode() {\r
390         return isoCode;\r
391     }\r
392 \r
393     /**\r
394      * Convenience and compatibility override of getName that\r
395      * requests the symbol name.\r
396      * @see #getName\r
397      * @stable ICU 3.4\r
398      */\r
399     public String getSymbol() {\r
400         return getSymbol(ULocale.getDefault());\r
401     }\r
402 \r
403     /**\r
404      * Convenience and compatibility override of getName that\r
405      * requests the symbol name.\r
406      * @param loc the Locale for the symbol\r
407      * @see #getName\r
408      * @stable ICU 3.4\r
409      */\r
410     public String getSymbol(Locale loc) {\r
411         return getSymbol(ULocale.forLocale(loc));\r
412     }\r
413 \r
414     /**\r
415      * Convenience and compatibility override of getName that\r
416      * requests the symbol name.\r
417      * @param uloc the ULocale for the symbol\r
418      * @see #getName\r
419      * @stable ICU 3.4\r
420      */\r
421     public String getSymbol(ULocale uloc) {\r
422         return getName(uloc, SYMBOL_NAME, new boolean[1]);\r
423     }\r
424 \r
425     /**\r
426      * Returns the display name for the given currency in the\r
427      * given locale.  \r
428      * This is a convenient method for \r
429      * getName(ULocale, int, boolean[]); \r
430      * @stable ICU 3.2\r
431      */\r
432     public String getName(Locale locale,\r
433                           int nameStyle,\r
434                           boolean[] isChoiceFormat) {\r
435         return getName(ULocale.forLocale(locale), nameStyle, isChoiceFormat);\r
436     }\r
437 \r
438     /**\r
439      * Returns the display name for the given currency in the\r
440      * given locale.  For example, the display name for the USD\r
441      * currency object in the en_US locale is "$".\r
442      * @param locale locale in which to display currency\r
443      * @param nameStyle selector for which kind of name to return.\r
444      *                  The nameStyle should be either SYMBOL_NAME or \r
445      *                  LONG_NAME. Otherwise, throw IllegalArgumentException.\r
446      * @param isChoiceFormat fill-in; isChoiceFormat[0] is set to true\r
447      * if the returned value is a ChoiceFormat pattern; otherwise it\r
448      * is set to false\r
449      * @return display string for this currency.  If the resource data\r
450      * contains no entry for this currency, then the ISO 4217 code is\r
451      * returned.  If isChoiceFormat[0] is true, then the result is a\r
452      * ChoiceFormat pattern.  Otherwise it is a static string. <b>Note:</b>\r
453      * as of ICU 4.4, choice formats are not used, and the value returned\r
454      * in isChoiceFormat is always false.\r
455      * <p>\r
456      * @throws  IllegalArgumentException  if the nameStyle is not SYMBOL_NAME\r
457      *                                    or LONG_NAME.\r
458      * @see #getName(ULocale, int, String, boolean[])\r
459      * @stable ICU 3.2\r
460      */\r
461     public String getName(ULocale locale, int nameStyle, boolean[] isChoiceFormat) {\r
462         if (!(nameStyle == SYMBOL_NAME || nameStyle == LONG_NAME)) {\r
463             throw new IllegalArgumentException("bad name style: " + nameStyle);\r
464         }\r
465 \r
466         // We no longer support choice format data in names.  Data should not contain\r
467         // choice patterns.\r
468         if (isChoiceFormat != null) {\r
469             isChoiceFormat[0] = false;\r
470         }\r
471 \r
472         CurrencyDisplayNames names = CurrencyDisplayNames.getInstance(locale);\r
473         return nameStyle == SYMBOL_NAME ? names.getSymbol(isoCode) : names.getName(isoCode);\r
474     }\r
475 \r
476     /**\r
477      * Returns the display name for the given currency in the given locale.  \r
478      * This is a convenience overload of getName(ULocale, int, String, boolean[]);\r
479      * @stable ICU 4.2\r
480      */\r
481     public String getName(Locale locale, int nameStyle, String pluralCount,\r
482             boolean[] isChoiceFormat) {\r
483         return getName(ULocale.forLocale(locale), nameStyle, pluralCount, isChoiceFormat);\r
484     }\r
485 \r
486     /**\r
487      * Returns the display name for the given currency in the\r
488      * given locale.  For example, the SYMBOL_NAME for the USD\r
489      * currency object in the en_US locale is "$".\r
490      * The PLURAL_LONG_NAME for the USD currency object when the currency \r
491      * amount is plural is "US dollars", such as in "3.00 US dollars";\r
492      * while the PLURAL_LONG_NAME for the USD currency object when the currency\r
493      * amount is singular is "US dollar", such as in "1.00 US dollar".\r
494      * @param locale locale in which to display currency\r
495      * @param nameStyle selector for which kind of name to return\r
496      * @param pluralCount plural count string for this locale\r
497      * @param isChoiceFormat fill-in; isChoiceFormat[0] is set to true\r
498      * if the returned value is a ChoiceFormat pattern; otherwise it\r
499      * is set to false\r
500      * @return display string for this currency.  If the resource data\r
501      * contains no entry for this currency, then the ISO 4217 code is\r
502      * returned.  If isChoiceFormat[0] is true, then the result is a\r
503      * ChoiceFormat pattern.  Otherwise it is a static string. <b>Note:</b>\r
504      * as of ICU 4.4, choice formats are not used, and the value returned\r
505      * in isChoiceFormat is always false.\r
506      * @throws  IllegalArgumentException  if the nameStyle is not SYMBOL_NAME,\r
507      *                                    LONG_NAME, or PLURAL_LONG_NAME.\r
508      * @stable ICU 4.2\r
509      */\r
510     public String getName(ULocale locale, int nameStyle, String pluralCount,\r
511             boolean[] isChoiceFormat) {\r
512         if (nameStyle != PLURAL_LONG_NAME) {\r
513             return getName(locale, nameStyle, isChoiceFormat);\r
514         }\r
515 \r
516         // We no longer support choice format\r
517         if (isChoiceFormat != null) {\r
518             isChoiceFormat[0] = false;\r
519         }\r
520         \r
521         CurrencyDisplayNames names = CurrencyDisplayNames.getInstance(locale);\r
522         return names.getPluralName(isoCode, pluralCount);\r
523     }\r
524 \r
525     /**\r
526      * Attempt to parse the given string as a currency, either as a\r
527      * display name in the given locale, or as a 3-letter ISO 4217\r
528      * code.  If multiple display names match, then the longest one is\r
529      * selected.  If both a display name and a 3-letter ISO code\r
530      * match, then the display name is preferred, unless it's length\r
531      * is less than 3.\r
532      *\r
533      * @param locale the locale of the display names to match\r
534      * @param text the text to parse\r
535      * @param type parse against currency type: LONG_NAME only or not\r
536      * @param pos input-output position; on input, the position within\r
537      * text to match; must have 0 <= pos.getIndex() < text.length();\r
538      * on output, the position after the last matched character. If\r
539      * the parse fails, the position in unchanged upon output.\r
540      * @return the ISO 4217 code, as a string, of the best match, or\r
541      * null if there is no match\r
542      *\r
543      * @internal\r
544      * @deprecated This API is ICU internal only.\r
545      */\r
546     public static String parse(ULocale locale, String text, int type, ParsePosition pos) {\r
547         Vector<TextTrieMap<CurrencyStringInfo>> currencyTrieVec = CURRENCY_NAME_CACHE.get(locale);\r
548         if (currencyTrieVec == null) {\r
549             TextTrieMap<CurrencyStringInfo> currencyNameTrie = \r
550                 new TextTrieMap<CurrencyStringInfo>(true);\r
551             TextTrieMap<CurrencyStringInfo> currencySymbolTrie = \r
552                 new TextTrieMap<CurrencyStringInfo>(false);\r
553             currencyTrieVec = new Vector<TextTrieMap<CurrencyStringInfo>>();\r
554             currencyTrieVec.addElement(currencySymbolTrie);\r
555             currencyTrieVec.addElement(currencyNameTrie);\r
556             setupCurrencyTrieVec(locale, currencyTrieVec);\r
557             CURRENCY_NAME_CACHE.put(locale, currencyTrieVec);\r
558         }\r
559         \r
560         int maxLength = 0;\r
561         String isoResult = null;\r
562 \r
563           // look for the names\r
564         TextTrieMap<CurrencyStringInfo> currencyNameTrie = currencyTrieVec.elementAt(1);\r
565         CurrencyNameResultHandler handler = new CurrencyNameResultHandler();\r
566         currencyNameTrie.find(text, pos.getIndex(), handler);\r
567         List<CurrencyStringInfo> list = handler.getMatchedCurrencyNames();\r
568         if (list != null && list.size() != 0) {\r
569             for (CurrencyStringInfo info : list) {\r
570                 String isoCode = info.getISOCode();\r
571                 String currencyString = info.getCurrencyString();\r
572                 if (currencyString.length() > maxLength) {\r
573                     maxLength = currencyString.length();\r
574                     isoResult = isoCode;\r
575                 }\r
576             }\r
577         }\r
578 \r
579         if (type != Currency.LONG_NAME) {  // not long name only\r
580             TextTrieMap<CurrencyStringInfo> currencySymbolTrie = currencyTrieVec.elementAt(0);\r
581             handler = new CurrencyNameResultHandler();\r
582             currencySymbolTrie.find(text, pos.getIndex(), handler);\r
583             list = handler.getMatchedCurrencyNames();\r
584             if (list != null && list.size() != 0) {\r
585                 for (CurrencyStringInfo info : list) {\r
586                     String isoCode = info.getISOCode();\r
587                     String currencyString = info.getCurrencyString();\r
588                     if (currencyString.length() > maxLength) {\r
589                         maxLength = currencyString.length();\r
590                         isoResult = isoCode;\r
591                     }\r
592                 }\r
593             }\r
594         }\r
595 \r
596         int start = pos.getIndex();\r
597         pos.setIndex(start + maxLength);\r
598         return isoResult;\r
599     }\r
600 \r
601     private static void setupCurrencyTrieVec(ULocale locale, \r
602             Vector<TextTrieMap<CurrencyStringInfo>> trieVec) {\r
603 \r
604         TextTrieMap<CurrencyStringInfo> symTrie = trieVec.elementAt(0);\r
605         TextTrieMap<CurrencyStringInfo> trie = trieVec.elementAt(1);\r
606 \r
607         CurrencyDisplayNames names = CurrencyDisplayNames.getInstance(locale);\r
608         for (Map.Entry<String, String> e : names.symbolMap().entrySet()) {\r
609             String symbol = e.getKey();\r
610             String isoCode = e.getValue();\r
611             symTrie.put(symbol, new CurrencyStringInfo(isoCode, symbol));\r
612         }\r
613         for (Map.Entry<String, String> e : names.nameMap().entrySet()) {\r
614             String name = e.getKey();\r
615             String isoCode = e.getValue();\r
616             trie.put(name, new CurrencyStringInfo(isoCode, name));\r
617         }\r
618     }\r
619 \r
620     private static final class CurrencyStringInfo {\r
621         private String isoCode;\r
622         private String currencyString;\r
623 \r
624         public CurrencyStringInfo(String isoCode, String currencyString) {\r
625             this.isoCode = isoCode;\r
626             this.currencyString = currencyString;\r
627         }\r
628 \r
629         private String getISOCode() {\r
630             return isoCode;\r
631         }\r
632 \r
633         private String getCurrencyString() {\r
634             return currencyString;\r
635         }\r
636     }\r
637 \r
638     private static class CurrencyNameResultHandler \r
639             implements TextTrieMap.ResultHandler<CurrencyStringInfo> {\r
640         private ArrayList<CurrencyStringInfo> resultList;\r
641     \r
642         public boolean handlePrefixMatch(int matchLength, Iterator<CurrencyStringInfo> values) {\r
643             if (resultList == null) {\r
644                 resultList = new ArrayList<CurrencyStringInfo>();\r
645             }\r
646             while (values.hasNext()) {\r
647                 CurrencyStringInfo item = values.next();\r
648                 if (item == null) {\r
649                     break;\r
650                 }\r
651                 int i = 0;\r
652                 for (; i < resultList.size(); i++) {\r
653                     CurrencyStringInfo tmp = resultList.get(i);\r
654                     if (item.getISOCode() == tmp.getISOCode()) {\r
655                         if (matchLength > tmp.getCurrencyString().length()) {\r
656                             resultList.set(i, item);\r
657                         }\r
658                         break;\r
659                     }\r
660                 }\r
661                 if (i == resultList.size()) {\r
662                     // not found in the current list\r
663                     resultList.add(item);\r
664                 }\r
665             }\r
666             return true;\r
667         }\r
668 \r
669         List<CurrencyStringInfo> getMatchedCurrencyNames() {\r
670             if (resultList == null || resultList.size() == 0) {\r
671                 return null;\r
672             }\r
673             return resultList;\r
674         }\r
675     }\r
676 \r
677     /**\r
678      * Returns the number of the number of fraction digits that should\r
679      * be displayed for this currency.\r
680      * @return a non-negative number of fraction digits to be\r
681      * displayed\r
682      * @stable ICU 2.2\r
683      */\r
684     public int getDefaultFractionDigits() {\r
685         CurrencyMetaInfo info = CurrencyMetaInfo.getInstance();\r
686         CurrencyDigits digits = info.currencyDigits(isoCode);\r
687         return digits.fractionDigits;\r
688     }\r
689 \r
690     /**\r
691      * Returns the rounding increment for this currency, or 0.0 if no\r
692      * rounding is done by this currency.\r
693      * @return the non-negative rounding increment, or 0.0 if none\r
694      * @stable ICU 2.2\r
695      */\r
696     public double getRoundingIncrement() {\r
697         CurrencyMetaInfo info = CurrencyMetaInfo.getInstance();\r
698         CurrencyDigits digits = info.currencyDigits(isoCode);\r
699 \r
700         int data1 = digits.roundingIncrement;\r
701 \r
702         // If there is no rounding return 0.0 to indicate no rounding.\r
703         // This is the high-runner case, by far.\r
704         if (data1 == 0) {\r
705             return 0.0;\r
706         }\r
707 \r
708         int data0 = digits.fractionDigits;\r
709 \r
710         // If the meta data is invalid, return 0.0 to indicate no rounding.\r
711         if (data0 < 0 || data0 >= POW10.length) {\r
712             return 0.0;\r
713         }\r
714 \r
715         // Return data[1] / 10^(data[0]).  The only actual rounding data,\r
716         // as of this writing, is CHF { 2, 25 }.\r
717         return (double) data1 / POW10[data0];\r
718     }\r
719 \r
720     /**\r
721      * Returns the ISO 4217 code for this currency.\r
722      * @stable ICU 2.2\r
723      */\r
724     public String toString() {\r
725         return isoCode;\r
726     }\r
727 \r
728     /**\r
729      * Constructs a currency object for the given ISO 4217 3-letter\r
730      * code.  This constructor assumes that the code is valid.\r
731      * \r
732      * @param theISOCode The iso code used to construct the currency.\r
733      * @stable ICU 3.4\r
734      */\r
735     protected Currency(String theISOCode) {\r
736         isoCode = theISOCode;\r
737     }\r
738 \r
739     // POW10[i] = 10^i\r
740     private static final int[] POW10 = { \r
741         1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 \r
742     };\r
743 \r
744     // -------- BEGIN ULocale boilerplate --------\r
745 \r
746     /**\r
747      * Return the locale that was used to create this object, or null.\r
748      * This may may differ from the locale requested at the time of\r
749      * this object's creation.  For example, if an object is created\r
750      * for locale <tt>en_US_CALIFORNIA</tt>, the actual data may be\r
751      * drawn from <tt>en</tt> (the <i>actual</i> locale), and\r
752      * <tt>en_US</tt> may be the most specific locale that exists (the\r
753      * <i>valid</i> locale).\r
754      *\r
755      * <p>Note: This method will be obsoleted.  The implementation is\r
756      * no longer locale-specific and so there is no longer a valid or\r
757      * actual locale associated with the Currency object.  Until\r
758      * it is removed, this method will return the root locale.\r
759      * @param type type of information requested, either {@link\r
760      * com.ibm.icu.util.ULocale#VALID_LOCALE} or {@link\r
761      * com.ibm.icu.util.ULocale#ACTUAL_LOCALE}.\r
762      * @return the information specified by <i>type</i>, or null if\r
763      * this object was not constructed from locale data.\r
764      * @see com.ibm.icu.util.ULocale\r
765      * @see com.ibm.icu.util.ULocale#VALID_LOCALE\r
766      * @see com.ibm.icu.util.ULocale#ACTUAL_LOCALE\r
767      * @obsolete ICU 3.2 to be removed\r
768      * @deprecated This API is obsolete.\r
769      */\r
770     public final ULocale getLocale(ULocale.Type type) {\r
771         ULocale result = (type == ULocale.ACTUAL_LOCALE) ? actualLocale : validLocale;\r
772         if (result == null) {\r
773             return ULocale.ROOT;\r
774         }\r
775         return result;\r
776     }\r
777 \r
778     /**\r
779      * Set information about the locales that were used to create this\r
780      * object.  If the object was not constructed from locale data,\r
781      * both arguments should be set to null.  Otherwise, neither\r
782      * should be null.  The actual locale must be at the same level or\r
783      * less specific than the valid locale.  This method is intended\r
784      * for use by factories or other entities that create objects of\r
785      * this class.\r
786      * @param valid the most specific locale containing any resource\r
787      * data, or null\r
788      * @param actual the locale containing data used to construct this\r
789      * object, or null\r
790      * @see com.ibm.icu.util.ULocale\r
791      * @see com.ibm.icu.util.ULocale#VALID_LOCALE\r
792      * @see com.ibm.icu.util.ULocale#ACTUAL_LOCALE\r
793      */\r
794     final void setLocale(ULocale valid, ULocale actual) {\r
795         // Change the following to an assertion later\r
796         if ((valid == null) != (actual == null)) {\r
797             ///CLOVER:OFF\r
798             throw new IllegalArgumentException();\r
799             ///CLOVER:ON\r
800         }\r
801         // Another check we could do is that the actual locale is at\r
802         // the same level or less specific than the valid locale.\r
803         this.validLocale = valid;\r
804         this.actualLocale = actual;\r
805     }\r
806 \r
807     /*\r
808      * The most specific locale containing any resource data, or null.\r
809      */\r
810     private ULocale validLocale;\r
811 \r
812     /*\r
813      * The locale containing data used to construct this object, or null.\r
814      */\r
815     private ULocale actualLocale;\r
816 \r
817     // -------- END ULocale boilerplate --------\r
818 }\r
819 \r
820 //eof\r