17935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/**
27935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *******************************************************************************
37388b89454a914dd65a78a7fc321f60cd211561dFredrik Roubert * Copyright (C) 2001-2015, International Business Machines Corporation and
47388b89454a914dd65a78a7fc321f60cd211561dFredrik Roubert * others. All Rights Reserved.
57935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *******************************************************************************
67935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */
77935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpackage com.ibm.icu.util;
87935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
97935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.io.ObjectStreamException;
107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.lang.ref.SoftReference;
117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.text.ParsePosition;
127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.ArrayList;
137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Collections;
147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Date;
157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.HashMap;
167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.HashSet;
177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Iterator;
187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.List;
197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Locale;
207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Map;
217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.MissingResourceException;
227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Set;
237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.ICUCache;
257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.ICUDebug;
267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.ICUResourceBundle;
277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.SimpleCache;
287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.TextTrieMap;
297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.CurrencyDisplayNames;
307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.CurrencyMetaInfo;
317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.CurrencyMetaInfo.CurrencyDigits;
327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.CurrencyMetaInfo.CurrencyFilter;
337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.ULocale.Category;
347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/**
367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * A class encapsulating a currency, as defined by ISO 4217.  A
377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tt>Currency</tt> object can be created given a <tt>Locale</tt> or
387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * given an ISO 4217 code.  Once created, the <tt>Currency</tt> object
397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * can return various data necessary to its proper display:
407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *
417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <ul><li>A display symbol, for a specific locale
427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <li>The number of fraction digits to display
437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <li>A rounding increment
447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </ul>
457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *
467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The <tt>DecimalFormat</tt> class uses these data to display
477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * currencies.
487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *
497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>Note: This class deliberately resembles
507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tt>java.util.Currency</tt> but it has a completely independent
517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * implementation, and adds features not present in the JDK.
527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @author Alan Liu
537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 2.2
547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */
557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpublic class Currency extends MeasureUnit {
567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final long serialVersionUID = -5839973855554750484L;
577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final boolean DEBUG = ICUDebug.enabled("currency");
587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // Cache to save currency name trie
607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static ICUCache<ULocale, List<TextTrieMap<CurrencyStringInfo>>> CURRENCY_NAME_CACHE =
617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        new SimpleCache<ULocale, List<TextTrieMap<CurrencyStringInfo>>>();
627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Selector for getName() indicating a symbolic name for a
657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * currency, such as "$" for USD.
667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.6
677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static final int SYMBOL_NAME = 0;
697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Selector for getName() indicating the long name for a
727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * currency, such as "US Dollar" for USD.
737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.6
747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static final int LONG_NAME = 1;
767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Selector for getName() indicating the plural long name for a
797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * currency, such as "US dollar" for USD in "1 US dollar",
807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * and "US dollars" for USD in "2 US dollars".
817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 4.2
827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static final int PLURAL_LONG_NAME = 2;
847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final EquivalenceRelation<String> EQUIVALENT_CURRENCY_SYMBOLS =
867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            new EquivalenceRelation<String>()
877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            .add("\u00a5", "\uffe5")
887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            .add("$", "\ufe69", "\uff04")
897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            .add("\u20a8", "\u20b9")
907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            .add("\u00a3", "\u20a4");
917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Currency Usage used for Decimal Format
947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @draft ICU 54
957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @provisional This API might change or be removed in a future release.
967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public enum CurrencyUsage{
987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /**
997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * a setting to specify currency usage which determines currency digit and rounding
1007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * for standard usage, for example: "50.00 NT$"
1017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * @draft ICU 54
1027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * @provisional This API might change or be removed in a future release.
1037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         */
1047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        STANDARD,
1057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /**
1077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * a setting to specify currency usage which determines currency digit and rounding
1087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * for cash usage, for example: "50 NT$"
1097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * @draft ICU 54
1107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * @provisional This API might change or be removed in a future release.
1117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         */
1127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        CASH
1137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // begin registry stuff
1167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // shim for service code
1187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /* package */ static abstract class ServiceShim {
1197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        abstract ULocale[] getAvailableULocales();
1207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        abstract Locale[] getAvailableLocales();
1217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        abstract Currency createInstance(ULocale l);
1227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        abstract Object registerInstance(Currency c, ULocale l);
1237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        abstract boolean unregister(Object f);
1247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static ServiceShim shim;
1277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static ServiceShim getShim() {
1287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Note: this instantiation is safe on loose-memory-model configurations
1297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // despite lack of synchronization, since the shim instance has no state--
1307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // it's all in the class init.  The worst problem is we might instantiate
1317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // two shim instances, but they'll share the same state so that's ok.
1327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (shim == null) {
1337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            try {
1347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                Class<?> cls = Class.forName("com.ibm.icu.util.CurrencyServiceShim");
1357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                shim = (ServiceShim)cls.newInstance();
1367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
1377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            catch (Exception e) {
1387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if(DEBUG){
1397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    e.printStackTrace();
1407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
1417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                throw new RuntimeException(e.getMessage());
1427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
1437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
1447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return shim;
1457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
1487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returns a currency object for the default currency in the given
1497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * locale.
1507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param locale the locale
1517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return the currency object for this locale
1527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.2
1537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
1547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static Currency getInstance(Locale locale) {
1557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return getInstance(ULocale.forLocale(locale));
1567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
1597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returns a currency object for the default currency in the given
1607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * locale.
1617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.2
1627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
1637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static Currency getInstance(ULocale locale) {
1647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        String currency = locale.getKeywordValue("currency");
1657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (currency != null) {
1667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return getInstance(currency);
1677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
1687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (shim == null) {
1707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return createCurrency(locale);
1717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
1727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return shim.createInstance(locale);
1747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
1777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returns an array of Strings which contain the currency
1787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * identifiers that are valid for the given locale on the
1797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * given date.  If there are no such identifiers, returns null.
1807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returned identifiers are in preference order.
1817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param loc the locale for which to retrieve currency codes.
1827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param d the date for which to retrieve currency codes for the given locale.
1837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return The array of ISO currency codes.
1847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 4.0
1857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
1867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static String[] getAvailableCurrencyCodes(ULocale loc, Date d) {
1877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        CurrencyFilter filter = CurrencyFilter.onDate(d).withRegion(loc.getCountry());
1887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        List<String> list = getTenderCurrencies(filter);
1897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Note: Prior to 4.4 the spec didn't say that we return null if there are no results, but
1907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // the test assumed it did.  Kept the behavior and amended the spec.
1917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (list.isEmpty()) {
1927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return null;
1937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
1947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return list.toArray(new String[list.size()]);
1957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
1987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returns an array of Strings which contain the currency
1997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * identifiers that are valid for the given JDK locale on the
2007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * given date.  If there are no such identifiers, returns null.
2017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returned identifiers are in preference order.
2027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param loc the JDK locale for which to retrieve currency codes.
2037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param d the date for which to retrieve currency codes for the given locale.
2047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return The array of ISO currency codes.
2057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @draft ICU 54
2067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @provisional This API might change or be removed in a future release.
2077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
2087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static String[] getAvailableCurrencyCodes(Locale loc, Date d) {
2097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return getAvailableCurrencyCodes(ULocale.forLocale(loc), d);
2107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
2117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
2137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returns the set of available currencies. The returned set of currencies contains all of the
2147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * available currencies, including obsolete ones. The result set can be modified without
2157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * affecting the available currencies in the runtime.
2167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
2177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return The set of available currencies. The returned set could be empty if there is no
2187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * currency data available.
2197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
2207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 49
2217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
2227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static Set<Currency> getAvailableCurrencies() {
2237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        CurrencyMetaInfo info = CurrencyMetaInfo.getInstance();
2247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        List<String> list = info.currencies(CurrencyFilter.all());
2257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        HashSet<Currency> resultSet = new HashSet<Currency>(list.size());
2267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        for (String code : list) {
2277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            resultSet.add(getInstance(code));
2287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return resultSet;
2307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
2317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final String EUR_STR = "EUR";
2337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final ICUCache<ULocale, String> currencyCodeCache = new SimpleCache<ULocale, String>();
2347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
2367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Instantiate a currency from resource data.
2377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
2387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /* package */ static Currency createCurrency(ULocale loc) {
2397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        String variant = loc.getVariant();
2417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if ("EURO".equals(variant)) {
2427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return getInstance(EUR_STR);
2437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        String code = currencyCodeCache.get(loc);
2467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (code == null) {
2477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            String country = loc.getCountry();
2487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            CurrencyMetaInfo info = CurrencyMetaInfo.getInstance();
2507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            List<String> list = info.currencies(CurrencyFilter.onRegion(country));
2517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (list.size() > 0) {
2527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                code = list.get(0);
2537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                boolean isPreEuro = "PREEURO".equals(variant);
2547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (isPreEuro && EUR_STR.equals(code)) {
2557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (list.size() < 2) {
2567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        return null;
2577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
2587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    code = list.get(1);
2597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
2607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else {
2617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return null;
2627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
2637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            currencyCodeCache.put(loc, code);
2647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return getInstance(code);
2667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
2677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
2697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returns a currency object given an ISO 4217 3-letter code.
2707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param theISOCode the iso code
2717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return the currency for this iso code
2727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @throws NullPointerException if <code>theISOCode</code> is null.
2737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @throws IllegalArgumentException if <code>theISOCode</code> is not a
2747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *         3-letter alpha code.
2757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.2
2767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
2777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static Currency getInstance(String theISOCode) {
2787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (theISOCode == null) {
2797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            throw new NullPointerException("The input currency code is null.");
2807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (!isAlpha3Code(theISOCode)) {
2827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            throw new IllegalArgumentException(
2837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    "The input currency code is not 3-letter alphabetic code.");
2847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return (Currency) MeasureUnit.internalGetInstance("currency", theISOCode.toUpperCase(Locale.ENGLISH));
2867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
2877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static boolean isAlpha3Code(String code) {
2907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (code.length() != 3) {
2917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return false;
2927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } else {
2937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            for (int i = 0; i < 3; i++) {
2947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                char ch = code.charAt(i);
2957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (ch < 'A' || (ch > 'Z' && ch < 'a') || ch > 'z') {
2967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    return false;
2977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
2987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
2997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
3007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return true;
3017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
3027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
3047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Registers a new currency for the provided locale.  The returned object
3057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * is a key that can be used to unregister this currency object.
3067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
3077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <p>Because ICU may choose to cache Currency objects internally, this must
3087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * be called at application startup, prior to any calls to
3097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Currency.getInstance to avoid undefined behavior.
3107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
3117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param currency the currency to register
3127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param locale the ulocale under which to register the currency
3137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return a registry key that can be used to unregister this currency
3147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @see #unregister
3157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.2
3167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
3177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static Object registerInstance(Currency currency, ULocale locale) {
3187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return getShim().registerInstance(currency, locale);
3197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
3207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
3227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Unregister the currency associated with this key (obtained from
3237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * registerInstance).
3247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param registryKey the registry key returned from registerInstance
3257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @see #registerInstance
3267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.6
3277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
3287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static boolean unregister(Object registryKey) {
3297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (registryKey == null) {
3307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            throw new IllegalArgumentException("registryKey must not be null");
3317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
3327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (shim == null) {
3337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return false;
3347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
3357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return shim.unregister(registryKey);
3367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
3377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
3397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Return an array of the locales for which a currency
3407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * is defined.
3417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return an array of the available locales
3427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.2
3437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
3447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static Locale[] getAvailableLocales() {
3457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (shim == null) {
3467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return ICUResourceBundle.getAvailableLocales();
3477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } else {
3487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return shim.getAvailableLocales();
3497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
3507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
3517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
3537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Return an array of the ulocales for which a currency
3547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * is defined.
3557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return an array of the available ulocales
3567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.2
3577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
3587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static ULocale[] getAvailableULocales() {
3597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (shim == null) {
3607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return ICUResourceBundle.getAvailableULocales();
3617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } else {
3627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return shim.getAvailableULocales();
3637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
3647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
3657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // end registry stuff
3677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
3697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Given a key and a locale, returns an array of values for the key for which data
3707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * exists.  If commonlyUsed is true, these are the values that typically are used
3717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * with this locale, otherwise these are all values for which data exists.
3727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * This is a common service API.
3737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <p>
3747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * The only supported key is "currency", other values return an empty array.
3757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <p>
3767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Currency information is based on the region of the locale.  If the locale does not
3777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * indicate a region, {@link ULocale#addLikelySubtags(ULocale)} is used to infer a region,
3787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * except for the 'und' locale.
3797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <p>
3807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * If commonlyUsed is true, only the currencies known to be in use as of the current date
3817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * are returned.  When there are more than one, these are returned in preference order
3827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * (typically, this occurs when a country is transitioning to a new currency, and the
3837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * newer currency is preferred), see
3847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <a href="http://unicode.org/reports/tr35/#Supplemental_Currency_Data">Unicode TR#35 Sec. C1</a>.
3857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * If commonlyUsed is false, all currencies ever used in any locale are returned, in no
3867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * particular order.
3877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
3887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param key           key whose values to look up.  the only recognized key is "currency"
3897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param locale        the locale
3907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param commonlyUsed  if true, return only values that are currently used in the locale.
3917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                      Otherwise returns all values.
3927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return an array of values for the given key and the locale.  If there is no data, the
3937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *   array will be empty.
3947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 4.2
3957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
3967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static final String[] getKeywordValuesForLocale(String key, ULocale locale,
3977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            boolean commonlyUsed) {
3987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // The only keyword we recognize is 'currency'
4007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (!"currency".equals(key)) {
4017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return EMPTY_STRING_ARRAY;
4027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
4037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
4047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (!commonlyUsed) {
4057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // Behavior change from 4.3.3, no longer sort the currencies
4067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return getAllTenderCurrencies().toArray(new String[0]);
4077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
4087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
4097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Don't resolve region if the requested locale is 'und', it will resolve to US
4107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // which we don't want.
4117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        String prefRegion = locale.getCountry();
4127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (prefRegion.length() == 0) {
4137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (UND.equals(locale)) {
4147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return EMPTY_STRING_ARRAY;
4157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
4167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            ULocale loc = ULocale.addLikelySubtags(locale);
4177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            prefRegion = loc.getCountry();
4187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert       }
4197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
4207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        CurrencyFilter filter = CurrencyFilter.now().withRegion(prefRegion);
4217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
4227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // currencies are in region's preferred order when we're filtering on region, which
4237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // matches our spec
4247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        List<String> result = getTenderCurrencies(filter);
4257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
4267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // No fallback anymore (change from 4.3.3)
4277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (result.size() == 0) {
4287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return EMPTY_STRING_ARRAY;
4297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
4307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
4317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return result.toArray(new String[result.size()]);
4327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
4337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
4347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final ULocale UND = new ULocale("und");
4357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final String[] EMPTY_STRING_ARRAY = new String[0];
4367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
4377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
4387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returns the ISO 4217 3-letter code for this currency object.
4397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.2
4407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
4417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public String getCurrencyCode() {
4427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return subType;
4437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
4447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
4457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
4467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returns the ISO 4217 numeric code for this currency object.
4477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <p>Note: If the ISO 4217 numeric code is not assigned for the currency or
4487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * the currency is unknown, this method returns 0.</p>
4497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return The ISO 4217 numeric code of this currency.
4507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 49
4517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
4527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public int getNumericCode() {
4537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int result = 0;
4547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        try {
4557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            UResourceBundle bundle = UResourceBundle.getBundleInstance(
4567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    ICUResourceBundle.ICU_BASE_NAME,
4577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    "currencyNumericCodes",
4587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    ICUResourceBundle.ICU_DATA_CLASS_LOADER);
4597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            UResourceBundle codeMap = bundle.get("codeMap");
4607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            UResourceBundle numCode = codeMap.get(subType);
4617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            result = numCode.getInt();
4627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } catch (MissingResourceException e) {
4637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // fall through
4647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
4657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return result;
4667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
4677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
4687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
4697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Convenience and compatibility override of getName that
4707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * requests the symbol name for the default <code>DISPLAY</code> locale.
4717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @see #getName
4727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @see Category#DISPLAY
4737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.4
4747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
4757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public String getSymbol() {
4767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return getSymbol(ULocale.getDefault(Category.DISPLAY));
4777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
4787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
4797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
4807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Convenience and compatibility override of getName that
4817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * requests the symbol name.
4827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param loc the Locale for the symbol
4837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @see #getName
4847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.4
4857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
4867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public String getSymbol(Locale loc) {
4877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return getSymbol(ULocale.forLocale(loc));
4887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
4897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
4907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
4917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Convenience and compatibility override of getName that
4927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * requests the symbol name.
4937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param uloc the ULocale for the symbol
4947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @see #getName
4957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.4
4967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
4977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public String getSymbol(ULocale uloc) {
4987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return getName(uloc, SYMBOL_NAME, new boolean[1]);
4997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
5007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
5017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
5027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returns the display name for the given currency in the
5037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * given locale.
5047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * This is a convenient method for
5057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * getName(ULocale, int, boolean[]);
5067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.2
5077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
5087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public String getName(Locale locale,
5097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                          int nameStyle,
5107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                          boolean[] isChoiceFormat) {
5117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return getName(ULocale.forLocale(locale), nameStyle, isChoiceFormat);
5127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
5137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
5147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
5157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returns the display name for the given currency in the
5167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * given locale.  For example, the display name for the USD
5177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * currency object in the en_US locale is "$".
5187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param locale locale in which to display currency
5197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param nameStyle selector for which kind of name to return.
5207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                  The nameStyle should be either SYMBOL_NAME or
5217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                  LONG_NAME. Otherwise, throw IllegalArgumentException.
5227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param isChoiceFormat fill-in; isChoiceFormat[0] is set to true
5237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * if the returned value is a ChoiceFormat pattern; otherwise it
5247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * is set to false
5257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return display string for this currency.  If the resource data
5267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * contains no entry for this currency, then the ISO 4217 code is
5277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * returned.  If isChoiceFormat[0] is true, then the result is a
5287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * ChoiceFormat pattern.  Otherwise it is a static string. <b>Note:</b>
5297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * as of ICU 4.4, choice formats are not used, and the value returned
5307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * in isChoiceFormat is always false.
5317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <p>
5327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @throws  IllegalArgumentException  if the nameStyle is not SYMBOL_NAME
5337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                                    or LONG_NAME.
5347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @see #getName(ULocale, int, String, boolean[])
5357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.2
5367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
5377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public String getName(ULocale locale, int nameStyle, boolean[] isChoiceFormat) {
5387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (!(nameStyle == SYMBOL_NAME || nameStyle == LONG_NAME)) {
5397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            throw new IllegalArgumentException("bad name style: " + nameStyle);
5407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
5417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
5427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // We no longer support choice format data in names.  Data should not contain
5437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // choice patterns.
5447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (isChoiceFormat != null) {
5457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            isChoiceFormat[0] = false;
5467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
5477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
5487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        CurrencyDisplayNames names = CurrencyDisplayNames.getInstance(locale);
5497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return nameStyle == SYMBOL_NAME ? names.getSymbol(subType) : names.getName(subType);
5507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
5517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
5527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
5537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returns the display name for the given currency in the given locale.
5547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * This is a convenience overload of getName(ULocale, int, String, boolean[]);
5557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 4.2
5567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
5577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public String getName(Locale locale, int nameStyle, String pluralCount,
5587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            boolean[] isChoiceFormat) {
5597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return getName(ULocale.forLocale(locale), nameStyle, pluralCount, isChoiceFormat);
5607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
5617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
5627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
5637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returns the display name for the given currency in the
5647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * given locale.  For example, the SYMBOL_NAME for the USD
5657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * currency object in the en_US locale is "$".
5667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * The PLURAL_LONG_NAME for the USD currency object when the currency
5677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * amount is plural is "US dollars", such as in "3.00 US dollars";
5687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * while the PLURAL_LONG_NAME for the USD currency object when the currency
5697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * amount is singular is "US dollar", such as in "1.00 US dollar".
5707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param locale locale in which to display currency
5717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param nameStyle selector for which kind of name to return
5727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param pluralCount plural count string for this locale
5737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param isChoiceFormat fill-in; isChoiceFormat[0] is set to true
5747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * if the returned value is a ChoiceFormat pattern; otherwise it
5757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * is set to false
5767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return display string for this currency.  If the resource data
5777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * contains no entry for this currency, then the ISO 4217 code is
5787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * returned.  If isChoiceFormat[0] is true, then the result is a
5797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * ChoiceFormat pattern.  Otherwise it is a static string. <b>Note:</b>
5807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * as of ICU 4.4, choice formats are not used, and the value returned
5817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * in isChoiceFormat is always false.
5827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @throws  IllegalArgumentException  if the nameStyle is not SYMBOL_NAME,
5837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                                    LONG_NAME, or PLURAL_LONG_NAME.
5847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 4.2
5857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
5867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public String getName(ULocale locale, int nameStyle, String pluralCount,
5877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            boolean[] isChoiceFormat) {
5887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (nameStyle != PLURAL_LONG_NAME) {
5897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return getName(locale, nameStyle, isChoiceFormat);
5907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
5917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
5927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // We no longer support choice format
5937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (isChoiceFormat != null) {
5947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            isChoiceFormat[0] = false;
5957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
5967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
5977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        CurrencyDisplayNames names = CurrencyDisplayNames.getInstance(locale);
5987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return names.getPluralName(subType, pluralCount);
5997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
6007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
6017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
6027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returns the display name for this currency in the default locale.
6037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * If the resource data for the default locale contains no entry for this currency,
6047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * then the ISO 4217 code is returned.
6057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <p>
6067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Note: This method was added for JDK compatibility support and equivalent to
6077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <code>getName(Locale.getDefault(), LONG_NAME, null)</code>.
6087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
6097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return The display name of this currency
6107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @see #getDisplayName(Locale)
6117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @see #getName(Locale, int, boolean[])
6127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 49
6137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
6147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public String getDisplayName() {
6157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return getName(Locale.getDefault(), LONG_NAME, null);
6167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
6177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
6187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
6197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returns the display name for this currency in the given locale.
6207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * If the resource data for the given locale contains no entry for this currency,
6217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * then the ISO 4217 code is returned.
6227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <p>
6237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Note: This method was added for JDK compatibility support and equivalent to
6247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <code>getName(locale, LONG_NAME, null)</code>.
6257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
6267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param locale locale in which to display currency
6277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return The display name of this currency for the specified locale
6287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @see #getDisplayName(Locale)
6297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @see #getName(Locale, int, boolean[])
6307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 49
6317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
6327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public String getDisplayName(Locale locale) {
6337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return getName(locale, LONG_NAME, null);
6347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
6357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
6367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
6377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Attempt to parse the given string as a currency, either as a
6387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * display name in the given locale, or as a 3-letter ISO 4217
6397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * code.  If multiple display names match, then the longest one is
6407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * selected.  If both a display name and a 3-letter ISO code
6417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * match, then the display name is preferred, unless it's length
6427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * is less than 3.
6437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
6447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param locale the locale of the display names to match
6457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param text the text to parse
6467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param type parse against currency type: LONG_NAME only or not
6477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param pos input-output position; on input, the position within
6487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * text to match; must have 0 <= pos.getIndex() < text.length();
6497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * on output, the position after the last matched character. If
6507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * the parse fails, the position in unchanged upon output.
6517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return the ISO 4217 code, as a string, of the best match, or
6527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * null if there is no match
6537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
6547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @internal
6557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @deprecated This API is ICU internal only.
6567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
6577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @Deprecated
6587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static String parse(ULocale locale, String text, int type, ParsePosition pos) {
6597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        List<TextTrieMap<CurrencyStringInfo>> currencyTrieVec = CURRENCY_NAME_CACHE.get(locale);
6607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (currencyTrieVec == null) {
6617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            TextTrieMap<CurrencyStringInfo> currencyNameTrie =
6627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                new TextTrieMap<CurrencyStringInfo>(true);
6637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            TextTrieMap<CurrencyStringInfo> currencySymbolTrie =
6647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                new TextTrieMap<CurrencyStringInfo>(false);
6657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            currencyTrieVec = new ArrayList<TextTrieMap<CurrencyStringInfo>>();
6667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            currencyTrieVec.add(currencySymbolTrie);
6677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            currencyTrieVec.add(currencyNameTrie);
6687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            setupCurrencyTrieVec(locale, currencyTrieVec);
6697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            CURRENCY_NAME_CACHE.put(locale, currencyTrieVec);
6707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
6717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
6727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int maxLength = 0;
6737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        String isoResult = null;
6747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
6757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          // look for the names
6767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        TextTrieMap<CurrencyStringInfo> currencyNameTrie = currencyTrieVec.get(1);
6777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        CurrencyNameResultHandler handler = new CurrencyNameResultHandler();
6787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        currencyNameTrie.find(text, pos.getIndex(), handler);
6797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        isoResult = handler.getBestCurrencyISOCode();
6807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        maxLength = handler.getBestMatchLength();
6817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
6827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (type != Currency.LONG_NAME) {  // not long name only
6837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            TextTrieMap<CurrencyStringInfo> currencySymbolTrie = currencyTrieVec.get(0);
6847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            handler = new CurrencyNameResultHandler();
6857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            currencySymbolTrie.find(text, pos.getIndex(), handler);
6867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (handler.getBestMatchLength() > maxLength) {
6877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                isoResult = handler.getBestCurrencyISOCode();
6887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                maxLength = handler.getBestMatchLength();
6897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
6907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
6917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int start = pos.getIndex();
6927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        pos.setIndex(start + maxLength);
6937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return isoResult;
6947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
6957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
6967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static void setupCurrencyTrieVec(ULocale locale,
6977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            List<TextTrieMap<CurrencyStringInfo>> trieVec) {
6987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
6997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        TextTrieMap<CurrencyStringInfo> symTrie = trieVec.get(0);
7007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        TextTrieMap<CurrencyStringInfo> trie = trieVec.get(1);
7017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
7027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        CurrencyDisplayNames names = CurrencyDisplayNames.getInstance(locale);
7037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        for (Map.Entry<String, String> e : names.symbolMap().entrySet()) {
7047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            String symbol = e.getKey();
7057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            String isoCode = e.getValue();
7067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // Register under not just symbol, but under every equivalent symbol as well
7077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // e.g short width yen and long width yen.
7087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            for (String equivalentSymbol : EQUIVALENT_CURRENCY_SYMBOLS.get(symbol)) {
7097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                symTrie.put(equivalentSymbol, new CurrencyStringInfo(isoCode, symbol));
7107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
7117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
7127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        for (Map.Entry<String, String> e : names.nameMap().entrySet()) {
7137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            String name = e.getKey();
7147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            String isoCode = e.getValue();
7157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            trie.put(name, new CurrencyStringInfo(isoCode, name));
7167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
7177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
7187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
7197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final class CurrencyStringInfo {
7207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        private String isoCode;
7217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        private String currencyString;
7227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
7237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        public CurrencyStringInfo(String isoCode, String currencyString) {
7247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            this.isoCode = isoCode;
7257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            this.currencyString = currencyString;
7267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
7277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
7287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        public String getISOCode() {
7297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return isoCode;
7307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
7317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
7327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        @SuppressWarnings("unused")
7337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        public String getCurrencyString() {
7347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return currencyString;
7357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
7367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
7377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
7387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static class CurrencyNameResultHandler
7397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            implements TextTrieMap.ResultHandler<CurrencyStringInfo> {
7407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // The length of longest matching key
7417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        private int bestMatchLength;
7427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // The currency ISO code of longest matching key
7437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        private String bestCurrencyISOCode;
7447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
7457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // As the trie is traversed, handlePrefixMatch is called at each node. matchLength is the
7467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // length length of the key at the current node; values is the list of all the values mapped to
7477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // that key. matchLength increases with each call as trie is traversed.
7487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        public boolean handlePrefixMatch(int matchLength, Iterator<CurrencyStringInfo> values) {
7497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (values.hasNext()) {
7507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // Since the best match criteria is only based on length of key in trie and since all the
7517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // values are mapped to the same key, we only need to examine the first value.
7527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                bestCurrencyISOCode = values.next().getISOCode();
7537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                bestMatchLength = matchLength;
7547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
7557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return true;
7567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
7577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
7587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        public String getBestCurrencyISOCode() {
7597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return bestCurrencyISOCode;
7607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
7617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
7627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        public int getBestMatchLength() {
7637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return bestMatchLength;
7647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
7657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
7667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
7677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
7687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returns the number of the number of fraction digits that should
7697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * be displayed for this currency.
7707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * This is equivalent to getDefaultFractionDigits(CurrencyUsage.STANDARD);
7717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return a non-negative number of fraction digits to be
7727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * displayed
7737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.2
7747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
7757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public int getDefaultFractionDigits() {
7767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return getDefaultFractionDigits(CurrencyUsage.STANDARD);
7777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
7787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
7797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
7807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returns the number of the number of fraction digits that should
7817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * be displayed for this currency with Usage.
7827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param Usage the usage of currency(Standard or Cash)
7837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return a non-negative number of fraction digits to be
7847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * displayed
7857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @draft ICU 54
7867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @provisional This API might change or be removed in a future release.
7877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
7887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public int getDefaultFractionDigits(CurrencyUsage Usage) {
7897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        CurrencyMetaInfo info = CurrencyMetaInfo.getInstance();
7907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        CurrencyDigits digits = info.currencyDigits(subType, Usage);
7917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return digits.fractionDigits;
7927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
7937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
7947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
7957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returns the rounding increment for this currency, or 0.0 if no
7967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * rounding is done by this currency.
7977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * This is equivalent to getRoundingIncrement(CurrencyUsage.STANDARD);
7987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return the non-negative rounding increment, or 0.0 if none
7997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.2
8007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
8017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public double getRoundingIncrement() {
8027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return getRoundingIncrement(CurrencyUsage.STANDARD);
8037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
8047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
8067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returns the rounding increment for this currency, or 0.0 if no
8077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * rounding is done by this currency with the Usage.
8087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param Usage the usage of currency(Standard or Cash)
8097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return the non-negative rounding increment, or 0.0 if none
8107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @draft ICU 54
8117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @provisional This API might change or be removed in a future release.
8127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
8137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public double getRoundingIncrement(CurrencyUsage Usage) {
8147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        CurrencyMetaInfo info = CurrencyMetaInfo.getInstance();
8157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        CurrencyDigits digits = info.currencyDigits(subType, Usage);
8167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int data1 = digits.roundingIncrement;
8187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // If there is no rounding return 0.0 to indicate no rounding.
8207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // This is the high-runner case, by far.
8217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (data1 == 0) {
8227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return 0.0;
8237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
8247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int data0 = digits.fractionDigits;
8267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // If the meta data is invalid, return 0.0 to indicate no rounding.
8287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (data0 < 0 || data0 >= POW10.length) {
8297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return 0.0;
8307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
8317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Return data[1] / 10^(data[0]). The only actual rounding data,
8337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // as of this writing, is CHF { 2, 25 }.
8347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return (double) data1 / POW10[data0];
8357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
8367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
8387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returns the ISO 4217 code for this currency.
8397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.2
8407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
8417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public String toString() {
8427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return subType;
8437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
8447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
8467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Constructs a currency object for the given ISO 4217 3-letter
8477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * code.  This constructor assumes that the code is valid.
8487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
8497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param theISOCode The iso code used to construct the currency.
8507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.4
8517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
8527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    protected Currency(String theISOCode) {
8537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        super("currency", theISOCode);
8547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // isoCode is kept for readResolve() and Currency class no longer
8567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // use it. So this statement actually does not have any effect.
8577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        isoCode = theISOCode;
8587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
8597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // POW10[i] = 10^i
8617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final int[] POW10 = {
8627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000
8637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    };
8647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static SoftReference<List<String>> ALL_TENDER_CODES;
8677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static SoftReference<Set<String>> ALL_CODES_AS_SET;
8687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /*
8697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returns an unmodifiable String list including all known tender currency codes.
8707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
8717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static synchronized List<String> getAllTenderCurrencies() {
8727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        List<String> all = (ALL_TENDER_CODES == null) ? null : ALL_TENDER_CODES.get();
8737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (all == null) {
8747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // Filter out non-tender currencies which have "from" date set to 9999-12-31
8757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // CurrencyFilter has "to" value set to 9998-12-31 in order to exclude them
8767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            //CurrencyFilter filter = CurrencyFilter.onDateRange(null, new Date(253373299200000L));
8777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            CurrencyFilter filter = CurrencyFilter.all();
8787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            all = Collections.unmodifiableList(getTenderCurrencies(filter));
8797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            ALL_TENDER_CODES = new SoftReference<List<String>>(all);
8807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
8817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return all;
8827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
8837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static synchronized Set<String> getAllCurrenciesAsSet() {
8857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        Set<String> all = (ALL_CODES_AS_SET == null) ? null : ALL_CODES_AS_SET.get();
8867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (all == null) {
8877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            CurrencyMetaInfo info = CurrencyMetaInfo.getInstance();
8887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            all = Collections.unmodifiableSet(
8897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    new HashSet<String>(info.currencies(CurrencyFilter.all())));
8907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            ALL_CODES_AS_SET = new SoftReference<Set<String>>(all);
8917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
8927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return all;
8937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
8947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
8967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Queries if the given ISO 4217 3-letter code is available on the specified date range.
8977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <p>
8987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Note: For checking availability of a currency on a specific date, specify the date on both <code>from</code> and
8997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <code>to</code>. When both <code>from</code> and <code>to</code> are null, this method checks if the specified
9007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * currency is available all time.
9017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
9027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param code
9037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *            The ISO 4217 3-letter code.
9047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param from
9057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *            The lower bound of the date range, inclusive. When <code>from</code> is null, check the availability
9067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *            of the currency any date before <code>to</code>
9077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param to
9087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *            The upper bound of the date range, inclusive. When <code>to</code> is null, check the availability of
9097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *            the currency any date after <code>from</code>
9107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return true if the given ISO 4217 3-letter code is supported on the specified date range.
9117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @throws IllegalArgumentException when <code>to</code> is before <code>from</code>.
9127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
9137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 4.6
9147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
9157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static boolean isAvailable(String code, Date from, Date to) {
9167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (!isAlpha3Code(code)) {
9177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return false;
9187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
9197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
9207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (from != null && to != null && from.after(to)) {
9217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            throw new IllegalArgumentException("To is before from");
9227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
9237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
9247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        code = code.toUpperCase(Locale.ENGLISH);
9257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        boolean isKnown = getAllCurrenciesAsSet().contains(code);
9267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (isKnown == false) {
9277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return false;
9287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } else if (from == null && to == null) {
9297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return true;
9307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
9317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
9327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // If caller passed a date range, we cannot rely solely on the cache
9337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        CurrencyMetaInfo info = CurrencyMetaInfo.getInstance();
9347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        List<String> allActive = info.currencies(
9357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                CurrencyFilter.onDateRange(from, to).withCurrency(code));
9367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return allActive.contains(code);
9377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
9387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
9397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
9407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returns the list of remaining tender currencies after a filter is applied.
9417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param filter the filter to apply to the tender currencies
9427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return a list of tender currencies
9437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
9447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static List<String> getTenderCurrencies(CurrencyFilter filter) {
9457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        CurrencyMetaInfo info = CurrencyMetaInfo.getInstance();
9467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return info.currencies(filter.withTender());
9477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
9487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
9497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final class EquivalenceRelation<T> {
9507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
9517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        private Map<T, Set<T>> data = new HashMap<T, Set<T>>();
9527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
9537388b89454a914dd65a78a7fc321f60cd211561dFredrik Roubert        @SuppressWarnings("unchecked")  // See ticket #11395, this is safe.
9547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        public EquivalenceRelation<T> add(T... items) {
9557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            Set<T> group = new HashSet<T>();
9567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            for (T item : items) {
9577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (data.containsKey(item)) {
9587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    throw new IllegalArgumentException("All groups passed to add must be disjoint.");
9597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
9607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                group.add(item);
9617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
9627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            for (T item : items) {
9637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                data.put(item, group);
9647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
9657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return this;
9667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
9677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
9687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        public Set<T> get(T item) {
9697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            Set<T> result = data.get(item);
9707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (result == null) {
9717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return Collections.singleton(item);
9727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
9737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return Collections.unmodifiableSet(result);
9747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
9757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
9767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
9777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private Object writeReplace() throws ObjectStreamException {
9787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return new MeasureUnitProxy(type, subType);
9797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
9807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
9817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // For backward compatibility only
9827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
9837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * ISO 4217 3-letter code.
9847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
9857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private final String isoCode;
9867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
9877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private Object readResolve() throws ObjectStreamException {
9887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // The old isoCode field used to determine the currency.
9897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return Currency.getInstance(isoCode);
9907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
9917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert}
9927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert//eof
993