/**
   * Returns a name for the locale's country that is appropriate for display to the user. If
   * possible, the name returned will be localized according to inLocale. For example, if the locale
   * is fr_FR and inLocale is en_US, getDisplayCountry() will return "France"; if the locale is
   * en_US and inLocale is fr_FR, getDisplayLanguage() will return "Etats-Unis". If the name
   * returned cannot be localized according to inLocale. (say, we don't have a Japanese name for
   * Croatia), this function falls back on the default locale, on the English name, and finally on
   * the ISO code as a last-resort value. If the locale doesn't specify a country, this function
   * returns the empty string.
   */
  public String getDisplayCountry(Locale inLocale) {
    String ctryCode = country;
    if (ctryCode.length() == 0) return "";

    Locale workingLocale = (Locale) inLocale.clone();
    String result = null;
    int phase = 0;
    boolean done = false;

    if (workingLocale.variant.length() == 0) phase = 1;
    if (workingLocale.country.length() == 0) phase = 2;

    while (!done) {
      try {
        ResourceBundle bundle = LocaleData.getLocaleElements(workingLocale);
        result = findStringMatch((String[][]) bundle.getObject("Countries"), ctryCode, ctryCode);
        if (result.length() != 0) done = true;
      } catch (Exception e) {
        // just fall through
      }

      if (!done) {
        switch (phase) {
          case 0:
            workingLocale = new Locale(workingLocale.language, workingLocale.country, "");
            break;

          case 1:
            workingLocale = new Locale(workingLocale.language, "", workingLocale.variant);
            break;

          case 2:
            workingLocale = getDefault();
            break;

          case 3:
            workingLocale = new Locale("", "", "");
            break;

          default:
            return ctryCode;
        }
        phase++;
      }
    }
    return result;
  }
  /**
   * Returns a name for the locale's variant code that is appropriate for display to the user. If
   * possible, the name will be localized for inLocale. If the locale doesn't specify a variant
   * code, this function returns the empty string.
   */
  public String getDisplayVariant(Locale inLocale) {
    if (variant.length() == 0) return "";

    ResourceBundle bundle = LocaleData.getLocaleElements(inLocale);

    String names[] = getDisplayVariantArray(bundle);

    // Get the localized patterns for formatting a list, and use
    // them to format the list.
    String[] patterns;
    try {
      patterns = (String[]) bundle.getObject("LocaleNamePatterns");
    } catch (MissingResourceException e) {
      patterns = null;
    }
    return formatList(patterns, names);
  }
  /** Initializes the symbols from the LocaleElements resource bundle. */
  private void initialize(Locale locale) {
    this.locale = locale;

    // get resource bundle data - try the cache first
    boolean needCacheUpdate = false;
    Object[] data = (Object[]) cachedLocaleData.get(locale);
    if (data == null) {
        /* cache miss */
      data = new Object[3];
      ResourceBundle rb = LocaleData.getLocaleElements(locale);
      data[0] = rb.getStringArray("NumberElements");
      needCacheUpdate = true;
    }

    String[] numberElements = (String[]) data[0];
    ;

    decimalSeparator = numberElements[0].charAt(0);
    groupingSeparator = numberElements[1].charAt(0);
    patternSeparator = numberElements[2].charAt(0);
    percent = numberElements[3].charAt(0);
    zeroDigit = numberElements[4].charAt(0); // different for Arabic,etc.
    digit = numberElements[5].charAt(0);
    minusSign = numberElements[6].charAt(0);
    exponential = numberElements[7].charAt(0);
    perMill = numberElements[8].charAt(0);
    infinity = numberElements[9];
    NaN = numberElements[10];

    // Try to obtain the currency used in the locale's country.
    // Check for empty country string separately because it's a valid
    // country ID for Locale (and used for the C locale), but not a valid
    // ISO 3166 country code, and exceptions are expensive.
    if (!"".equals(locale.getCountry())) {
      try {
        currency = Currency.getInstance(locale);
      } catch (IllegalArgumentException e) {
        // use default values below for compatibility
      }
    }
    if (currency != null) {
      intlCurrencySymbol = currency.getCurrencyCode();
      if (data[1] != null && data[1] == intlCurrencySymbol) {
        currencySymbol = (String) data[2];
      } else {
        currencySymbol = currency.getSymbol(locale);
        data[1] = intlCurrencySymbol;
        data[2] = currencySymbol;
        needCacheUpdate = true;
      }
    } else {
      // default values
      intlCurrencySymbol = "XXX";
      try {
        currency = Currency.getInstance(intlCurrencySymbol);
      } catch (IllegalArgumentException e) {
      }
      currencySymbol = "\u00A4";
    }
    // Currently the monetary decimal separator is the same as the
    // standard decimal separator for all locales that we support.
    // If that changes, add a new entry to NumberElements.
    monetarySeparator = decimalSeparator;

    if (needCacheUpdate) {
      cachedLocaleData.put(locale, data);
    }
  }
  /**
   * Returns a name for the locale that is appropriate for display to the user. This will be the
   * values returned by getDisplayLanguage(), getDisplayCountry(), and getDisplayVariant() assembled
   * into a single string. The display name will have one of the following forms:
   *
   * <p>
   *
   * <blockquote>
   *
   * language (country, variant)
   *
   * <p>language (country)
   *
   * <p>language (variant)
   *
   * <p>country (variant)
   *
   * <p>language
   *
   * <p>country
   *
   * <p>variant
   *
   * <p>
   *
   * </blockquote>
   *
   * depending on which fields are specified in the locale. If the language, country, and variant
   * fields are all empty, this function returns the empty string.
   */
  public String getDisplayName(Locale inLocale) {
    ResourceBundle bundle = LocaleData.getLocaleElements(inLocale);

    String languageName = getDisplayLanguage(inLocale);
    String countryName = getDisplayCountry(inLocale);
    String[] variantNames = getDisplayVariantArray(bundle);

    // Get the localized patterns for formatting a display name.
    String[] patterns;
    try {
      patterns = (String[]) bundle.getObject("LocaleNamePatterns");
    } catch (MissingResourceException e) {
      patterns = null;
    }

    // The display name consists of a main name, followed by qualifiers.
    // Typically, the format is "MainName (Qualifier, Qualifier)" but this
    // depends on what pattern is stored in the display locale.
    String mainName = null;
    String[] qualifierNames = null;

    // The main name is the language, or if there is no language, the country.
    // If there is neither language nor country (an anomalous situation) then
    // the display name is simply the variant's display name.
    if (languageName.length() != 0) {
      mainName = languageName;
      if (countryName.length() != 0) {
        qualifierNames = new String[variantNames.length + 1];
        System.arraycopy(variantNames, 0, qualifierNames, 1, variantNames.length);
        qualifierNames[0] = countryName;
      } else qualifierNames = variantNames;
    } else if (countryName.length() != 0) {
      mainName = countryName;
      qualifierNames = variantNames;
    } else {
      return formatList(patterns, variantNames);
    }

    // Create an array whose first element is the number of remaining
    // elements.  This serves as a selector into a ChoiceFormat pattern from
    // the resource.  The second and third elements are the main name and
    // the qualifier; if there are no qualifiers, the third element is
    // unused by the format pattern.
    Object[] displayNames = {
      new Integer(qualifierNames.length != 0 ? 2 : 1),
      mainName,
      // We could also just call formatList() and have it handle the empty
      // list case, but this is more efficient, and we want it to be
      // efficient since all the language-only locales will not have any
      // qualifiers.
      qualifierNames.length != 0 ? formatList(patterns, qualifierNames) : null
    };

    if (patterns != null) {
      return new MessageFormat(patterns[0]).format(displayNames);
    } else {
      // If we cannot get the message format pattern, then we use a simple
      // hard-coded pattern.  This should not occur in practice unless the
      // installation is missing some core files (LocaleElements etc.).
      StringBuffer result = new StringBuffer();
      result.append((String) displayNames[1]);
      if (displayNames.length > 2) {
        result.append(" (");
        result.append((String) displayNames[2]);
        result.append(")");
      }
      return result.toString();
    }
  }
 /**
  * Returns an array of all installed locales. The array returned must contain at least a <code>
  * Locale</code> instance equal to {@link java.util.Locale#US Locale.US}.
  *
  * @return An array of installed locales.
  */
 public static Locale[] getAvailableLocales() {
   return LocaleData.getAvailableLocales("LocaleString");
 }