Package com.ibm.icu.text

Source Code of com.ibm.icu.text.DecimalFormat$AffixForCurrency

//##header
/*
*******************************************************************************
* Copyright (C) 1996-2009, International Business Machines Corporation and    *
* others. All Rights Reserved.                                                *
*******************************************************************************
*/
package com.ibm.icu.text;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.math.BigInteger;
import java.text.ChoiceFormat;
import java.text.FieldPosition;
import java.text.ParsePosition;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

//#if defined(FOUNDATION10)
//#else
import java.io.ObjectOutputStream;
//#endif

//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import java.text.Format;
import java.util.ArrayList;
//#endif

import com.ibm.icu.impl.UCharacterProperty;
import com.ibm.icu.impl.Utility;
import com.ibm.icu.lang.UCharacter;
import com.ibm.icu.math.BigDecimal;
import com.ibm.icu.util.Currency;
import com.ibm.icu.util.CurrencyAmount;
import com.ibm.icu.util.ULocale;
import com.ibm.icu.math.MathContext;

//This is an enhanced version of DecimalFormat that is based on the standard version in the JDK.
/**
* <code>DecimalFormat</code> is a concrete subclass of
* {@link NumberFormat} that formats decimal numbers. It has a variety of
* features designed to make it possible to parse and format numbers in any
* locale, including support for Western, Arabic, or Indic digits.  It also
* supports different flavors of numbers, including integers ("123"),
* fixed-point numbers ("123.4"), scientific notation ("1.23E4"), percentages
* ("12%"), and currency amounts ("$123.00", "USD123.00", "123.00 US dollars").
* All of these flavors can be easily localized.
*
*
* <p>To obtain a {@link NumberFormat} for a specific locale (including the
* default locale) call one of <code>NumberFormat</code>'s factory methods such
* as {@link NumberFormat#getInstance}. Do not call the <code>DecimalFormat</code>
* constructors directly, unless you know what you are doing, since the
* {@link NumberFormat} factory methods may return subclasses other than
* <code>DecimalFormat</code>. If you need to customize the format object, do
* something like this:
*
* <blockquote><pre>
* NumberFormat f = NumberFormat.getInstance(loc);
* if (f instanceof DecimalFormat) {
*     ((DecimalFormat) f).setDecimalSeparatorAlwaysShown(true);
* }</pre></blockquote>
*
* <p><strong>Example Usage</strong>
*
* <blockquote><pre>
* <strong>// Print out a number using the localized number, currency,
* // and percent format for each locale</strong>
* Locale[] locales = NumberFormat.getAvailableLocales();
* double myNumber = -1234.56;
* NumberFormat format;
* for (int j=0; j<3; ++j) {
*     System.out.println("FORMAT");
*     for (int i = 0; i < locales.length; ++i) {
*         if (locales[i].getCountry().length() == 0) {
*            // Skip language-only locales
*            continue;
*         }
*         System.out.print(locales[i].getDisplayName());
*         switch (j) {
*         case 0:
*             format = NumberFormat.getInstance(locales[i]); break;
*         case 1:
*             format = NumberFormat.getCurrencyInstance(locales[i]); break;
*         default:
*             format = NumberFormat.getPercentInstance(locales[i]); break;
*         }
*         try {
*             // Assume format is a DecimalFormat
*             System.out.print(": " + ((DecimalFormat) format).toPattern()
*                              + " -> " + form.format(myNumber));
*         } catch (Exception e) {}
*         try {
*             System.out.println(" -> " + format.parse(form.format(myNumber)));
*         } catch (ParseException e) {}
*     }
* }</pre></blockquote>
*
* <P>
* Another example use getInstance(style)
* <P>
* <pre>
* <strong>// Print out a number using the localized number, currency,
* // percent, scientific, integer, iso currency, and plural currency
* // format for each locale</strong>
* ULocale locale = new ULocale("en_US");
* double myNumber = 1234.56;
* for (int j=NumberFormat.NUMBERSTYLE; j<=NumberFormat.PLURALCURRENCYSTYLE; ++j) {
*     NumberFormat format = NumberFormat.getInstance(locale, j);
*     try {
*         // Assume format is a DecimalFormat
*         System.out.print(": " + ((DecimalFormat) format).toPattern()
*                          + " -> " + form.format(myNumber));
*     } catch (Exception e) {}
*     try {
*         System.out.println(" -> " + format.parse(form.format(myNumber)));
*     } catch (ParseException e) {}
* }</pre></blockquote>
*
* <h4>Patterns</h4>
*
* <p>A <code>DecimalFormat</code> consists of a <em>pattern</em> and a set of
* <em>symbols</em>.  The pattern may be set directly using
* {@link #applyPattern}, or indirectly using other API methods which
* manipulate aspects of the pattern, such as the minimum number of integer
* digits.  The symbols are stored in a {@link DecimalFormatSymbols}
* object.  When using the {@link NumberFormat} factory methods, the
* pattern and symbols are read from ICU's locale data.
*
* <h4>Special Pattern Characters</h4>
*
* <p>Many characters in a pattern are taken literally; they are matched during
* parsing and output unchanged during formatting.  Special characters, on the
* other hand, stand for other characters, strings, or classes of characters.
* For example, the '#' character is replaced by a localized digit.  Often the
* replacement character is the same as the pattern character; in the U.S. locale,
* the ',' grouping character is replaced by ','.  However, the replacement is
* still happening, and if the symbols are modified, the grouping character
* changes.  Some special characters affect the behavior of the formatter by
* their presence; for example, if the percent character is seen, then the
* value is multiplied by 100 before being displayed.
*
* <p>To insert a special character in a pattern as a literal, that is, without
* any special meaning, the character must be quoted.  There are some exceptions to
* this which are noted below.
*
* <p>The characters listed here are used in non-localized patterns.  Localized
* patterns use the corresponding characters taken from this formatter's
* {@link DecimalFormatSymbols} object instead, and these characters lose
* their special status.  Two exceptions are the currency sign and quote, which
* are not localized.
*
* <blockquote>
* <table border=0 cellspacing=3 cellpadding=0 summary="Chart showing symbol,
*  location, localized, and meaning.">
*   <tr bgcolor="#ccccff">
*     <th align=left>Symbol
*     <th align=left>Location
*     <th align=left>Localized?
*     <th align=left>Meaning
*   <tr valign=top>
*     <td><code>0</code>
*     <td>Number
*     <td>Yes
*     <td>Digit
*   <tr valign=top bgcolor="#eeeeff">
*     <td><code>1-9</code>
*     <td>Number
*     <td>Yes
*     <td>'1' through '9' indicate rounding.
*        
*   <tr valign=top>
*     <td><code>@</code>
*     <td>Number
*     <td>No
*     <td>Significant digit
*   <tr valign=top bgcolor="#eeeeff">
*     <td><code>#</code>
*     <td>Number
*     <td>Yes
*     <td>Digit, zero shows as absent
*   <tr valign=top>
*     <td><code>.</code>
*     <td>Number
*     <td>Yes
*     <td>Decimal separator or monetary decimal separator
*   <tr valign=top bgcolor="#eeeeff">
*     <td><code>-</code>
*     <td>Number
*     <td>Yes
*     <td>Minus sign
*   <tr valign=top>
*     <td><code>,</code>
*     <td>Number
*     <td>Yes
*     <td>Grouping separator
*   <tr valign=top bgcolor="#eeeeff">
*     <td><code>E</code>
*     <td>Number
*     <td>Yes
*     <td>Separates mantissa and exponent in scientific notation.
*         <em>Need not be quoted in prefix or suffix.</em>
*   <tr valign=top>
*     <td><code>+</code>
*     <td>Exponent
*     <td>Yes
*     <td>Prefix positive exponents with localized plus sign.
*         <em>Need not be quoted in prefix or suffix.</em>
*   <tr valign=top bgcolor="#eeeeff">
*     <td><code>;</code>
*     <td>Subpattern boundary
*     <td>Yes
*     <td>Separates positive and negative subpatterns
*   <tr valign=top>
*     <td><code>%</code>
*     <td>Prefix or suffix
*     <td>Yes
*     <td>Multiply by 100 and show as percentage
*   <tr valign=top bgcolor="#eeeeff">
*     <td><code>&#92;u2030</code>
*     <td>Prefix or suffix
*     <td>Yes
*     <td>Multiply by 1000 and show as per mille
*   <tr valign=top>
*     <td><code>&#164;</code> (<code>&#92;u00A4</code>)
*     <td>Prefix or suffix
*     <td>No
*     <td>Currency sign, replaced by currency symbol.  If
*         doubled, replaced by international currency symbol.
*         If tripled, replaced by currency plural names, for example,
*         "US dollar" or "US dollars" for America.
*         If present in a pattern, the monetary decimal separator
*         is used instead of the decimal separator.
*   <tr valign=top bgcolor="#eeeeff">
*     <td><code>'</code>
*     <td>Prefix or suffix
*     <td>No
*     <td>Used to quote special characters in a prefix or suffix,
*         for example, <code>"'#'#"</code> formats 123 to
*         <code>"#123"</code>.  To create a single quote
*         itself, use two in a row: <code>"# o''clock"</code>.
*   <tr valign=top>
*     <td><code>*</code>
*     <td>Prefix or suffix boundary
*     <td>Yes
*     <td>Pad escape, precedes pad character
* </table>
* </blockquote>
*
* <p>A <code>DecimalFormat</code> pattern contains a postive and negative
* subpattern, for example, "#,##0.00;(#,##0.00)".  Each subpattern has a
* prefix, a numeric part, and a suffix.  If there is no explicit negative
* subpattern, the negative subpattern is the localized minus sign prefixed to the
* positive subpattern. That is, "0.00" alone is equivalent to "0.00;-0.00".  If there
* is an explicit negative subpattern, it serves only to specify the negative
* prefix and suffix; the number of digits, minimal digits, and other
* characteristics are ignored in the negative subpattern. That means that
* "#,##0.0#;(#)" has precisely the same result as "#,##0.0#;(#,##0.0#)".
*
* <p>The prefixes, suffixes, and various symbols used for infinity, digits,
* thousands separators, decimal separators, etc. may be set to arbitrary
* values, and they will appear properly during formatting.  However, care must
* be taken that the symbols and strings do not conflict, or parsing will be
* unreliable.  For example, either the positive and negative prefixes or the
* suffixes must be distinct for {@link #parse} to be able
* to distinguish positive from negative values.  Another example is that the
* decimal separator and thousands separator should be distinct characters, or
* parsing will be impossible.
*
* <p>The <em>grouping separator</em> is a character that separates clusters of
* integer digits to make large numbers more legible.  It commonly used for
* thousands, but in some locales it separates ten-thousands.  The <em>grouping
* size</em> is the number of digits between the grouping separators, such as 3
* for "100,000,000" or 4 for "1 0000 0000". There are actually two different
* grouping sizes: One used for the least significant integer digits, the
* <em>primary grouping size</em>, and one used for all others, the
* <em>secondary grouping size</em>.  In most locales these are the same, but
* sometimes they are different. For example, if the primary grouping interval
* is 3, and the secondary is 2, then this corresponds to the pattern
* "#,##,##0", and the number 123456789 is formatted as "12,34,56,789".  If a
* pattern contains multiple grouping separators, the interval between the last
* one and the end of the integer defines the primary grouping size, and the
* interval between the last two defines the secondary grouping size. All others
* are ignored, so "#,##,###,####" == "###,###,####" == "##,#,###,####".
*
* <p>Illegal patterns, such as "#.#.#" or "#.###,###", will cause
* <code>DecimalFormat</code> to throw an {@link IllegalArgumentException}
* with a message that describes the problem.
*
* <h4>Pattern BNF</h4>
*
* <pre>
* pattern    := subpattern (';' subpattern)?
* subpattern := prefix? number exponent? suffix?
* number     := (integer ('.' fraction)?) | sigDigits
* prefix     := '&#92;u0000'..'&#92;uFFFD' - specialCharacters
* suffix     := '&#92;u0000'..'&#92;uFFFD' - specialCharacters
* integer    := '#'* '0'* '0'
* fraction   := '0'* '#'*
* sigDigits  := '#'* '@' '@'* '#'*
* exponent   := 'E' '+'? '0'* '0'
* padSpec    := '*' padChar
* padChar    := '&#92;u0000'..'&#92;uFFFD' - quote
* &#32;
* Notation:
*   X*       0 or more instances of X
*   X?       0 or 1 instances of X
*   X|Y      either X or Y
*   C..D     any character from C up to D, inclusive
*   S-T      characters in S, except those in T
* </pre>
* The first subpattern is for positive numbers. The second (optional)
* subpattern is for negative numbers.
*
* <p>Not indicated in the BNF syntax above:
*
* <ul><li>The grouping separator ',' can occur inside the integer and
* sigDigits elements, between any two pattern characters of that
* element, as long as the integer or sigDigits element is not
* followed by the exponent element.
*
* <li>Two grouping intervals are recognized: That between the
*     decimal point and the first grouping symbol, and that
*     between the first and second grouping symbols. These
*     intervals are identical in most locales, but in some
*     locales they differ. For example, the pattern
*     &quot;#,##,###&quot; formats the number 123456789 as
*     &quot;12,34,56,789&quot;.</li>
*
* <li>
* The pad specifier <code>padSpec</code> may appear before the prefix,
* after the prefix, before the suffix, after the suffix, or not at all.
*
* <li>
* In place of '0', the digits '1' through '9' may be used to
* indicate a rounding increment.
* </ul>
*
* <h4>Parsing</h4>
*
* <p><code>DecimalFormat</code> parses all Unicode characters that represent
* decimal digits, as defined by {@link UCharacter#digit}.  In addition,
* <code>DecimalFormat</code> also recognizes as digits the ten consecutive
* characters starting with the localized zero digit defined in the
* {@link DecimalFormatSymbols} object.  During formatting, the
* {@link DecimalFormatSymbols}-based digits are output.
*
* <p>During parsing, grouping separators are ignored.
*
* <p>For currency parsing, the formatter is able to parse every currency
* style formats no matter which style the formatter is constructed with.
* For example, a formatter instance gotten from
* NumberFormat.getInstance(ULocale, NumberFormat.CURRENCYSTYLE) can parse
* formats such as "USD1.00" and "3.00 US dollars".
*
* <p>If {@link #parse(String, ParsePosition)} fails to parse
* a string, it returns <code>null</code> and leaves the parse position
* unchanged.  The convenience method {@link #parse(String)}
* indicates parse failure by throwing a {@link java.text.ParseException}.
*
* <h4>Formatting</h4>
*
* <p>Formatting is guided by several parameters, all of which can be
* specified either using a pattern or using the API.  The following
* description applies to formats that do not use <a href="#sci">scientific
* notation</a> or <a href="#sigdig">significant digits</a>.
*
* <ul><li>If the number of actual integer digits exceeds the
* <em>maximum integer digits</em>, then only the least significant
* digits are shown.  For example, 1997 is formatted as "97" if the
* maximum integer digits is set to 2.
*
* <li>If the number of actual integer digits is less than the
* <em>minimum integer digits</em>, then leading zeros are added.  For
* example, 1997 is formatted as "01997" if the minimum integer digits
* is set to 5.
*
* <li>If the number of actual fraction digits exceeds the <em>maximum
* fraction digits</em>, then half-even rounding it performed to the
* maximum fraction digits.  For example, 0.125 is formatted as "0.12"
* if the maximum fraction digits is 2.  This behavior can be changed
* by specifying a rounding increment and a rounding mode.
*
* <li>If the number of actual fraction digits is less than the
* <em>minimum fraction digits</em>, then trailing zeros are added.
* For example, 0.125 is formatted as "0.1250" if the mimimum fraction
* digits is set to 4.
*
* <li>Trailing fractional zeros are not displayed if they occur
* <em>j</em> positions after the decimal, where <em>j</em> is less
* than the maximum fraction digits. For example, 0.10004 is
* formatted as "0.1" if the maximum fraction digits is four or less.
* </ul>
*
* <p><strong>Special Values</strong>
*
* <p><code>NaN</code> is represented as a single character, typically
* <code>&#92;uFFFD</code>.  This character is determined by the
* {@link DecimalFormatSymbols} object.  This is the only value for which
* the prefixes and suffixes are not used.
*
* <p>Infinity is represented as a single character, typically
* <code>&#92;u221E</code>, with the positive or negative prefixes and suffixes
* applied.  The infinity character is determined by the
* {@link DecimalFormatSymbols} object.
*
* <a name="sci"><h4>Scientific Notation</h4></a>
*
* <p>Numbers in scientific notation are expressed as the product of a mantissa
* and a power of ten, for example, 1234 can be expressed as 1.234 x 10<sup>3</sup>. The
* mantissa is typically in the half-open interval [1.0, 10.0) or sometimes [0.0, 1.0),
* but it need not be.  <code>DecimalFormat</code> supports arbitrary mantissas.
* <code>DecimalFormat</code> can be instructed to use scientific
* notation through the API or through the pattern.  In a pattern, the exponent
* character immediately followed by one or more digit characters indicates
* scientific notation.  Example: "0.###E0" formats the number 1234 as
* "1.234E3".
*
* <ul>
* <li>The number of digit characters after the exponent character gives the
* minimum exponent digit count.  There is no maximum.  Negative exponents are
* formatted using the localized minus sign, <em>not</em> the prefix and suffix
* from the pattern.  This allows patterns such as "0.###E0 m/s".  To prefix
* positive exponents with a localized plus sign, specify '+' between the
* exponent and the digits: "0.###E+0" will produce formats "1E+1", "1E+0",
* "1E-1", etc.  (In localized patterns, use the localized plus sign rather than
* '+'.)
*
* <li>The minimum number of integer digits is achieved by adjusting the
* exponent.  Example: 0.00123 formatted with "00.###E0" yields "12.3E-4".  This
* only happens if there is no maximum number of integer digits.  If there is a
* maximum, then the minimum number of integer digits is fixed at one.
*
* <li>The maximum number of integer digits, if present, specifies the exponent
* grouping.  The most common use of this is to generate <em>engineering
* notation</em>, in which the exponent is a multiple of three, e.g.,
* "##0.###E0".  The number 12345 is formatted using "##0.####E0" as "12.345E3".
*
* <li>When using scientific notation, the formatter controls the
* digit counts using significant digits logic.  The maximum number of
* significant digits limits the total number of integer and fraction
* digits that will be shown in the mantissa; it does not affect
* parsing.  For example, 12345 formatted with "##0.##E0" is "12.3E3".
* See the section on significant digits for more details.
*
* <li>The number of significant digits shown is determined as
* follows: If areSignificantDigitsUsed() returns false, then the
* minimum number of significant digits shown is one, and the maximum
* number of significant digits shown is the sum of the <em>minimum
* integer</em> and <em>maximum fraction</em> digits, and is
* unaffected by the maximum integer digits.  If this sum is zero,
* then all significant digits are shown.  If
* areSignificantDigitsUsed() returns true, then the significant digit
* counts are specified by getMinimumSignificantDigits() and
* getMaximumSignificantDigits().  In this case, the number of
* integer digits is fixed at one, and there is no exponent grouping.
*
* <li>Exponential patterns may not contain grouping separators.
* </ul>
*
* <a name="sigdig"><h4>
* Significant Digits</h4></a>
*
* <code>DecimalFormat</code> has two ways of controlling how many
* digits are shows: (a) significant digits counts, or (b) integer and
* fraction digit counts.  Integer and fraction digit counts are
* described above.  When a formatter is using significant digits
* counts, the number of integer and fraction digits is not specified
* directly, and the formatter settings for these counts are ignored.
* Instead, the formatter uses however many integer and fraction
* digits are required to display the specified number of significant
* digits.  Examples:
*
* <blockquote>
* <table border=0 cellspacing=3 cellpadding=0>
*   <tr bgcolor="#ccccff">
*     <th align=left>Pattern
*     <th align=left>Minimum significant digits
*     <th align=left>Maximum significant digits
*     <th align=left>Number
*     <th align=left>Output of format()
*   <tr valign=top>
*     <td><code>@@@</code>
*     <td>3
*     <td>3
*     <td>12345
*     <td><code>12300</code>
*   <tr valign=top bgcolor="#eeeeff">
*     <td><code>@@@</code>
*     <td>3
*     <td>3
*     <td>0.12345
*     <td><code>0.123</code>
*   <tr valign=top>
*     <td><code>@@##</code>
*     <td>2
*     <td>4
*     <td>3.14159
*     <td><code>3.142</code>
*   <tr valign=top bgcolor="#eeeeff">
*     <td><code>@@##</code>
*     <td>2
*     <td>4
*     <td>1.23004
*     <td><code>1.23</code>
* </table>
* </blockquote>
*
* <ul>
* <li>Significant digit counts may be expressed using patterns that
* specify a minimum and maximum number of significant digits.  These
* are indicated by the <code>'@'</code> and <code>'#'</code>
* characters.  The minimum number of significant digits is the number
* of <code>'@'</code> characters.  The maximum number of significant
* digits is the number of <code>'@'</code> characters plus the number
* of <code>'#'</code> characters following on the right.  For
* example, the pattern <code>"@@@"</code> indicates exactly 3
* significant digits.  The pattern <code>"@##"</code> indicates from
* 1 to 3 significant digits.  Trailing zero digits to the right of
* the decimal separator are suppressed after the minimum number of
* significant digits have been shown.  For example, the pattern
* <code>"@##"</code> formats the number 0.1203 as
* <code>"0.12"</code>.
*
* <li>If a pattern uses significant digits, it may not contain a
* decimal separator, nor the <code>'0'</code> pattern character.
* Patterns such as <code>"@00"</code> or <code>"@.###"</code> are
* disallowed.
*
* <li>Any number of <code>'#'</code> characters may be prepended to
* the left of the leftmost <code>'@'</code> character.  These have no
* effect on the minimum and maximum significant digits counts, but
* may be used to position grouping separators.  For example,
* <code>"#,#@#"</code> indicates a minimum of one significant digits,
* a maximum of two significant digits, and a grouping size of three.
*
* <li>In order to enable significant digits formatting, use a pattern
* containing the <code>'@'</code> pattern character.  Alternatively,
* call {@link #setSignificantDigitsUsed setSignificantDigitsUsed(true)}.
*
* <li>In order to disable significant digits formatting, use a
* pattern that does not contain the <code>'@'</code> pattern
* character. Alternatively, call {@link #setSignificantDigitsUsed
* setSignificantDigitsUsed(false)}.
*
* <li>The number of significant digits has no effect on parsing.
*
* <li>Significant digits may be used together with exponential notation. Such
* patterns are equivalent to a normal exponential pattern with a minimum and
* maximum integer digit count of one, a minimum fraction digit count of
* <code>getMinimumSignificantDigits() - 1</code>, and a maximum fraction digit
* count of <code>getMaximumSignificantDigits() - 1</code>. For example, the
* pattern <code>"@@###E0"</code> is equivalent to <code>"0.0###E0"</code>.
*
* <li>If signficant digits are in use, then the integer and fraction
* digit counts, as set via the API, are ignored.  If significant
* digits are not in use, then the signficant digit counts, as set via
* the API, are ignored.
*
* </ul>
*
* <h4>
* Padding</h4>
*
* <p><code>DecimalFormat</code> supports padding the result of
* {@link #format} to a specific width.  Padding may be specified either
* through the API or through the pattern syntax.  In a pattern the pad escape
* character, followed by a single pad character, causes padding to be parsed
* and formatted.  The pad escape character is '*' in unlocalized patterns, and
* can be localized using {@link DecimalFormatSymbols#setPadEscape}.  For
* example, <code>"$*x#,##0.00"</code> formats 123 to <code>"$xx123.00"</code>,
* and 1234 to <code>"$1,234.00"</code>.
*
* <ul>
* <li>When padding is in effect, the width of the positive subpattern,
* including prefix and suffix, determines the format width.  For example, in
* the pattern <code>"* #0 o''clock"</code>, the format width is 10.
*
* <li>The width is counted in 16-bit code units (Java <code>char</code>s).
*
* <li>Some parameters which usually do not matter have meaning when padding is
* used, because the pattern width is significant with padding.  In the pattern
* "* ##,##,#,##0.##", the format width is 14.  The initial characters "##,##,"
* do not affect the grouping size or maximum integer digits, but they do affect
* the format width.
*
* <li>Padding may be inserted at one of four locations: before the prefix,
* after the prefix, before the suffix, or after the suffix.  If padding is
* specified in any other location, {@link #applyPattern} throws an {@link
* IllegalArgumentException}.  If there is no prefix, before the
* prefix and after the prefix are equivalent, likewise for the suffix.
*
* <li>When specified in a pattern, the 16-bit <code>char</code> immediately
* following the pad escape is the pad character. This may be any character,
* including a special pattern character. That is, the pad escape
* <em>escapes</em> the following character. If there is no character after
* the pad escape, then the pattern is illegal.
*
* </ul>
*
* <p>
* <strong>Rounding</strong>
*
* <p><code>DecimalFormat</code> supports rounding to a specific increment.  For
* example, 1230 rounded to the nearest 50 is 1250.  1.234 rounded to the
* nearest 0.65 is 1.3.  The rounding increment may be specified through the API
* or in a pattern.  To specify a rounding increment in a pattern, include the
* increment in the pattern itself.  "#,#50" specifies a rounding increment of
* 50.  "#,##0.05" specifies a rounding increment of 0.05.
*
* <ul>
* <li>Rounding only affects the string produced by formatting.  It does
* not affect parsing or change any numerical values.
*
* <li>A <em>rounding mode</em> determines how values are rounded; see the
* {@link com.ibm.icu.math.BigDecimal} documentation for a description of the
* modes.  Rounding increments specified in patterns use the default mode,
* {@link com.ibm.icu.math.BigDecimal#ROUND_HALF_EVEN}.
*
* <li>Some locales use rounding in their currency formats to reflect the
* smallest currency denomination.
*
* <li>In a pattern, digits '1' through '9' specify rounding, but otherwise
* behave identically to digit '0'.
* </ul>
*
* <h4>Synchronization</h4>
*
* <p><code>DecimalFormat</code> objects are not synchronized.  Multiple
* threads should not access one formatter concurrently.
*
* @see          java.text.Format
* @see          NumberFormat
* @author       Mark Davis
* @author       Alan Liu
* @stable ICU 2.0
*/
public class DecimalFormat extends NumberFormat {

    /**
     * Create a DecimalFormat using the default pattern and symbols
     * for the default locale. This is a convenient way to obtain a
     * DecimalFormat when internationalization is not the main concern.
     * <p>
     * To obtain standard formats for a given locale, use the factory methods
     * on NumberFormat such as getNumberInstance. These factories will
     * return the most appropriate sub-class of NumberFormat for a given
     * locale.
     * @see NumberFormat#getInstance
     * @see NumberFormat#getNumberInstance
     * @see NumberFormat#getCurrencyInstance
     * @see NumberFormat#getPercentInstance
     * @stable ICU 2.0
     */
    public DecimalFormat() {
        // [NEW]
        ULocale def = ULocale.getDefault();
        String pattern = getPattern(def, 0);
        // Always applyPattern after the symbols are set
        this.symbols = new DecimalFormatSymbols(def);
        setCurrency(Currency.getInstance(def));
        applyPatternWithoutExpandAffix(pattern, false);
        if (currencySignCount == CURRENCY_SIGN_COUNT_IN_PLURAL_FORMAT) {
            currencyPluralInfo = new CurrencyPluralInfo(def);
            // the exact pattern is not known until the plural count is known.
            // so, no need to expand affix now.
        } else {
            expandAffixAdjustWidth(null);
        }
    }


    /**
     * Create a DecimalFormat from the given pattern and the symbols
     * for the default locale. This is a convenient way to obtain a
     * DecimalFormat when internationalization is not the main concern.
     * <p>
     * To obtain standard formats for a given locale, use the factory methods
     * on NumberFormat such as getNumberInstance. These factories will
     * return the most appropriate sub-class of NumberFormat for a given
     * locale.
     * @param pattern A non-localized pattern string.
     * @exception IllegalArgumentException if the given pattern is invalid.
     * @see NumberFormat#getInstance
     * @see NumberFormat#getNumberInstance
     * @see NumberFormat#getCurrencyInstance
     * @see NumberFormat#getPercentInstance
     * @stable ICU 2.0
     */
    public DecimalFormat(String pattern) {
        // Always applyPattern after the symbols are set
        ULocale def = ULocale.getDefault();
        this.symbols = new DecimalFormatSymbols(def);
        setCurrency(Currency.getInstance(def));
        applyPatternWithoutExpandAffix( pattern, false );
        if (currencySignCount == CURRENCY_SIGN_COUNT_IN_PLURAL_FORMAT) {
            currencyPluralInfo = new CurrencyPluralInfo(def);
        } else {
            expandAffixAdjustWidth(null);
        }
    }


    /**
     * Create a DecimalFormat from the given pattern and symbols.
     * Use this constructor when you need to completely customize the
     * behavior of the format.
     * <p>
     * To obtain standard formats for a given
     * locale, use the factory methods on NumberFormat such as
     * getInstance or getCurrencyInstance. If you need only minor adjustments
     * to a standard format, you can modify the format returned by
     * a NumberFormat factory method.
     * @param pattern a non-localized pattern string
     * @param symbols the set of symbols to be used
     * @exception IllegalArgumentException if the given pattern is invalid
     * @see NumberFormat#getInstance
     * @see NumberFormat#getNumberInstance
     * @see NumberFormat#getCurrencyInstance
     * @see NumberFormat#getPercentInstance
     * @see DecimalFormatSymbols
     * @stable ICU 2.0
     */
    public DecimalFormat(String pattern, DecimalFormatSymbols symbols) {
        createFromPatternAndSymbols(pattern, symbols);
    }

    private void createFromPatternAndSymbols(String pattern, DecimalFormatSymbols inputSymbols) {
        // Always applyPattern after the symbols are set
        symbols = (DecimalFormatSymbols) inputSymbols.clone();
        setCurrencyForSymbols();
        applyPatternWithoutExpandAffix(pattern, false);
        if (currencySignCount == CURRENCY_SIGN_COUNT_IN_PLURAL_FORMAT) {
            currencyPluralInfo = new CurrencyPluralInfo(symbols.getLocale());
        } else {
            expandAffixAdjustWidth(null);
        }
    }


    /**
     * Create a DecimalFormat from the given pattern, symbols,
     * information used for currency plural format, and format style.
     * Use this constructor when you need to completely customize the
     * behavior of the format.
     * <p>
     * To obtain standard formats for a given
     * locale, use the factory methods on NumberFormat such as
     * getInstance or getCurrencyInstance.
     * <p>
     * If you need only minor adjustments to a standard format,
     * you can modify the format returned by
     * a NumberFormat factory method using the setters.
     * <p>
     * If you want to completely customize a decimal format,
     * using your own DecimalFormatSymbols (such as group separators) and
     * your own information for currency plural formatting (such as
     * plural rule and currency plural patterns), you can use this constructor.
     * <p>
     * @param pattern a non-localized pattern string
     * @param symbols the set of symbols to be used
     * @param infoInput the information used for currency plural format,
     *                  including currency plural patterns and plural rules.
     * @param style the decimal formatting style,
     *              it is one of the following values:
     *              NumberFormat.NUMBERSTYLE;
     *              NumberFormat.CURRENCYSTYLE;
     *              NumberFormat.PERCENTSTYLE;
     *              NumberFormat.SCIENTIFICSTYLE;
     *              NumberFormat.INTEGERSTYLE;
     *              NumberFormat.ISOCURRENCYSTYLE;
     *              NumberFormat.PLURALCURRENCYSTYLE;
     * @draft ICU 4.2
     * @provisional This API might change or be removed in a future release.
     */
    public DecimalFormat(String pattern, DecimalFormatSymbols symbols,
                         CurrencyPluralInfo infoInput,
                         int style) {
        CurrencyPluralInfo info = infoInput;
        if (style == NumberFormat.PLURALCURRENCYSTYLE) {
            info = (CurrencyPluralInfo)infoInput.clone();
        }
        create(pattern, symbols, info, style);
    }


    private void create(String pattern, DecimalFormatSymbols inputSymbols,
                        CurrencyPluralInfo info,
                        int inputStyle) {
        if (inputStyle != NumberFormat.PLURALCURRENCYSTYLE) {
            createFromPatternAndSymbols(pattern, inputSymbols);
        } else {
            // Always applyPattern after the symbols are set
            symbols = (DecimalFormatSymbols) inputSymbols.clone();
            currencyPluralInfo = info;
            // the pattern used in format is not fixed until formatting,
            // in which, the number is known and
            // will be used to pick the right pattern based on plural count.
            // Here, set the pattern as the pattern of plural count == "other".
            // For most locale, the patterns are probably the same for all
            // plural count. If not, the right pattern need to be re-applied
            // during format.
            String currencyPluralPatternForOther = currencyPluralInfo.getCurrencyPluralPattern("other");
            applyPatternWithoutExpandAffix(currencyPluralPatternForOther,false);
            setCurrencyForSymbols();
        }
        style = inputStyle;
    }


    /*
     * Create a DecimalFormat for currency plural format
     * from the given pattern, symbols, and style.
     */
    DecimalFormat(String pattern, DecimalFormatSymbols inputSymbols, int style) {
        CurrencyPluralInfo info = null;
        if (style == NumberFormat.PLURALCURRENCYSTYLE) {
            info = new CurrencyPluralInfo(inputSymbols.getLocale());
        }
        create(pattern, inputSymbols, info, style);
    }

    /**
     * @stable ICU 2.0
     */
    public StringBuffer format(double number, StringBuffer result,
            FieldPosition fieldPosition) {
        return format(number, result, fieldPosition, false);
    }
   
    // [Spark/CDL] The actual method to format number. If boolean value
    // parseAttr == true, then attribute information will be recorded.
    private StringBuffer format(double number, StringBuffer result,
            FieldPosition fieldPosition, boolean parseAttr)
    {
        fieldPosition.setBeginIndex(0);
        fieldPosition.setEndIndex(0);

        if (Double.isNaN(number))
        {
            if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) {
                fieldPosition.setBeginIndex(result.length());
            }
//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
            else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.INTEGER) {
                fieldPosition.setBeginIndex(result.length());
            }
//#endif

            result.append(symbols.getNaN());
            // [Spark/CDL] Add attribute for NaN here.
            // result.append(symbols.getNaN());
//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
            if (parseAttr) {
                addAttribute(Field.INTEGER, result.length()
                        - symbols.getNaN().length(), result.length());
            }
//#endif
            if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) {
                fieldPosition.setEndIndex(result.length());
            }
//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
            else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.INTEGER) {
                fieldPosition.setEndIndex(result.length());
            }
//#endif

            addPadding(result, fieldPosition, 0, 0);
            return result;
        }

        // Do this BEFORE checking to see if value is infinite or negative!
        if (multiplier != 1) number *= multiplier;

        /* Detecting whether a double is negative is easy with the exception of
         * the value -0.0.  This is a double which has a zero mantissa (and
         * exponent), but a negative sign bit.  It is semantically distinct from
         * a zero with a positive sign bit, and this distinction is important
         * to certain kinds of computations.  However, it's a little tricky to
         * detect, since (-0.0 == 0.0) and !(-0.0 < 0.0).  How then, you may
         * ask, does it behave distinctly from +0.0?  Well, 1/(-0.0) ==
         * -Infinity.  Proper detection of -0.0 is needed to deal with the
         * issues raised by bugs 4106658, 4106667, and 4147706.  Liu 7/6/98.
         */
        boolean isNegative = (number < 0.0) || (number == 0.0 && 1/number < 0.0);
        if (isNegative) number = -number;

        // Apply rounding after multiplier
        if (roundingDouble > 0.0) {
            // number = roundingDouble
            //  * round(number / roundingDouble, roundingMode, isNegative);
            double newNumber = round(number, roundingDouble, roundingDoubleReciprocal, roundingMode, isNegative);
            if (newNumber == 0.0 && number != newNumber) isNegative = false; // if we touched it, then make zero be zero.
            number = newNumber;
        }

        if (Double.isInfinite(number))
        {
            int prefixLen = appendAffix(result, isNegative, true, parseAttr);

            if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) {
                fieldPosition.setBeginIndex(result.length());
            }
//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
            else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.INTEGER) {
                fieldPosition.setBeginIndex(result.length());
            }
//#endif

            // [Spark/CDL] Add attribute for infinity here.
            result.append(symbols.getInfinity());
//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
            if (parseAttr) {
                addAttribute(Field.INTEGER, result.length()
                        - symbols.getInfinity().length(), result.length());
            }
//#endif
            if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) {
                fieldPosition.setEndIndex(result.length());
            }
//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
            else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.INTEGER) {
                fieldPosition.setEndIndex(result.length());
            }
//#endif

            int suffixLen = appendAffix(result, isNegative, false, parseAttr);

            addPadding(result, fieldPosition, prefixLen, suffixLen);
            return result;
        }

        // At this point we are guaranteed a nonnegative finite
        // number.
        synchronized(digitList) {
            digitList.set(number, precision(false),
                          !useExponentialNotation && !areSignificantDigitsUsed());
            return subformat(number, result, fieldPosition, isNegative, false,
                    parseAttr);
        }
    }
   
    // [NEW]
    /**
     * Round a double value to the nearest multiple of the given
     * rounding increment, according to the given mode.  This is
     * equivalent to rounding value/roundingInc to the nearest
     * integer, according to the given mode, and returning that
     * integer * roundingInc.
     * Note this is changed from the version in 2.4, since division of doubles
     * have inaccuracies. jitterbug 1871.
     * @param number the absolute value of the number to be rounded
     * @param roundingInc the rounding increment
     * @param roundingIncReciprocal if non-zero, is the
     * @param mode a BigDecimal rounding mode
     * @param isNegative true if the number to be rounded is negative
     * @return the absolute value of the rounded result
     */
    private static double round(double number, double roundingInc,
            double roundingIncReciprocal, int mode, boolean isNegative) {
       
        double div = roundingIncReciprocal == 0.0
            ? number / roundingInc
            : number * roundingIncReciprocal;
       
        // do the absolute cases first
       
        switch (mode) {
        case BigDecimal.ROUND_CEILING:
            div = (isNegative ? Math.floor(div + epsilon) : Math.ceil(div - epsilon));
            break;
        case BigDecimal.ROUND_FLOOR:
            div = (isNegative ? Math.ceil(div - epsilon) : Math.floor(div + epsilon));
            break;
        case BigDecimal.ROUND_DOWN:
            div = (Math.floor(div + epsilon));
            break;
        case BigDecimal.ROUND_UP:
            div = (Math.ceil(div - epsilon));
            break;
        case BigDecimal.ROUND_UNNECESSARY:
            if (div != Math.floor(div)) {
                throw new ArithmeticException("Rounding necessary");
            }
            return number;
        default:
           
            // Handle complex cases, where the choice depends on the closer value.
           
            // We figure out the distances to the two possible values, ceiling and floor.
            // We then go for the diff that is smaller.
            // Only if they are equal does the mode matter.

            double ceil = Math.ceil(div);
            double ceildiff = ceil - div; // (ceil * roundingInc) - number;
            double floor = Math.floor(div);
            double floordiff = div - floor; // number - (floor * roundingInc);
           
            // Note that the diff values were those mapped back to the "normal" space
            // by using the roundingInc. I don't have access to the original author of the code
            // but suspect that that was to produce better result in edge cases because of machine
            // precision, rather than simply using the difference between, say, ceil and div.
            // However, it didn't work in all cases. Am trying instead using an epsilon value.
           
            switch (mode) {
            case BigDecimal.ROUND_HALF_EVEN:
                // We should be able to just return Math.rint(a), but this
                // doesn't work in some VMs.
                // if one is smaller than the other, take the corresponding side
                if (floordiff + epsilon < ceildiff) {
                        div = floor;
                    } else if (ceildiff + epsilon < floordiff) {
                        div = ceil;
                } else { // they are equal, so we want to round to whichever is even
                    double testFloor = floor / 2;
                    div = (testFloor == Math.floor(testFloor)) ? floor : ceil;
                }
                break;
            case BigDecimal.ROUND_HALF_DOWN:
                div = ((floordiff <= ceildiff + epsilon) ? floor : ceil);
                break;
            case BigDecimal.ROUND_HALF_UP:
                div = ((ceildiff <= floordiff + epsilon) ? ceil : floor);
                break;
            default:
                throw new IllegalArgumentException("Invalid rounding mode: " + mode);
            }
        }
        number = roundingIncReciprocal == 0.0
            ? div * roundingInc
            : div / roundingIncReciprocal;
        return number;
    }
    private static double epsilon = 0.00000000001;

    /**
     * @stable ICU 2.0
     */
    // [Spark/CDL] Delegate to format_long_StringBuffer_FieldPosition_boolean
    public StringBuffer format(long number, StringBuffer result,
            FieldPosition fieldPosition) {
        return format(number, result, fieldPosition, false);
    }

    private StringBuffer format(long number, StringBuffer result,
            FieldPosition fieldPosition, boolean parseAttr)
    {
        fieldPosition.setBeginIndex(0);
        fieldPosition.setEndIndex(0);

        // If we are to do rounding, we need to move into the BigDecimal
        // domain in order to do divide/multiply correctly.
        // [NEW]
        if (roundingIncrementICU != null) {
            return format(BigDecimal.valueOf(number), result, fieldPosition);
        }

        boolean isNegative = (number < 0);
        if (isNegative) number = -number;

        // In general, long values always represent real finite numbers, so
        // we don't have to check for +/- Infinity or NaN.  However, there
        // is one case we have to be careful of:  The multiplier can push
        // a number near MIN_VALUE or MAX_VALUE outside the legal range.  We
        // check for this before multiplying, and if it happens we use BigInteger
        // instead.
        // [NEW]
        if (multiplier != 1) {
            boolean tooBig = false;
            if (number < 0) { // This can only happen if number == Long.MIN_VALUE
                long cutoff = Long.MIN_VALUE / multiplier;
                tooBig = (number <= cutoff); // number == cutoff can only happen if multiplier == -1
            } else {
                long cutoff = Long.MAX_VALUE / multiplier;
                tooBig = (number > cutoff);
            }
            if (tooBig) {
                // [Spark/CDL] Use
                // format_BigInteger_StringBuffer_FieldPosition_boolean instead
                // parseAttr is used to judge whether to synthesize attributes.
                return format(
                        BigInteger.valueOf(isNegative ? -number : number),
                        result, fieldPosition, parseAttr);
            }
        }

        number *= multiplier;
        synchronized(digitList) {
            digitList.set(number, precision(true));
            return subformat(number, result, fieldPosition, isNegative, true, parseAttr);
        }
    }

    // [NEW]
    /**
     * Format a BigInteger number.
     *
     * @stable ICU 2.0
     */
    public StringBuffer format(BigInteger number, StringBuffer result,
            FieldPosition fieldPosition) {
        return format(number, result, fieldPosition, false);
    }

    // [Spark/CDL]
    private StringBuffer format(BigInteger number, StringBuffer result,
            FieldPosition fieldPosition, boolean parseAttr) {
        // If we are to do rounding, we need to move into the BigDecimal
        // domain in order to do divide/multiply correctly.
        if (roundingIncrementICU != null) {
            return format(new BigDecimal(number), result, fieldPosition);
        }

        if (multiplier != 1) {
            number = number.multiply(BigInteger.valueOf(multiplier));
        }

        // At this point we are guaranteed a nonnegative finite
        // number.
        synchronized(digitList) {
            digitList.set(number, precision(true));
            return subformat(number.intValue(), result, fieldPosition, number.signum() < 0, true, parseAttr);
        }
    }

//#if defined(FOUNDATION10)
//#else
    // [NEW]
    /**
     * Format a BigDecimal number.
     * @stable ICU 2.0
     */
    public StringBuffer format(java.math.BigDecimal number, StringBuffer result,
                               FieldPosition fieldPosition) {
        return format(number, result, fieldPosition, false);
    }
   
    private StringBuffer format(java.math.BigDecimal number,
            StringBuffer result, FieldPosition fieldPosition, boolean parseAttr) {
        if (multiplier != 1) {
            number = number.multiply(java.math.BigDecimal.valueOf(multiplier));
        }

        if (roundingIncrement != null) {
            number = number.divide(roundingIncrement, 0, roundingMode)
                    .multiply(roundingIncrement);
        }

        synchronized(digitList) {
            digitList.set(number, precision(false),
                          !useExponentialNotation && !areSignificantDigitsUsed());
            return subformat(number.doubleValue(), result, fieldPosition, number.signum() < 0, false, parseAttr);
        }       
    }
//#endif
   
    // [NEW]
    /**
     * Format a BigDecimal number.
     * @stable ICU 2.0
     */
    public StringBuffer format(BigDecimal number, StringBuffer result,
                               FieldPosition fieldPosition) {
        /* This method is just a copy of the corresponding java.math.BigDecimal
         * method for now.  It isn't very efficient since it must create a
         * conversion object to do math on the rounding increment.  In the
         * future we may try to clean this up, or even better, limit our support
         * to just one flavor of BigDecimal.
         */
        if (multiplier != 1) {
            number = number.multiply(BigDecimal.valueOf(multiplier), mathContext);
        }

        if (roundingIncrementICU != null) {
            number = number.divide(roundingIncrementICU, 0, roundingMode)
                .multiply(roundingIncrementICU, mathContext);
        }

        synchronized(digitList) {
            digitList.set(number, precision(false),
                          !useExponentialNotation && !areSignificantDigitsUsed());
            return subformat(number.doubleValue(), result, fieldPosition, number.signum() < 0, false, false);
        }       
    }

    /**
     * Return true if a grouping separator belongs at the given
     * position, based on whether grouping is in use and the values of
     * the primary and secondary grouping interval.
     * @param pos the number of integer digits to the right of
     * the current position.  Zero indicates the position after the
     * rightmost integer digit.
     * @return true if a grouping character belongs at the current
     * position.
     */
    private boolean isGroupingPosition(int pos) {
        boolean result = false;
        if (isGroupingUsed() && (pos > 0) && (groupingSize > 0)) {
            if ((groupingSize2 > 0) && (pos > groupingSize)) {
                result = ((pos - groupingSize) % groupingSize2) == 0;
            } else {
                result = pos % groupingSize == 0;
            }
        }
        return result;
    }

    /**
     * Return the number of fraction digits to display, or the total
     * number of digits for significant digit formats and exponential
     * formats.
     */
    private int precision(boolean isIntegral) {
        if (areSignificantDigitsUsed()) {
            return getMaximumSignificantDigits();
        } else if (useExponentialNotation) {
            return getMinimumIntegerDigits() + getMaximumFractionDigits();
        } else {
            return isIntegral ? 0 : getMaximumFractionDigits();
        }
    }

    private StringBuffer subformat(int number, StringBuffer result,
                                   FieldPosition fieldPosition,
                                   boolean isNegative, boolean isInteger,
                                   boolean parseAttr) {
        if (currencySignCount == CURRENCY_SIGN_COUNT_IN_PLURAL_FORMAT) {
            return subformat(currencyPluralInfo.select(number), result, fieldPosition,
                             isNegative, isInteger, parseAttr);
        } else {
            return subformat(result, fieldPosition, isNegative, isInteger, parseAttr);
        }
    }

    private StringBuffer subformat(double number, StringBuffer result,
                                   FieldPosition fieldPosition,
                                   boolean isNegative, boolean isInteger,
                                   boolean parseAttr) {
        if (currencySignCount == CURRENCY_SIGN_COUNT_IN_PLURAL_FORMAT) {
            return subformat(currencyPluralInfo.select(number), result, fieldPosition,
                             isNegative, isInteger, parseAttr);
        } else {
            return subformat(result, fieldPosition, isNegative, isInteger, parseAttr);
        }
    }

    private StringBuffer subformat(String pluralCount,
            StringBuffer result,
            FieldPosition fieldPosition, boolean isNegative, boolean isInteger,
            boolean parseAttr)
    {
        // There are 2 ways to activate currency plural format:
        // by applying a pattern with 3 currency sign directly,
        // or by instantiate a decimal formatter using PLURALCURRENCYSTYLE.
        // For both cases, the number of currency sign in the pattern is 3.
        // Even if the number of currency sign in the pattern is 3,
        // it does not mean we need to reset the pattern.
        // For 1st case, we do not need to reset pattern.
        // For 2nd case, we might need to reset pattern,
        // if the default pattern (corresponding to plural count 'other')
        // we use is different from the pattern based on 'pluralCount'.
        //
        // style is only valid when decimal formatter is constructed through
        // DecimalFormat(pattern, symbol, style)
        if (style == NumberFormat.PLURALCURRENCYSTYLE) {
            // May need to reset pattern if the style is PLURALCURRENCYSTYLE.
            String currencyPluralPattern = currencyPluralInfo.getCurrencyPluralPattern(pluralCount);
            if (formatPattern.equals(currencyPluralPattern) == false) {
                applyPatternWithoutExpandAffix(currencyPluralPattern, false);
            }
        }
        // Expand the affix to the right name according to
        // the plural rule.
        // This is only used for currency plural formatting.
        // Currency plural name is not a fixed static one,
        // it is a dynamic name based on the currency plural count.
        // So, the affixes need to be expanded here.
        // For other cases, the affix is a static one based on pattern alone,
        // and it is already expanded during applying pattern,
        // or setDecimalFormatSymbols, or setCurrency.
        expandAffixAdjustWidth(pluralCount);
        return subformat(result, fieldPosition, isNegative, isInteger, parseAttr);
    }

    /**
     * Complete the formatting of a finite number.  On entry, the digitList must
     * be filled in with the correct digits.
     */
    private StringBuffer subformat(StringBuffer result,
            FieldPosition fieldPosition, boolean isNegative, boolean isInteger,
            boolean parseAttr)
    {
        // NOTE: This isn't required anymore because DigitList takes care of this.
        //
        //  // The negative of the exponent represents the number of leading
        //  // zeros between the decimal and the first non-zero digit, for
        //  // a value < 0.1 (e.g., for 0.00123, -fExponent == 2).  If this
        //  // is more than the maximum fraction digits, then we have an underflow
        //  // for the printed representation.  We recognize this here and set
        //  // the DigitList representation to zero in this situation.
        //
        //  if (-digitList.decimalAt >= getMaximumFractionDigits())
        //  {
        //      digitList.count = 0;
        //  }

        int i;
        char zero = symbols.getZeroDigit();
        int zeroDelta = zero - '0'; // '0' is the DigitList representation of zero
        char grouping = currencySignCount > 0 ?
                    symbols.getMonetaryGroupingSeparator() :
                    symbols.getGroupingSeparator();
        char decimal =  currencySignCount > 0 ?
            symbols.getMonetaryDecimalSeparator() :
            symbols.getDecimalSeparator();
        boolean useSigDig = areSignificantDigitsUsed();
        int maxIntDig = getMaximumIntegerDigits();
        int minIntDig = getMinimumIntegerDigits();

        /* Per bug 4147706, DecimalFormat must respect the sign of numbers which
         * format as zero.  This allows sensible computations and preserves
         * relations such as signum(1/x) = signum(x), where x is +Infinity or
         * -Infinity.  Prior to this fix, we always formatted zero values as if
         * they were positive.  Liu 7/6/98.
         */
        if (digitList.isZero())
        {
            digitList.decimalAt = 0; // Normalize
        }

        int prefixLen = appendAffix(result, isNegative, true, parseAttr);

        if (useExponentialNotation)
        {
            // Record field information for caller.
            if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) {
                fieldPosition.setBeginIndex(result.length());
                fieldPosition.setEndIndex(-1);
            } else if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD) {
                fieldPosition.setBeginIndex(-1);
            }
//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
            else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.INTEGER) {
                fieldPosition.setBeginIndex(result.length());
                fieldPosition.setEndIndex(-1);
            } else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.FRACTION) {
                fieldPosition.setBeginIndex(-1);
            }
//#endif

//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
            // [Spark/CDL]
            // the begin index of integer part
            // the end index of integer part
            // the begin index of fractional part
            int intBegin = result.length();
            int intEnd = -1;
            int fracBegin = -1;
//#endif

            int minFracDig = 0;
            if (useSigDig) {
                maxIntDig = minIntDig = 1;
                minFracDig = getMinimumSignificantDigits() - 1;
            } else {
                minFracDig = getMinimumFractionDigits();
                if (maxIntDig > MAX_SCIENTIFIC_INTEGER_DIGITS) {
                    maxIntDig = 1;
                    if (maxIntDig < minIntDig) {
                        maxIntDig = minIntDig;
                    }
                }
                if (maxIntDig > minIntDig) {
                    minIntDig = 1;
                }
            }           

            // Minimum integer digits are handled in exponential format by
            // adjusting the exponent.  For example, 0.01234 with 3 minimum
            // integer digits is "123.4E-4".

            // Maximum integer digits are interpreted as indicating the
            // repeating range.  This is useful for engineering notation, in
            // which the exponent is restricted to a multiple of 3.  For
            // example, 0.01234 with 3 maximum integer digits is "12.34e-3".
            // If maximum integer digits are defined and are larger than
            // minimum integer digits, then minimum integer digits are
            // ignored.

            int exponent = digitList.decimalAt;
            if (maxIntDig > 1 && maxIntDig != minIntDig) {
                // A exponent increment is defined; adjust to it.
                exponent = (exponent > 0) ? (exponent - 1) / maxIntDig
                                          : (exponent / maxIntDig) - 1;
                exponent *= maxIntDig;
            } else {
                // No exponent increment is defined; use minimum integer digits.
                // If none is specified, as in "#E0", generate 1 integer digit.
                exponent -= (minIntDig > 0 || minFracDig > 0)
                    ? minIntDig : 1;
            }

            // We now output a minimum number of digits, and more if there
            // are more digits, up to the maximum number of digits.  We
            // place the decimal point after the "integer" digits, which
            // are the first (decimalAt - exponent) digits.
            int minimumDigits = minIntDig + minFracDig;
            // The number of integer digits is handled specially if the number
            // is zero, since then there may be no digits.
            int integerDigits = digitList.isZero() ? minIntDig :
                digitList.decimalAt - exponent;
            int totalDigits = digitList.count;
            if (minimumDigits > totalDigits) totalDigits = minimumDigits;
            if (integerDigits > totalDigits) totalDigits = integerDigits;

            for (i=0; i<totalDigits; ++i)
            {
                if (i == integerDigits)
                {
                    // Record field information for caller.
                    if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) {
                        fieldPosition.setEndIndex(result.length());
                    }
//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
                    else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.INTEGER) {
                        fieldPosition.setEndIndex(result.length());
                    }
//#endif

//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
                    // [Spark/CDL] Add attribute for integer part
                    if (parseAttr) {
                        intEnd = result.length();
                        addAttribute(Field.INTEGER, intBegin, result.length());
                    }
//#endif
                    result.append(decimal);
//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
                    // [Spark/CDL] Add attribute for decimal separator
                    if (parseAttr) {
                        // Length of decimal separator is 1.
                        int decimalSeparatorBegin = result.length() - 1;
                        addAttribute(Field.DECIMAL_SEPARATOR,
                                decimalSeparatorBegin, result.length());
                            fracBegin = result.length();
                    }
//#endif
                    // Record field information for caller.
                    if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD) {
                        fieldPosition.setBeginIndex(result.length());
                    }
//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
                    else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.FRACTION) {
                        fieldPosition.setBeginIndex(result.length());
                    }
//#endif

                }
                result.append((i < digitList.count) ?
                          (char)(digitList.digits[i] + zeroDelta) :
                          zero);
            }
           
            //For ICU compatibility and format 0 to 0E0 with pattern "#E0" [Richard/GCL]
            if (digitList.isZero() && (totalDigits ==0)) {
                result.append(zero);
            }

            // Record field information
            if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) {
                if (fieldPosition.getEndIndex() < 0) {
                    fieldPosition.setEndIndex(result.length());
                }
            } else if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD) {
                if (fieldPosition.getBeginIndex() < 0) {
                    fieldPosition.setBeginIndex(result.length());
                }
                fieldPosition.setEndIndex(result.length());
            }
//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
            else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.INTEGER) {
                if (fieldPosition.getEndIndex() < 0) {
                    fieldPosition.setEndIndex(result.length());
                }
            } else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.FRACTION) {
                if (fieldPosition.getBeginIndex() < 0) {
                    fieldPosition.setBeginIndex(result.length());
                }
                fieldPosition.setEndIndex(result.length());
            }
//#endif

//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
            // [Spark/CDL] Calcuate the end index of integer part and fractional
            // part if they are not properly processed yet.
            if (parseAttr) {
                if (intEnd < 0) {
                    addAttribute(Field.INTEGER, intBegin, result.length());
                }
                if (fracBegin > 0) {
                    addAttribute(Field.FRACTION, fracBegin, result.length());
                }
            }
//#endif

            // The exponent is output using the pattern-specified minimum
            // exponent digits.  There is no maximum limit to the exponent
            // digits, since truncating the exponent would result in an
            // unacceptable inaccuracy.
            result.append(symbols.getExponentSeparator());
//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
            // [Spark/CDL] For exponent symbol, add an attribute.
            if (parseAttr) {
                addAttribute(Field.EXPONENT_SYMBOL, result.length()
                        - symbols.getExponentSeparator().length(), result
                        .length());
            }
//#endif
            // For zero values, we force the exponent to zero.  We
            // must do this here, and not earlier, because the value
            // is used to determine integer digit count above.
            if (digitList.isZero()) exponent = 0;

            boolean negativeExponent = exponent < 0;
            if (negativeExponent) {
                exponent = -exponent;
                result.append(symbols.getMinusSign());
//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
                // [Spark/CDL] If exponent has sign, then add an exponent sign
                // attribute.
                if (parseAttr) {
                    // Length of exponent sign is 1.
                    addAttribute(Field.EXPONENT_SIGN, result.length() - 1,
                            result.length());
                }
//#endif
            } else if (exponentSignAlwaysShown) {
                result.append(symbols.getPlusSign());
//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
                // [Spark/CDL] Add an plus sign attribute.
                if (parseAttr) {
                    // Length of exponent sign is 1.
                    int expSignBegin = result.length() - 1;
                    addAttribute(Field.EXPONENT_SIGN, expSignBegin, result
                            .length());
                }
//#endif
            }
//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
            int expBegin = result.length();
//#endif
            digitList.set(exponent);
            {
                int expDig = minExponentDigits;
                if (useExponentialNotation && expDig < 1) {
                    expDig = 1;
                }
                for (i=digitList.decimalAt; i<expDig; ++i) result.append(zero);
            }
            for (i=0; i<digitList.decimalAt; ++i)
            {
                result.append((i < digitList.count) ?
                          (char)(digitList.digits[i] + zeroDelta) : zero);
            }
//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
            // [Spark/CDL] Add attribute for exponent part.
            if (parseAttr) {
                addAttribute(Field.EXPONENT, expBegin, result.length());
            }
//#endif
        }
        else
        {
//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
            // [Spark/CDL] Record the integer start index.
            int intBegin = result.length();
//#endif
            // Record field information for caller.
            if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) {
                fieldPosition.setBeginIndex(result.length());
            }
//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
            else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.INTEGER) {
                fieldPosition.setBeginIndex(result.length());
            }
//#endif

            int sigCount = 0;
            int minSigDig = getMinimumSignificantDigits();
            int maxSigDig = getMaximumSignificantDigits();
            if (!useSigDig) {
                minSigDig = 0;
                maxSigDig = Integer.MAX_VALUE;
            }

            // Output the integer portion.  Here 'count' is the total
            // number of integer digits we will display, including both
            // leading zeros required to satisfy getMinimumIntegerDigits,
            // and actual digits present in the number.
            int count = useSigDig ?
                Math.max(1, digitList.decimalAt) : minIntDig;
            if (digitList.decimalAt > 0 && count < digitList.decimalAt) {
                count = digitList.decimalAt;
            }

            // Handle the case where getMaximumIntegerDigits() is smaller
            // than the real number of integer digits.  If this is so, we
            // output the least significant max integer digits.  For example,
            // the value 1997 printed with 2 max integer digits is just "97".

            int digitIndex = 0; // Index into digitList.fDigits[]
            if (count > maxIntDig && maxIntDig >= 0) {
                count = maxIntDig;
                digitIndex = digitList.decimalAt - count;
            }

            int sizeBeforeIntegerPart = result.length();
            for (i=count-1; i>=0; --i)
            {
                if (i < digitList.decimalAt && digitIndex < digitList.count &&
                    sigCount < maxSigDig) {
                    // Output a real digit
                    byte d = digitList.digits[digitIndex++];
                    result.append((char)(d + zeroDelta));
                    ++sigCount;
                }
                else
                {
                    // Output a zero (leading or trailing)
                    result.append(zero);
                    if (sigCount > 0) {
                        ++sigCount;
                    }
                }

                // Output grouping separator if necessary.
                if (isGroupingPosition(i)) {
                    result.append(grouping);
//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
                    // [Spark/CDL] Add grouping separator attribute here.
                    if (parseAttr) {
                        // Length of grouping separator is 1.
                        addAttribute(Field.GROUPING_SEPARATOR,
                                result.length() - 1, result.length());
                    }
//#endif
                }
            }

            // Record field information for caller.
            if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) {
                fieldPosition.setEndIndex(result.length());
            }
//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
            else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.INTEGER) {
                fieldPosition.setEndIndex(result.length());
            }
//#endif

            // Determine whether or not there are any printable fractional
            // digits.  If we've used up the digits we know there aren't.
            boolean fractionPresent = (!isInteger && digitIndex < digitList.count) ||
                (useSigDig ? (sigCount < minSigDig) : (getMinimumFractionDigits() > 0));

            // If there is no fraction present, and we haven't printed any
            // integer digits, then print a zero.  Otherwise we won't print
            // _any_ digits, and we won't be able to parse this string.
            if (!fractionPresent && result.length() == sizeBeforeIntegerPart)
                result.append(zero);
//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
            // [Spark/CDL] Add attribute for integer part.
            if (parseAttr) {
                addAttribute(Field.INTEGER, intBegin, result.length());
            }
//#endif
            // Output the decimal separator if we always do so.
            if (decimalSeparatorAlwaysShown || fractionPresent)
            {
                result.append(decimal);
//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
                // [Spark/CDL] Add attribute for decimal separator
                if (parseAttr) {
                    addAttribute(Field.DECIMAL_SEPARATOR, result.length() - 1,
                            result.length());
                }
//#endif
            }

            // Record field information for caller.
            if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD) {
                fieldPosition.setBeginIndex(result.length());
            }
//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
            else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.FRACTION) {
                fieldPosition.setBeginIndex(result.length());
            }
//#endif

//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
            // [Spark/CDL] Record the begin index of fraction part.
            int fracBegin = result.length();
//#endif

            count = useSigDig ? Integer.MAX_VALUE : getMaximumFractionDigits();
            if (useSigDig && (sigCount == maxSigDig ||
                              (sigCount >= minSigDig && digitIndex == digitList.count))) {
                count = 0;  
            }
            for (i=0; i < count; ++i) {
                // Here is where we escape from the loop.  We escape
                // if we've output the maximum fraction digits
                // (specified in the for expression above).  We also
                // stop when we've output the minimum digits and
                // either: we have an integer, so there is no
                // fractional stuff to display, or we're out of
                // significant digits.
                if (!useSigDig && i >= getMinimumFractionDigits() &&
                    (isInteger || digitIndex >= digitList.count)) {
                    break;
                }

                // Output leading fractional zeros.  These are zeros
                // that come after the decimal but before any
                // significant digits.  These are only output if
                // abs(number being formatted) < 1.0.
                if (-1-i > (digitList.decimalAt-1)) {
                    result.append(zero);
                    continue;
                }

                // Output a digit, if we have any precision left, or a
                // zero if we don't.  We don't want to output noise digits.
                if (!isInteger && digitIndex < digitList.count) {
                    result.append((char)(digitList.digits[digitIndex++] + zeroDelta));
                } else {
                    result.append(zero);
                }

                // If we reach the maximum number of significant
                // digits, or if we output all the real digits and
                // reach the minimum, then we are done.
                ++sigCount;
                if (useSigDig &&
                    (sigCount == maxSigDig ||
                     (digitIndex == digitList.count && sigCount >= minSigDig))) {
                    break;
                }
            }

            // Record field information for caller.
            if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD) {
                fieldPosition.setEndIndex(result.length());
            }
//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
            else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.FRACTION) {
                fieldPosition.setEndIndex(result.length());
            }
//#endif

//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
            // [Spark/CDL] Add attribute information if necessary.
            if (parseAttr && (decimalSeparatorAlwaysShown || fractionPresent)) {
                addAttribute(Field.FRACTION, fracBegin, result.length());
            }
//#endif
        }

        int suffixLen = appendAffix(result, isNegative, false, parseAttr);

        // [NEW]
        addPadding(result, fieldPosition, prefixLen, suffixLen);
        return result;
    }

    // [NEW]
    private final void addPadding(StringBuffer result, FieldPosition fieldPosition,
                                  int prefixLen, int suffixLen) {
        if (formatWidth > 0) {
            int len = formatWidth - result.length();
            if (len > 0) {
                char[] padding = new char[len];
                for (int i=0; i<len; ++i) {
                    padding[i] = pad;
                }
                switch (padPosition) {
                case PAD_AFTER_PREFIX:
                    result.insert(prefixLen, padding);
                    break;
                case PAD_BEFORE_PREFIX:
                    result.insert(0, padding);
                    break;
                case PAD_BEFORE_SUFFIX:
                    result.insert(result.length() - suffixLen, padding);
                    break;
                case PAD_AFTER_SUFFIX:
                    result.append(padding);
                    break;
                }
                if (padPosition == PAD_BEFORE_PREFIX ||
                    padPosition == PAD_AFTER_PREFIX) {
                    fieldPosition.setBeginIndex(fieldPosition.getBeginIndex() + len);
                    fieldPosition.setEndIndex(fieldPosition.getEndIndex() + len);
                }
            }
        }
    }

    // [CHANGED]
    /**
     * Parse the given string, returning a <code>Number</code> object to
     * represent the parsed value.  <code>Double</code> objects are returned to
     * represent non-integral values which cannot be stored in a
     * <code>BigDecimal</code>.  These are <code>NaN</code>, infinity,
     * -infinity, and -0.0.  If {@link #isParseBigDecimal()} is false (the
     * default), all other values are returned as <code>Long</code>,
     * <code>BigInteger</code>, or <code>BigDecimal</code> values,
     * in that order of preference. If {@link #isParseBigDecimal()} is true,
     * all other values are returned as <code>BigDecimal</code> valuse.
     * If the parse fails, null is returned.
     * @param text the string to be parsed
     * @param parsePosition defines the position where parsing is to begin,
     * and upon return, the position where parsing left off.  If the position
     * has not changed upon return, then parsing failed.
     * @return a <code>Number</code> object with the parsed value or
     * <code>null</code> if the parse failed
     * @stable ICU 2.0
     */
    public Number parse(String text, ParsePosition parsePosition) {
       return (Number) parse(text, parsePosition, false);
    }

    // [NEW]
    /**
     * Parses text from the given string as a CurrencyAmount.  Unlike
     * the parse() method, this method will attempt to parse a generic
     * currency name, searching for a match of this object's locale's
     * currency display names, or for a 3-letter ISO currency code.
     * This method will fail if this format is not a currency format,
     * that is, if it does not contain the currency pattern symbol
     * (U+00A4) in its prefix or suffix.
     *
     * @param text the string to parse
     * @param pos input-output position; on input, the position within
     * text to match; must have 0 <= pos.getIndex() < text.length();
     * on output, the position after the last matched character. If
     * the parse fails, the position in unchanged upon output.
     * @return a CurrencyAmount, or null upon failure
     * @internal
     * @deprecated This API is ICU internal only.
     */
    CurrencyAmount parseCurrency(String text, ParsePosition pos) {
        return (CurrencyAmount) parse(text, pos, true);
    }

    /**
     * Parses the given text as either a Number or a CurrencyAmount.
     * @param text the string to parse
     * @param parsePosition input-output position; on input, the
     * position within text to match; must have 0 <= pos.getIndex() <
     * text.length(); on output, the position after the last matched
     * character. If the parse fails, the position in unchanged upon
     * output.
     * @param parseCurrency if true, a CurrencyAmount is parsed and
     * returned; otherwise a Number is parsed and returned
     * @return a Number or CurrencyAmount or null
     */
    private Object parse(String text, ParsePosition parsePosition, boolean parseCurrency) {
        int backup;
        int i = backup = parsePosition.getIndex();

        // Handle NaN as a special case:

        // Skip padding characters, if around prefix
        if (formatWidth > 0 && (padPosition == PAD_BEFORE_PREFIX ||
                                padPosition == PAD_AFTER_PREFIX)) {
            i = skipPadding(text, i);
        }
        if (text.regionMatches(i, symbols.getNaN(),
                               0, symbols.getNaN().length())) {
            i += symbols.getNaN().length();
            // Skip padding characters, if around suffix
            if (formatWidth > 0 && (padPosition == PAD_BEFORE_SUFFIX ||
                                    padPosition == PAD_AFTER_SUFFIX)) {
                i = skipPadding(text, i);
            }
            parsePosition.setIndex(i);
            return new Double(Double.NaN);
        }

        // NaN parse failed; start over
        i = backup;

        boolean[] status = new boolean[STATUS_LENGTH];
        Currency[] currency = parseCurrency ? new Currency[1] : null;
        if (currencySignCount > 0) {
            if (!parseForCurrency(text, parsePosition, parseCurrency,
                                  currency, status)) {
                return null;
            }
        } else {
            if (!subparse(text, parsePosition, digitList, false, status,
                          currency, negPrefixPattern, negSuffixPattern,
                          posPrefixPattern, posSuffixPattern, Currency.SYMBOL_NAME)) {
                parsePosition.setIndex(backup);
                return null;
            }
        }

        Number n = null;

        // Handle infinity
        if (status[STATUS_INFINITE]) {
            n = new Double(status[STATUS_POSITIVE]
                           ? Double.POSITIVE_INFINITY
                           : Double.NEGATIVE_INFINITY);
        }

        // Handle underflow
        else if (status[STATUS_UNDERFLOW]) {
            n = status[STATUS_POSITIVE] ? new Double("0.0") : new Double("-0.0");
        }

        // Handle -0.0
        else if (!status[STATUS_POSITIVE] && digitList.isZero()) {
            n = new Double("-0.0");
        }

        else {
            // Do as much of the multiplier conversion as possible without
            // losing accuracy.
            int mult = multiplier; // Don't modify this.multiplier
            while (mult % 10 == 0) {
                --digitList.decimalAt;
                mult /= 10;
            }

            // Handle integral values
            if (!parseBigDecimal && mult == 1 && digitList.isIntegral()) {
                // hack quick long
                if (digitList.decimalAt < 12) { // quick check for long
                    long l = 0;
                    if (digitList.count > 0) {
                        int nx = 0;
                        while (nx < digitList.count) {
                            l = l * 10 + (char)digitList.digits[nx++] - '0';
                        }
                        while (nx++ < digitList.decimalAt) {
                            l *= 10;
                        }
                        if (!status[STATUS_POSITIVE]) {
                            l = -l;
                        }
                    }
                    n = new Long(l);
                } else {
                    BigInteger big = digitList.getBigInteger(status[STATUS_POSITIVE]);
                    n = (big.bitLength() < 64) ?
                        (Number) new Long(big.longValue()) : (Number) big;
                }
            }
            // Handle non-integral values or the case where parseBigDecimal is set
            else {
                BigDecimal big = digitList.getBigDecimalICU(status[STATUS_POSITIVE]);
                n = big;
                if (mult != 1) {
                    n = big.divide(BigDecimal.valueOf(mult), mathContext);
                }
            }
        }

        // Assemble into CurrencyAmount if necessary
        return parseCurrency ? (Object) new CurrencyAmount(n, currency[0])
                             : (Object) n;
    }


    private boolean parseForCurrency(String text, ParsePosition parsePosition,
                                     boolean parseCurrency, Currency[] currency,
                                     boolean[] status) {
        int origPos = parsePosition.getIndex();
        if (!isReadyForParsing) {
            int savedCurrencySignCount = currencySignCount;
            setupCurrencyAffixForAllPatterns();
            // reset pattern back
            if (savedCurrencySignCount == CURRENCY_SIGN_COUNT_IN_PLURAL_FORMAT) {
                applyPatternWithoutExpandAffix(formatPattern, false);
            } else {
                applyPattern(formatPattern, false);
            }
            isReadyForParsing = true;
        }
        int maxPosIndex = origPos;
        int maxErrorPos = -1;
        boolean[] savedStatus = null;
        // First, parse against current pattern.
        // Since current pattern could be set by applyPattern(),
        // it could be an arbitrary pattern, and it may not be the one
        // defined in current locale.
        boolean[] tmpStatus = new boolean[STATUS_LENGTH];
        ParsePosition tmpPos = new ParsePosition(origPos);
        DigitList tmpDigitList = new DigitList();
        boolean found;
        if (style == NumberFormat.PLURALCURRENCYSTYLE) {
            found  = subparse(text, tmpPos, tmpDigitList, false,
                  tmpStatus, currency, negPrefixPattern, negSuffixPattern,
                  posPrefixPattern, posSuffixPattern, Currency.LONG_NAME);
        } else {
            found  = subparse(text, tmpPos, tmpDigitList, false,
                  tmpStatus, currency, negPrefixPattern, negSuffixPattern,
                  posPrefixPattern, posSuffixPattern, Currency.SYMBOL_NAME);
        }
        if (found) {
            if (tmpPos.getIndex() > maxPosIndex) {
                maxPosIndex = tmpPos.getIndex();
                savedStatus = tmpStatus;
                digitList = tmpDigitList;
            }
        } else {
            maxErrorPos = tmpPos.getErrorIndex();
        }
        // Then, parse against affix patterns.
        // Those are currency patterns and currency plural patterns
        // defined in the locale.
        Iterator  iter = affixPatternsForCurrency.iterator();
        while (iter.hasNext()) {
            AffixForCurrency affix = (AffixForCurrency)iter.next();

            tmpStatus = new boolean[STATUS_LENGTH];
            tmpPos = new ParsePosition(origPos);
            tmpDigitList = new DigitList();
            boolean result = subparse(text, tmpPos, tmpDigitList, false,
                               tmpStatus, currency, affix.getNegPrefix(),
                               affix.getNegSuffix(), affix.getPosPrefix(),
                               affix.getPosSuffix(), affix.getPatternType());
            if (result) {
                found = true;
                if (tmpPos.getIndex() > maxPosIndex) {
                    maxPosIndex = tmpPos.getIndex();
                    savedStatus = tmpStatus;
                    digitList = tmpDigitList;
                }
            } else {
                maxErrorPos = (tmpPos.getErrorIndex() > maxErrorPos) ?
                              tmpPos.getErrorIndex() : maxErrorPos;
            }
        }
        // Finally, parse against simple affix to find the match.
        // For example, in TestMonster suite,
        // if the to-be-parsed text is "-\u00A40,00".
        // complexAffixCompare will not find match,
        // since there is no ISO code matches "\u00A4",
        // and the parse stops at "\u00A4".
        // We will just use simple affix comparison (look for exact match)
        // to pass it.
        tmpStatus = new boolean[STATUS_LENGTH];
        tmpPos = new ParsePosition(origPos);
        tmpDigitList = new DigitList();
        int savedCurrencySignCount = currencySignCount;
        // set currencySignCount to 0 so that compareAffix function will
        // fall to compareSimpleAffix path, not compareComplexAffix path.
        currencySignCount = 0;
        boolean result = subparse(text, tmpPos, tmpDigitList, false,
                  tmpStatus, currency, negativePrefix, negativeSuffix,
                  positivePrefix, positiveSuffix, Currency.SYMBOL_NAME);
        currencySignCount = savedCurrencySignCount;
        if (result) {
            if (tmpPos.getIndex() > maxPosIndex) {
                maxPosIndex = tmpPos.getIndex();
                savedStatus = tmpStatus;
                digitList = tmpDigitList;
            }
            found = true;
        } else {
                maxErrorPos = (tmpPos.getErrorIndex() > maxErrorPos) ?
                              tmpPos.getErrorIndex() : maxErrorPos;
        }

        if (!found) {
            //parsePosition.setIndex(origPos);
            parsePosition.setErrorIndex(maxErrorPos);
        } else {
            parsePosition.setIndex(maxPosIndex);
            parsePosition.setErrorIndex(-1);
            for (int index = 0; index < STATUS_LENGTH; ++index) {
                status[index] = savedStatus[index];
            }
        }
        return found;
    }


    // Get affix patterns used in locale's currency pattern
    // (NumberPatterns[1]) and currency plural pattern (CurrencyUnitPatterns).
    private void setupCurrencyAffixForAllPatterns() {
        if (currencyPluralInfo == null) {
            currencyPluralInfo = new CurrencyPluralInfo(symbols.getLocale());
        }
        affixPatternsForCurrency = new HashSet();

        // save the current pattern, since it will be changed by
        // applyPatternWithoutExpandAffix
        String savedFormatPattern = formatPattern;
       
        // CURRENCYSTYLE and ISOCURRENCYSTYLE should have the same
        // prefix and suffix, so, only need to save one of them.
        // Here, chose onlyApplyPatternWithoutExpandAffix without
        // saving the actualy pattern in 'pattern' data member.
        // TODO: is it uloc?
        applyPatternWithoutExpandAffix(getPattern(symbols.getLocale(), NumberFormat.CURRENCYSTYLE), false);
        AffixForCurrency affixes = new AffixForCurrency(negPrefixPattern,
                                                        negSuffixPattern,
                                                        posPrefixPattern,
                                                        posSuffixPattern,
                                                        Currency.SYMBOL_NAME);
        affixPatternsForCurrency.add(affixes);
       
        // add plural pattern
        Iterator iter = currencyPluralInfo.pluralPatternIterator();
        Set currencyUnitPatternSet = new HashSet();
        while (iter.hasNext()) {
            String pluralCount = (String)iter.next();
            String currencyPattern = (String)currencyPluralInfo.getCurrencyPluralPattern(pluralCount);
            if (currencyPattern != null &&
                currencyUnitPatternSet.contains(currencyPattern) == false) {
                currencyUnitPatternSet.add(currencyPattern);
                applyPatternWithoutExpandAffix(currencyPattern, false);
                affixes = new AffixForCurrency(negPrefixPattern,
                                               negSuffixPattern,
                                               posPrefixPattern,
                                               posSuffixPattern,
                                               Currency.LONG_NAME);
                affixPatternsForCurrency.add(affixes);
            }  
        }
        // reset pattern back
        formatPattern = savedFormatPattern;
    }

    private static final int CURRENCY_SIGN_COUNT_IN_SYMBOL_FORMAT = 1;
    private static final int CURRENCY_SIGN_COUNT_IN_ISO_FORMAT = 2;
    private static final int CURRENCY_SIGN_COUNT_IN_PLURAL_FORMAT = 3;

    private static final int STATUS_INFINITE = 0;
    private static final int STATUS_POSITIVE = 1;
    private static final int STATUS_UNDERFLOW = 2;
    private static final int STATUS_LENGTH   = 3;
    private static final UnicodeSet dotEquivalents =(UnicodeSet) new UnicodeSet(
        "[.\u2024\u3002\uFE12\uFE52\uFF0E\uFF61]").freeze();
    private static final UnicodeSet commaEquivalents = (UnicodeSet) new UnicodeSet(
        "[,\u060C\u066B\u3001\uFE10\uFE11\uFE50\uFE51\uFF0C\uFF64]").freeze();
    private static final UnicodeSet otherGroupingSeparators = (UnicodeSet) new UnicodeSet(
        "[\\ '\u00A0\u066C\u2000-\u200A\u2018\u2019\u202F\u205F\u3000\uFF07]").freeze();
   
    private static final UnicodeSet strictDotEquivalents =(UnicodeSet) new UnicodeSet(
        "[.\u2024\uFE52\uFF0E\uFF61]").freeze();
    private static final UnicodeSet strictCommaEquivalents = (UnicodeSet) new UnicodeSet(
        "[,\u066B\uFE10\uFE50\uFF0C]").freeze();
    private static final UnicodeSet strictOtherGroupingSeparators = (UnicodeSet) new UnicodeSet(
        "[\\ '\u00A0\u066C\u2000-\u200A\u2018\u2019\u202F\u205F\u3000\uFF07]").freeze();

    private static final UnicodeSet defaultGroupingSeparators = (UnicodeSet) new UnicodeSet(
        dotEquivalents).addAll(commaEquivalents).addAll(otherGroupingSeparators).freeze();
    private static final UnicodeSet strictDefaultGroupingSeparators = (UnicodeSet) new UnicodeSet(
            strictDotEquivalents).addAll(strictCommaEquivalents).addAll(strictOtherGroupingSeparators).freeze();

    // When parsing a number with big exponential value, it requires to transform
    // the value into a string representation to construct BigInteger instance.
    // We want to set the maximum size because it can easily trigger OutOfMemoryException.
    // PARSE_MAX_EXPONENT is currently set to 1000, which is much bigger than
    // MAX_VALUE of Double (
    // See the problem reported by ticket#5698
    private static final int PARSE_MAX_EXPONENT = 1000;

    /**
     * <strong><font face=helvetica color=red>CHANGED</font></strong>
     * Parse the given text into a number.  The text is parsed beginning at
     * parsePosition, until an unparseable character is seen.
     * @param text The string to parse.
     * @param parsePosition The position at which to being parsing.  Upon
     * return, the first unparseable character.
     * @param digits The DigitList to set to the parsed value.
     * @param isExponent If true, parse an exponent.  This means no
     * infinite values and integer only.
     * @param status Upon return contains boolean status flags indicating
     * whether the value was infinite and whether it was positive.
     * @param currency return value for parsed currency, for generic
     * currency parsing mode, or null for normal parsing. In generic
     * currency parsing mode, any currency is parsed, not just the
     * currency that this formatter is set to.
     * @param negPrefix negative prefix pattern
     * @param negSuffix negative suffix pattern
     * @param posPrefix positive prefix pattern
     * @param negSuffix negative suffix pattern
     * @param type type of currency to parse against, LONG_NAME only or not.
     */
    private final boolean subparse(String text, ParsePosition parsePosition,
                   DigitList digits, boolean isExponent,
                   boolean status[], Currency currency[],
                   String negPrefix, String negSuffix,
                   String posPrefix, String posSuffix,
                   int type)
    {
        int position = parsePosition.getIndex();
        int oldStart = parsePosition.getIndex();

        // Match padding before prefix
        if (formatWidth > 0 && padPosition == PAD_BEFORE_PREFIX) {
            position = skipPadding(text, position);
        }

        // Match positive and negative prefixes; prefer longest match.
        int posMatch = compareAffix(text, position, false, true, posPrefix, type, currency);
        int negMatch = compareAffix(text, position, true, true, negPrefix, type, currency);
        if (posMatch >= 0 && negMatch >= 0) {
            if (posMatch > negMatch) {
                negMatch = -1;
            } else if (negMatch > posMatch) {
                posMatch = -1;
           
        }
        if (posMatch >= 0) {
            position += posMatch;
        } else if (negMatch >= 0) {
            position += negMatch;
        } else {
            parsePosition.setErrorIndex(position);
            return false;
        }

        // Match padding after prefix
        if (formatWidth > 0 && padPosition == PAD_AFTER_PREFIX) {
            position = skipPadding(text, position);
        }

        // process digits or Inf, find decimal position
        status[STATUS_INFINITE] = false;
        if (!isExponent && text.regionMatches(position,symbols.getInfinity(),0,
                          symbols.getInfinity().length()))
        {
            position += symbols.getInfinity().length();
            status[STATUS_INFINITE] = true;
        } else {
            // We now have a string of digits, possibly with grouping symbols,
            // and decimal points.  We want to process these into a DigitList.
            // We don't want to put a bunch of leading zeros into the DigitList
            // though, so we keep track of the location of the decimal point,
            // put only significant digits into the DigitList, and adjust the
            // exponent as needed.

            digits.decimalAt = digits.count = 0;
            char zero = symbols.getZeroDigit();
            char decimal = currencySignCount > 0 ?
            symbols.getMonetaryDecimalSeparator() : symbols.getDecimalSeparator();
            char grouping = symbols.getGroupingSeparator();
                       
            String exponentSep = symbols.getExponentSeparator();
            boolean sawDecimal = false;
            boolean sawExponent = false;
            boolean sawDigit = false;
            long exponent = 0; // Set to the exponent value, if any
            int digit = 0;

            // strict parsing
            boolean strictParse = isParseStrict();
            boolean strictFail = false; // did we exit with a strict parse failure?
            int lastGroup = -1; // where did we last see a grouping separator?
            int gs2 = groupingSize2 == 0 ? groupingSize : groupingSize2;

            // Strict parsing leading zeroes.  If a leading zero would
            // be forced by the pattern, then don't fail strict parsing.
            boolean strictLeadingZero = false;
            int leadingZeroPos   = 0;
            int leadingZeroCount = 0;
           
            // equivalent grouping and decimal support
           
            // TODO markdavis Cache these if it makes a difference in performance.
            UnicodeSet decimalSet = new UnicodeSet(getSimilarDecimals(decimal, strictParse));
            UnicodeSet groupingSet = new UnicodeSet(strictParse ? strictDefaultGroupingSeparators : defaultGroupingSeparators)
                .add(grouping).removeAll(decimalSet);
           
            // we are guaranteed that
            // decimalSet contains the decimal, and
            // groupingSet contains the groupingSeparator
            // (unless decimal and grouping are the same, which should never happen. But in that case, groupingSet will just be empty.)


            // We have to track digitCount ourselves, because digits.count will
            // pin when the maximum allowable digits is reached.
            int digitCount = 0;
           
            int backup = -1;
            for (; position < text.length(); ++position)
            {
                char ch = text.charAt(position);

                /* We recognize all digit ranges, not only the Latin digit range
                 * '0'..'9'.  We do so by using the UCharacter.digit() method,
                 * which converts a valid Unicode digit to the range 0..9.
                 *
                 * The character 'ch' may be a digit.  If so, place its value
                 * from 0 to 9 in 'digit'.  First try using the locale digit,
                 * which may or MAY NOT be a standard Unicode digit range.  If
                 * this fails, try using the standard Unicode digit ranges by
                 * calling UCharacter.digit().  If this also fails, digit will
                 * have a value outside the range 0..9.
                 */
                digit = ch - zero;
                if (digit < 0 || digit > 9) digit = UCharacter.digit(ch, 10);

                if (digit == 0)
                {
                    // Cancel out backup setting (see grouping handler below)
                    if (strictParse && backup != -1) {
                        // comma followed by digit, so group before comma is a
                        // secondary group.  If there was a group separator
                        // before that, the group must == the secondary group
                        // length, else it can be <= the the secondary group
                        // length.
                        if ((lastGroup != -1 && backup - lastGroup - 1 != gs2) ||
                            (lastGroup == -1 && position - oldStart - 1 > gs2)) {
                            strictFail = true;
                            break;
                        }
                        lastGroup = backup;
                    }
                    backup = -1; // Do this BEFORE continue statement below!!!
                    sawDigit = true;

                    // Handle leading zeros
                    if (digits.count == 0)
                    {
                        if (!sawDecimal) {
                            if (strictParse && !isExponent) {
                                // Allow leading zeros in exponents
                                // Count leading zeros for checking later
                                if (!strictLeadingZero) leadingZeroPos = position + 1;
                                strictLeadingZero = true;
                                ++leadingZeroCount;                               
                            }
                            // Ignore leading zeros in integer part of number.
                            continue;
                        }

                        // If we have seen the decimal, but no significant digits yet,
                        // then we account for leading zeros by decrementing the
                        // digits.decimalAt into negative values.
                        --digits.decimalAt;
                    }
                    else
                    {
                        ++digitCount;
                        digits.append((char)(digit + '0'));
                    }
                }
                else if (digit > 0 && digit <= 9) // [sic] digit==0 handled above
                {
                    if (strictParse) {
                        if (backup != -1) {
                            if ((lastGroup != -1 && backup - lastGroup - 1 != gs2) ||
                                (lastGroup == -1 && position - oldStart - 1 > gs2)) {
                                strictFail = true;
                                break;
                            }
                            lastGroup = backup;
                        }
                    }

                    sawDigit = true;
                    ++digitCount;
                    digits.append((char)(digit + '0'));

                    // Cancel out backup setting (see grouping handler below)
                    backup = -1;
                }
                else if (!isExponent && decimalSet.contains(ch))
                {
                    if (strictParse) {
                        if (backup != -1 ||
                            (lastGroup != -1 && position - lastGroup != groupingSize + 1)) {
                            strictFail = true;
                            break;
                        }
                    }
                    // If we're only parsing integers, or if we ALREADY saw the
                    // decimal, then don't parse this one.
                    if (isParseIntegerOnly() || sawDecimal) break;
                    digits.decimalAt = digitCount; // Not digits.count!
                    sawDecimal = true;
                   
                    // Once we see a decimal character, we only accept that decimal character from then on.
                    decimalSet.set(ch,ch);
                }
                else if (!isExponent && isGroupingUsed() && groupingSet.contains(ch))
                {
                    if (sawDecimal) {
                        break;
                    }
                    if (strictParse) {
                        if ((!sawDigit || backup != -1)) {
                            // leading group, or two group separators in a row
                            strictFail = true;
                            break;
                        }
                    }
                    // Once we see a grouping character, we only accept that grouping character from then on.
                    groupingSet.set(ch,ch);
                   
                    // Ignore grouping characters, if we are using them, but require
                    // that they be followed by a digit.  Otherwise we backup and
                    // reprocess them.
                    backup = position;
                }
                else if (!isExponent && !sawExponent &&
                         text.regionMatches(position, exponentSep,
                                            0, exponentSep.length()))
                {
                    // Parse sign, if present
                    boolean negExp = false;
                    int pos = position + exponentSep.length();
                    if (pos < text.length()) {
                        ch = text.charAt(pos);
                        if (ch == symbols.getPlusSign()) {
                            ++pos;
                        } else if (ch == symbols.getMinusSign()) {
                            ++pos;
                            negExp = true;
                        }
                    }

                    DigitList exponentDigits = new DigitList();
                    exponentDigits.count = 0;
                    while (pos < text.length()) {
                        digit = text.charAt(pos) - zero;
                        if (digit < 0 || digit > 9) {
                            /*
                              Can't parse "[1E0]" when pattern is "0.###E0;[0.###E0]"
                              Should update reassign the value of 'ch' in the
                              code:  digit = Character.digit(ch, 10);
                              [Richard/GCL]
                            */
                            digit = UCharacter.digit(text.charAt(pos), 10);
                        }
                        if (digit >= 0 && digit <= 9) {
                            exponentDigits.append((char)(digit + '0'));
                            ++pos;
                        } else {
                            break;
                        }
                    }
                   
                    if (exponentDigits.count > 0) {
                        // defer strict parse until we know we have a bona-fide exponent
                        if (strictParse) {
                            if (backup != -1 || lastGroup != -1) {
                                strictFail = true;
                                break;
                            }
                        }

                        // Quick overflow check for exponential part.
                        // Actual limit check will be done later in this code.
                        if (exponentDigits.count > 10 /* maximum decimal digits for int */) {
                            if (negExp) {
                                // set underflow flag
                                status[STATUS_UNDERFLOW] = true;
                            } else {
                                // set infinite flag
                                status[STATUS_INFINITE] = true;
                            }
                        } else {
                            exponentDigits.decimalAt = exponentDigits.count;
                            exponent = exponentDigits.getLong();
                            if (negExp) {
                                exponent = -exponent;
                            }
                        }
                        position = pos; // Advance past the exponent
                        sawExponent = true;
                    }

                    break; // Whether we fail or succeed, we exit this loop
                }
                else break;
            }

            if (backup != -1) position = backup;

            // If there was no decimal point we have an integer
            if (!sawDecimal) digits.decimalAt = digitCount; // Not digits.count!           
           
            // check for strict parse errors
            if (strictParse && strictLeadingZero) {
                if ((leadingZeroCount + digits.decimalAt) > this.getMinimumIntegerDigits()) {
                    parsePosition.setIndex(oldStart);
                    parsePosition.setErrorIndex(leadingZeroPos);
                    return false;
                }
            }
            if (strictParse && !sawDecimal) {
                if (lastGroup != -1 && position - lastGroup != groupingSize + 1) {
                    strictFail = true;
                }
            }
            if (strictFail) {
                // only set with strictParse and a leading zero error
                // leading zeros are an error with strict parsing except
                // immediately before nondigit (except group separator
                // followed by digit), or end of text.
               
                parsePosition.setIndex(oldStart);
                parsePosition.setErrorIndex(position);
                return false;
            }

            // Adjust for exponent, if any
            exponent += digits.decimalAt;
            if (exponent < -PARSE_MAX_EXPONENT) {
                status[STATUS_UNDERFLOW] = true;
            } else if (exponent > PARSE_MAX_EXPONENT) {
                status[STATUS_INFINITE] = true;
            } else {
                digits.decimalAt = (int)exponent;
            }

            // If none of the text string was recognized.  For example, parse
            // "x" with pattern "#0.00" (return index and error index both 0)
            // parse "$" with pattern "$#0.00". (return index 0 and error index
            // 1).
            if (!sawDigit && digitCount == 0) {
                parsePosition.setIndex(oldStart);
                parsePosition.setErrorIndex(oldStart);
                return false;
            }
        }

        // Match padding before suffix
        if (formatWidth > 0 && padPosition == PAD_BEFORE_SUFFIX) {
            position = skipPadding(text, position);
        }

        // Match positive and negative suffixes; prefer longest match.
        if (posMatch >= 0) {
            posMatch = compareAffix(text, position, false, false, posSuffix, type, currency);
        }
        if (negMatch >= 0) {
            negMatch = compareAffix(text, position, true, false, negSuffix, type, currency);
        }
        if (posMatch >= 0 && negMatch >= 0) {
            if (posMatch > negMatch) {
                negMatch = -1;
            } else if (negMatch > posMatch) {
                posMatch = -1;
           
        }

        // Fail if neither or both
        if ((posMatch >= 0) == (negMatch >= 0)) {
            parsePosition.setErrorIndex(position);
            return false;
        }

        position += (posMatch>=0 ? posMatch : negMatch);

        // Match padding after suffix
        if (formatWidth > 0 && padPosition == PAD_AFTER_SUFFIX) {
            position = skipPadding(text, position);
        }

        parsePosition.setIndex(position);

        status[STATUS_POSITIVE] = (posMatch >= 0);

        if (parsePosition.getIndex() == oldStart) {
            parsePosition.setErrorIndex(position);
            return false;
        }
        return true;
    }

    /**
     * Return characters that are used where this decimal is used.
     * @param decimal
     * @param strictParse
     * @return
     */
    private UnicodeSet getSimilarDecimals(char decimal, boolean strictParse) {
        if (dotEquivalents.contains(decimal)) {
            return strictParse ? strictDotEquivalents : dotEquivalents;
        }
        if (commaEquivalents.contains(decimal)) {
            return strictParse ? strictCommaEquivalents : commaEquivalents;
        }
        // if there is no match, return the character itself
        return new UnicodeSet().add(decimal);
    }

    /**
     * Starting at position, advance past a run of pad characters, if any.
     * Return the index of the first character after position that is not a pad
     * character.  Result is >= position.
     */
    private final int skipPadding(String text, int position) {
        while (position < text.length() && text.charAt(position) == pad) {
            ++position;
        }
        return position;
    }

    /*
     * Return the length matched by the given affix, or -1 if none.
     * Runs of white space in the affix, match runs of white space in
     * the input.  Pattern white space and input white space are
     * determined differently; see code.
     * @param text input text
     * @param pos offset into input at which to begin matching
     * @param isNegative
     * @param isPrefix
     * @param affixPat affix pattern used for currency affix comparison
     * @param type compare against currency type, LONG_NAME only or not.
     * @param currency return value for parsed currency, for generic
     * currency parsing mode, or null for normal parsing. In generic
     * currency parsing mode, any currency is parsed, not just the
     * currency that this formatter is set to.
     * @return length of input that matches, or -1 if match failure
     */
    private int compareAffix(String text, int pos,
                             boolean isNegative, boolean isPrefix,
                             String affixPat,
                             int type,
                             Currency[] currency) {
        if (currency != null || currencyChoice != null ||
            currencySignCount > 0) {
                return compareComplexAffix(affixPat, text, pos, type, currency);
        }
        if (isPrefix) {
            return compareSimpleAffix(isNegative ? negativePrefix : positivePrefix,
                                      text, pos);
        } else {
            return compareSimpleAffix(isNegative ? negativeSuffix : positiveSuffix,
                                      text, pos);
        }

    }



    /**
     * Return the length matched by the given affix, or -1 if none.
     * Runs of white space in the affix, match runs of white space in
     * the input.  Pattern white space and input white space are
     * determined differently; see code.
     * @param affix pattern string, taken as a literal
     * @param input input text
     * @param pos offset into input at which to begin matching
     * @return length of input that matches, or -1 if match failure
     */
    private static int compareSimpleAffix(String affix, String input, int pos) {
        int start = pos;
        for (int i=0; i<affix.length(); ) {
            int c = UTF16.charAt(affix, i);
            int len = UTF16.getCharCount(c);
            if (UCharacterProperty.isRuleWhiteSpace(c)) {
                // We may have a pattern like: \u200F \u0020
                //        and input text like: \u200F \u0020
                // Note that U+200F and U+0020 are RuleWhiteSpace but only
                // U+0020 is UWhiteSpace.  So we have to first do a direct
                // match of the run of RULE whitespace in the pattern,
                // then match any extra characters.
                boolean literalMatch = false;
                while (pos < input.length() &&
                       UTF16.charAt(input, pos) == c) {
                    literalMatch = true;
                    i += len;
                    pos += len;
                    if (i == affix.length()) {
                        break;
                    }
                    c = UTF16.charAt(affix, i);
                    len = UTF16.getCharCount(c);
                    if (!UCharacterProperty.isRuleWhiteSpace(c)) {
                        break;
                    }
                }
               
                // Advance over run in affix
                i = skipRuleWhiteSpace(affix, i);
               
                // Advance over run in input text
                // Must see at least one white space char in input,
                // unless we've already matched some characters literally.
                int s = pos;
                pos = skipUWhiteSpace(input, pos);
                if (pos == s && !literalMatch) {
                    return -1;
                }
                // If we skip UWhiteSpace in the input text, we need to skip it in the pattern.
                // Otherwise, the previous lines may have skipped over text (such as U+00A0) that
                // is also in the affix.
                i = skipUWhiteSpace(affix, i);
            } else {
                if (pos < input.length() &&
                    UTF16.charAt(input, pos) == c) {
                    i += len;
                    pos += len;
                } else {
                    return -1;
                }
            }
        }
        return pos - start;
    }

    /**
     * Skip over a run of zero or more isRuleWhiteSpace() characters at
     * pos in text.
     */
    private static int skipRuleWhiteSpace(String text, int pos) {
        while (pos < text.length()) {
            int c = UTF16.charAt(text, pos);
            if (!UCharacterProperty.isRuleWhiteSpace(c)) {
                break;
            }
            pos += UTF16.getCharCount(c);
        }
        return pos;
    }

    /**
     * Skip over a run of zero or more isUWhiteSpace() characters at pos
     * in text.
     */
    private static int skipUWhiteSpace(String text, int pos) {
        while (pos < text.length()) {
            int c = UTF16.charAt(text, pos);
            if (!UCharacter.isUWhiteSpace(c)) {
                break;
            }
            pos += UTF16.getCharCount(c);
        }
        return pos;
    }

    /*
     * Return the length matched by the given affix, or -1 if none.
     * @param affixPat pattern string
     * @param text input text
     * @param pos offset into input at which to begin matching
     * @param type parse against currency type, LONG_NAME only or not.
     * @param currency return value for parsed currency, for generic
     * currency parsing mode, or null for normal parsing. In generic
     * currency parsing mode, any currency is parsed, not just the
     * currency that this formatter is set to.
     * @return position after the matched text, or -1 if match failure
     */
    private int compareComplexAffix(String affixPat, String text, int pos,
                                    int type, Currency[] currency) {
        int start = pos;
        for (int i=0;
             i < affixPat.length() && pos >= 0; ) {
            char c = affixPat.charAt(i++);
            if (c == QUOTE) {
                for (;;) {
                    int j = affixPat.indexOf(QUOTE, i);
                    if (j == i) {
                        pos = match(text, pos, QUOTE);
                        i = j+1;
                        break;
                    } else if (j > i) {
                        pos = match(text, pos, affixPat.substring(i, j));
                        i = j+1;
                        if (i<affixPat.length() &&
                            affixPat.charAt(i)==QUOTE) {
                            pos = match(text, pos, QUOTE);
                            ++i;
                            // loop again
                        } else {
                            break;
                        }
                    } else {
                        // Unterminated quote; should be caught by apply
                        // pattern.
                        throw new RuntimeException();
                    }
                }
                continue;
            }

            switch (c) {
            case CURRENCY_SIGN:
                // since the currency names in choice format is saved
                // the same way as other currency names,
                // do not need to do currency choice parsing here.
                // the general currency parsing parse against all names,
                // including names in choice format.
                //assert(currency != null ||
                //       (getCurrency() != null && currencyChoice != null));
                boolean intl = i<affixPat.length() &&
                    affixPat.charAt(i) == CURRENCY_SIGN;
                if (intl) {
                    ++i;
                }
                boolean plural = i<affixPat.length() &&
                    affixPat.charAt(i) == CURRENCY_SIGN;
                if (plural) {
                    ++i;
                    intl = false;
                }
                // Parse generic currency -- anything for which we
                // have a display name, or any 3-letter ISO code.
                // Try to parse display name for our locale; first
                // determine our locale.
                // TODO: use locale in CurrencyPluralInfo
                ULocale uloc = getLocale(ULocale.VALID_LOCALE);
                if (uloc == null) {
                    // applyPattern has been called; use the symbols
                    uloc = symbols.getLocale(ULocale.VALID_LOCALE);
                }
                // Delegate parse of display name => ISO code to Currency
                ParsePosition ppos = new ParsePosition(pos);
                // using Currency.parse to handle mixed style parsing.
                String iso = Currency.parse(uloc, text, type, ppos);

                // If parse succeeds, populate currency[0]
                if (iso != null) {
                    if (currency != null) {
                        currency[0] = Currency.getInstance(iso);
                    }
                    pos = ppos.getIndex();
                } else {
                    pos = -1;
                }
                continue;
            case PATTERN_PERCENT:
                c = symbols.getPercent();
                break;
            case PATTERN_PER_MILLE:
                c = symbols.getPerMill();
                break;
            case PATTERN_MINUS:
                c = symbols.getMinusSign();
                break;
            }
            pos = match(text, pos, c);
            if (UCharacterProperty.isRuleWhiteSpace(c)) {
                i = skipRuleWhiteSpace(affixPat, i);
            }
        }

        return pos - start;
    }

    /**
     * Match a single character at text[pos] and return the index of the
     * next character upon success.  Return -1 on failure.  If
     * isRuleWhiteSpace(ch) then match a run of white space in text.
     */
    static final int match(String text, int pos, int ch) {
        if (pos >= text.length()) {
            return -1;
        }
        if (UCharacterProperty.isRuleWhiteSpace(ch)) {
            // Advance over run of white space in input text
            // Must see at least one white space char in input
            int s = pos;
            pos = skipUWhiteSpace(text, pos);
            if (pos == s) {
                return -1;
            }
            return pos;
        }
        return (pos >= 0 && UTF16.charAt(text, pos) == ch) ?
            (pos + UTF16.getCharCount(ch)) : -1;
    }

    /**
     * Match a string at text[pos] and return the index of the next
     * character upon success.  Return -1 on failure.  Match a run of
     * white space in str with a run of white space in text.
     */
    static final int match(String text, int pos, String str) {
        for (int i=0; i<str.length() && pos >= 0; ) {
            int ch = UTF16.charAt(str, i);
            i += UTF16.getCharCount(ch);
            pos = match(text, pos, ch);
            if (UCharacterProperty.isRuleWhiteSpace(ch)) {
                i = skipRuleWhiteSpace(str, i);
            }
        }
        return pos;
    }

    /**
     * Returns a copy of the decimal format symbols used by this format.
     * @return desired DecimalFormatSymbols
     * @see DecimalFormatSymbols
     * @stable ICU 2.0
     */
    public DecimalFormatSymbols getDecimalFormatSymbols() {
        try {
            // don't allow multiple references
            return (DecimalFormatSymbols) symbols.clone();
        } catch (Exception foo) {
            return null; // should never happen
        }
    }


    /**
     * Sets the decimal format symbols used by this format.  The
     * format uses a copy of the provided symbols.
     * @param newSymbols desired DecimalFormatSymbols
     * @see DecimalFormatSymbols
     * @stable ICU 2.0
     */
    public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) {
        symbols = (DecimalFormatSymbols) newSymbols.clone();
        setCurrencyForSymbols();
        expandAffixes(null);
    }

    /**
     * Update the currency object to match the symbols.  This method
     * is used only when the caller has passed in a symbols object
     * that may not be the default object for its locale.
     */
    private void setCurrencyForSymbols() {
        /*Bug 4212072
          Update the affix strings according to symbols in order to keep
          the affix strings up to date.
          [Richard/GCL]
        */
       
        // With the introduction of the Currency object, the currency
        // symbols in the DFS object are ignored.  For backward
        // compatibility, we check any explicitly set DFS object.  If it
        // is a default symbols object for its locale, we change the
        // currency object to one for that locale.  If it is custom,
        // we set the currency to null.
        DecimalFormatSymbols def =
            new DecimalFormatSymbols(symbols.getLocale());
       
        if (symbols.getCurrencySymbol().equals(
                def.getCurrencySymbol()) &&
            symbols.getInternationalCurrencySymbol().equals(
                def.getInternationalCurrencySymbol())) {
            setCurrency(Currency.getInstance(symbols.getLocale()));
        } else {
            setCurrency(null);
        }
    }

    /**
     * Get the positive prefix.
     * <P>Examples: +123, $123, sFr123
     * @stable ICU 2.0
     */
    public String getPositivePrefix () {
        return positivePrefix;
    }

    /**
     * Set the positive prefix.
     * <P>Examples: +123, $123, sFr123
     * @stable ICU 2.0
     */
    public void setPositivePrefix (String newValue) {
        positivePrefix = newValue;
        posPrefixPattern = null;
    }

    /**
     * Get the negative prefix.
     * <P>Examples: -123, ($123) (with negative suffix), sFr-123
     * @stable ICU 2.0
     */
    public String getNegativePrefix () {
        return negativePrefix;
    }

    /**
     * Set the negative prefix.
     * <P>Examples: -123, ($123) (with negative suffix), sFr-123
     * @stable ICU 2.0
     */
    public void setNegativePrefix (String newValue) {
        negativePrefix = newValue;
        negPrefixPattern = null;
    }

    /**
     * Get the positive suffix.
     * <P>Example: 123%
     * @stable ICU 2.0
     */
    public String getPositiveSuffix () {
        return positiveSuffix;
    }

    /**
     * Set the positive suffix.
     * <P>Example: 123%
     * @stable ICU 2.0
     */
    public void setPositiveSuffix (String newValue) {
        positiveSuffix = newValue;
        posSuffixPattern = null;
    }

    /**
     * Get the negative suffix.
     * <P>Examples: -123%, ($123) (with positive suffixes)
     * @stable ICU 2.0
     */
    public String getNegativeSuffix () {
        return negativeSuffix;
    }

    /**
     * Set the positive suffix.
     * <P>Examples: 123%
     * @stable ICU 2.0
     */
    public void setNegativeSuffix (String newValue) {
        negativeSuffix = newValue;
        negSuffixPattern = null;
    }

    /**
     * Get the multiplier for use in percent, permill, etc.
     * For a percentage, set the suffixes to have "%" and the multiplier to be 100.
     * (For Arabic, use arabic percent symbol).
     * For a permill, set the suffixes to have "\u2031" and the multiplier to be 1000.
     * <P>Examples: with 100, 1.23 -> "123", and "123" -> 1.23
     * @stable ICU 2.0
     */
    public int getMultiplier () {
        return multiplier;
    }

    /**
     * Set the multiplier for use in percent, permill, etc.
     * For a percentage, set the suffixes to have "%" and the multiplier to be 100.
     * (For Arabic, use arabic percent symbol).
     * For a permill, set the suffixes to have "\u2031" and the multiplier to be 1000.
     * <P>Examples: with 100, 1.23 -> "123", and "123" -> 1.23
     * @stable ICU 2.0
     */
    public void setMultiplier (int newValue) {
        if (newValue == 0) {
            throw new IllegalArgumentException("Bad multiplier: " + newValue);
        }
        multiplier = newValue;
    }
   
    // [NEW]
    /**
     * Get the rounding increment.
     * @return A positive rounding increment, or <code>null</code> if rounding
     * is not in effect.
     * @see #setRoundingIncrement
     * @see #getRoundingMode
     * @see #setRoundingMode
     * @stable ICU 2.0
     */
//#if defined(FOUNDATION10) || defined(ECLIPSE_FRAGMENT)
//##    public BigDecimal getRoundingIncrement() {
//##        if (roundingIncrementICU == null) return null;
//##        return new BigDecimal(roundingIncrementICU.toString());
//##    }
//#else
    public java.math.BigDecimal getRoundingIncrement() {
        if (roundingIncrementICU == null) return null;
        return roundingIncrementICU.toBigDecimal();
    }
//#endif
   
//#if defined(FOUNDATION10)
//#else
    // [NEW]
    /**
     * Set the rounding increment.  This method also controls whether
     * rounding is enabled.
     * @param newValue A positive rounding increment, or <code>null</code> or
     * <code>BigDecimal(0.0)</code> to disable rounding.
     * @exception IllegalArgumentException if <code>newValue</code> is < 0.0
     * @see #getRoundingIncrement
     * @see #getRoundingMode
     * @see #setRoundingMode
     * @stable ICU 2.0
     */
    public void setRoundingIncrement(java.math.BigDecimal newValue) {
        if (newValue == null) {
            setRoundingIncrement((BigDecimal)null);
        } else {
            setRoundingIncrement(new BigDecimal(newValue));
        }
    }
//#endif
   
    // [NEW]
    /**
     * Set the rounding increment.  This method also controls whether
     * rounding is enabled.
     * @param newValue A positive rounding increment, or <code>null</code> or
     * <code>BigDecimal(0.0)</code> to disable rounding.
     * @exception IllegalArgumentException if <code>newValue</code> is < 0.0
     * @see #getRoundingIncrement
     * @see #getRoundingMode
     * @see #setRoundingMode
     * @stable ICU 3.6
     */
    public void setRoundingIncrement(BigDecimal newValue) {
        int i = newValue == null
            ? 0 : newValue.compareTo(BigDecimal.ZERO);
        if (i < 0) {
            throw new IllegalArgumentException("Illegal rounding increment");
        }
        if (i == 0) {
            setInternalRoundingIncrement(null);
        } else {
            setInternalRoundingIncrement(newValue);
        }
        setRoundingDouble();
    }

    // [NEW]
    /**
     * Set the rounding increment.  This method also controls whether
     * rounding is enabled.
     * @param newValue A positive rounding increment, or 0.0 to disable
     * rounding.
     * @exception IllegalArgumentException if <code>newValue</code> is < 0.0
     * @see #getRoundingIncrement
     * @see #getRoundingMode
     * @see #setRoundingMode
     * @stable ICU 2.0
     */
    public void setRoundingIncrement(double newValue) {
        if (newValue < 0.0) {
            throw new IllegalArgumentException("Illegal rounding increment");
        }
        roundingDouble = newValue;
        roundingDoubleReciprocal = 0.0d;
        if (newValue == 0.0d) {
            setRoundingIncrement((BigDecimal)null);
        } else {
            roundingDouble = newValue;
            if (roundingDouble < 1.0d) {
                double rawRoundedReciprocal = 1.0d/roundingDouble;
                setRoundingDoubleReciprocal(rawRoundedReciprocal);
            }
            setInternalRoundingIncrement(new BigDecimal(newValue));
        }
    }


    private void setRoundingDoubleReciprocal(double rawRoundedReciprocal) {
        roundingDoubleReciprocal = Math.rint(rawRoundedReciprocal);
        if (Math.abs(rawRoundedReciprocal - roundingDoubleReciprocal) > roundingIncrementEpsilon) {
            roundingDoubleReciprocal = 0.0d;
        }
    }
   
    static final double roundingIncrementEpsilon = 0.000000001;
   
    /**
     * Get the rounding mode.
     * @return A rounding mode, between <code>BigDecimal.ROUND_UP</code>
     * and <code>BigDecimal.ROUND_UNNECESSARY</code>.
     * @see #setRoundingIncrement
     * @see #getRoundingIncrement
     * @see #setRoundingMode
     * @see java.math.BigDecimal
     * @stable ICU 2.0
     */
    public int getRoundingMode() {
        return roundingMode;
    }

    /**
     * Set the rounding mode.  This has no effect unless the rounding
     * increment is greater than zero.
     * @param roundingMode A rounding mode, between
     * <code>BigDecimal.ROUND_UP</code> and
     * <code>BigDecimal.ROUND_UNNECESSARY</code>.
     * @exception IllegalArgumentException if <code>roundingMode</code>
     * is unrecognized.
     * @see #setRoundingIncrement
     * @see #getRoundingIncrement
     * @see #getRoundingMode
     * @see java.math.BigDecimal
     * @stable ICU 2.0
     */
    public void setRoundingMode(int roundingMode) {
        if (roundingMode < BigDecimal.ROUND_UP
            || roundingMode > BigDecimal.ROUND_UNNECESSARY) {
            throw new IllegalArgumentException("Invalid rounding mode: "
                                               + roundingMode);
        }

        this.roundingMode = roundingMode;

        if (getRoundingIncrement() == null) {
            setRoundingIncrement(Math.pow(10.0,(double)-getMaximumFractionDigits()));
        }
    }

    // [NEW]
    /**
     * Get the width to which the output of <code>format()</code> is padded.
     * The width is counted in 16-bit code units.
     * @return the format width, or zero if no padding is in effect
     * @see #setFormatWidth
     * @see #getPadCharacter
     * @see #setPadCharacter
     * @see #getPadPosition
     * @see #setPadPosition
     * @stable ICU 2.0
     */
    public int getFormatWidth() {
        return formatWidth;
    }

    // [NEW]
    /**
     * Set the width to which the output of <code>format()</code> is padded.
     * The width is counted in 16-bit code units.
     * This method also controls whether padding is enabled.
     * @param width the width to which to pad the result of
     * <code>format()</code>, or zero to disable padding
     * @exception IllegalArgumentException if <code>width</code> is < 0
     * @see #getFormatWidth
     * @see #getPadCharacter
     * @see #setPadCharacter
     * @see #getPadPosition
     * @see #setPadPosition
     * @stable ICU 2.0
     */
    public void setFormatWidth(int width) {
        if (width < 0) {
            throw new IllegalArgumentException("Illegal format width");
        }
        formatWidth = width;
    }

    // [NEW]
    /**
     * Get the character used to pad to the format width.  The default is ' '.
     * @return the pad character
     * @see #setFormatWidth
     * @see #getFormatWidth
     * @see #setPadCharacter
     * @see #getPadPosition
     * @see #setPadPosition
     * @stable ICU 2.0
     */
    public char getPadCharacter() {
        return pad;
    }

    // [NEW]
    /**
     * Set the character used to pad to the format width.  If padding
     * is not enabled, then this will take effect if padding is later
     * enabled.
     * @param padChar the pad character
     * @see #setFormatWidth
     * @see #getFormatWidth
     * @see #getPadCharacter
     * @see #getPadPosition
     * @see #setPadPosition
     * @stable ICU 2.0
     */
    public void setPadCharacter(char padChar) {
        pad = padChar;
    }

    // [NEW]
    /**
     * Get the position at which padding will take place.  This is the location
     * at which padding will be inserted if the result of <code>format()</code>
     * is shorter than the format width.
     * @return the pad position, one of <code>PAD_BEFORE_PREFIX</code>,
     * <code>PAD_AFTER_PREFIX</code>, <code>PAD_BEFORE_SUFFIX</code>, or
     * <code>PAD_AFTER_SUFFIX</code>.
     * @see #setFormatWidth
     * @see #getFormatWidth
     * @see #setPadCharacter
     * @see #getPadCharacter
     * @see #setPadPosition
     * @see #PAD_BEFORE_PREFIX
     * @see #PAD_AFTER_PREFIX
     * @see #PAD_BEFORE_SUFFIX
     * @see #PAD_AFTER_SUFFIX
     * @stable ICU 2.0
     */
    public int getPadPosition() {
        return padPosition;
    }

    // [NEW]
    /**
     * Set the position at which padding will take place.  This is the location
     * at which padding will be inserted if the result of <code>format()</code>
     * is shorter than the format width.  This has no effect unless padding is
     * enabled.
     * @param padPos the pad position, one of <code>PAD_BEFORE_PREFIX</code>,
     * <code>PAD_AFTER_PREFIX</code>, <code>PAD_BEFORE_SUFFIX</code>, or
     * <code>PAD_AFTER_SUFFIX</code>.
     * @exception IllegalArgumentException if the pad position in
     * unrecognized
     * @see #setFormatWidth
     * @see #getFormatWidth
     * @see #setPadCharacter
     * @see #getPadCharacter
     * @see #getPadPosition
     * @see #PAD_BEFORE_PREFIX
     * @see #PAD_AFTER_PREFIX
     * @see #PAD_BEFORE_SUFFIX
     * @see #PAD_AFTER_SUFFIX
     * @stable ICU 2.0
     */
    public void setPadPosition(int padPos) {
        if (padPos < PAD_BEFORE_PREFIX || padPos > PAD_AFTER_SUFFIX) {
            throw new IllegalArgumentException("Illegal pad position");
        }
        padPosition = padPos;
    }

    // [NEW]
    /**
     * Return whether or not scientific notation is used.
     * @return true if this object formats and parses scientific notation
     * @see #setScientificNotation
     * @see #getMinimumExponentDigits
     * @see #setMinimumExponentDigits
     * @see #isExponentSignAlwaysShown
     * @see #setExponentSignAlwaysShown
     * @stable ICU 2.0
     */
    public boolean isScientificNotation() {
        return useExponentialNotation;
    }

    // [NEW]
    /**
     * Set whether or not scientific notation is used.  When scientific notation
     * is used, the effective maximum number of integer digits is <= 8.  If the
     * maximum number of integer digits is set to more than 8, the effective
     * maximum will be 1.  This allows this call to generate a 'default' scientific
     * number format without additional changes.
     * @param useScientific true if this object formats and parses scientific
     * notation
     * @see #isScientificNotation
     * @see #getMinimumExponentDigits
     * @see #setMinimumExponentDigits
     * @see #isExponentSignAlwaysShown
     * @see #setExponentSignAlwaysShown
     * @stable ICU 2.0
     */
    public void setScientificNotation(boolean useScientific) {
        useExponentialNotation = useScientific;
    }

    // [NEW]
    /**
     * Return the minimum exponent digits that will be shown.
     * @return the minimum exponent digits that will be shown
     * @see #setScientificNotation
     * @see #isScientificNotation
     * @see #setMinimumExponentDigits
     * @see #isExponentSignAlwaysShown
     * @see #setExponentSignAlwaysShown
     * @stable ICU 2.0
     */
    public byte getMinimumExponentDigits() {
        return minExponentDigits;
    }
   
    // [NEW]
    /**
     * Set the minimum exponent digits that will be shown.  This has no
     * effect unless scientific notation is in use.
     * @param minExpDig a value >= 1 indicating the fewest exponent digits
     * that will be shown
     * @exception IllegalArgumentException if <code>minExpDig</code> < 1
     * @see #setScientificNotation
     * @see #isScientificNotation
     * @see #getMinimumExponentDigits
     * @see #isExponentSignAlwaysShown
     * @see #setExponentSignAlwaysShown
     * @stable ICU 2.0
     */
    public void setMinimumExponentDigits(byte minExpDig) {
        if (minExpDig < 1) {
            throw new IllegalArgumentException("Exponent digits must be >= 1");
        }
        minExponentDigits = minExpDig;
    }

    // [NEW]
    /**
     * Return whether the exponent sign is always shown.
     * @return true if the exponent is always prefixed with either the
     * localized minus sign or the localized plus sign, false if only negative
     * exponents are prefixed with the localized minus sign.
     * @see #setScientificNotation
     * @see #isScientificNotation
     * @see #setMinimumExponentDigits
     * @see #getMinimumExponentDigits
     * @see #setExponentSignAlwaysShown
     * @stable ICU 2.0
     */
    public boolean isExponentSignAlwaysShown() {
        return exponentSignAlwaysShown;
    }

    // [NEW]
    /**
     * Set whether the exponent sign is always shown.  This has no effect
     * unless scientific notation is in use.
     * @param expSignAlways true if the exponent is always prefixed with either
     * the localized minus sign or the localized plus sign, false if only
     * negative exponents are prefixed with the localized minus sign.
     * @see #setScientificNotation
     * @see #isScientificNotation
     * @see #setMinimumExponentDigits
     * @see #getMinimumExponentDigits
     * @see #isExponentSignAlwaysShown
     * @stable ICU 2.0
     */
    public void setExponentSignAlwaysShown(boolean expSignAlways) {
        exponentSignAlwaysShown = expSignAlways;
    }

    /**
     * Return the grouping size. Grouping size is the number of digits between
     * grouping separators in the integer portion of a number.  For example,
     * in the number "123,456.78", the grouping size is 3.
     * @see #setGroupingSize
     * @see NumberFormat#isGroupingUsed
     * @see DecimalFormatSymbols#getGroupingSeparator
     * @stable ICU 2.0
     */
    public int getGroupingSize () {
        return groupingSize;
    }

    /**
     * Set the grouping size. Grouping size is the number of digits between
     * grouping separators in the integer portion of a number.  For example,
     * in the number "123,456.78", the grouping size is 3.
     * @see #getGroupingSize
     * @see NumberFormat#setGroupingUsed
     * @see DecimalFormatSymbols#setGroupingSeparator
     * @stable ICU 2.0
     */
    public void setGroupingSize (int newValue) {
        groupingSize = (byte)newValue;
    }

    // [NEW]
    /**
     * Return the secondary grouping size. In some locales one
     * grouping interval is used for the least significant integer
     * digits (the primary grouping size), and another is used for all
     * others (the secondary grouping size).  A formatter supporting a
     * secondary grouping size will return a positive integer unequal
     * to the primary grouping size returned by
     * <code>getGroupingSize()</code>.  For example, if the primary
     * grouping size is 4, and the secondary grouping size is 2, then
     * the number 123456789 formats as "1,23,45,6789", and the pattern
     * appears as "#,##,###0".
     * @return the secondary grouping size, or a value less than
     * one if there is none
     * @see #setSecondaryGroupingSize
     * @see NumberFormat#isGroupingUsed
     * @see DecimalFormatSymbols#getGroupingSeparator
     * @stable ICU 2.0
     */
    public int getSecondaryGroupingSize () {
        return groupingSize2;
    }

    // [NEW]
    /**
     * Set the secondary grouping size. If set to a value less than 1,
     * then secondary grouping is turned off, and the primary grouping
     * size is used for all intervals, not just the least significant.
     * @see #getSecondaryGroupingSize
     * @see NumberFormat#setGroupingUsed
     * @see DecimalFormatSymbols#setGroupingSeparator
     * @stable ICU 2.0
     */
    public void setSecondaryGroupingSize (int newValue) {
        groupingSize2 = (byte)newValue;
    }

    // [NEW]
    /**
     * Returns the MathContext
     * used by this format.
     * @return desired MathContext
     * @see #mathContext
     * @see #getMathContext
     * @draft ICU 4.2
     * @provisional This API might change or be removed in a future release.
     */
    public MathContext getMathContextICU() {
        return mathContext;
    }

//#if defined(FOUNDATION10) || defined(J2SE13) || defined(J2SE14) || defined(ECLIPSE_FRAGMENT)
//#else
    // [NEW]
    /**
     * Returns the MathContext
     * used by this format.
     * @return desired MathContext
     * @see #mathContext
     * @see #getMathContext
     * @draft ICU 4.2
     * @provisional This API might change or be removed in a future release.
     */
    public java.math.MathContext getMathContext()
    {
        try
        {
            // don't allow multiple references
            return mathContext == null ?
                   null :
                   new java.math.MathContext(mathContext.getDigits(),
                                             java.math.RoundingMode.valueOf(mathContext.getRoundingMode()));
        }
        catch (Exception foo)
        {
            return null; // should never happen
        }
    }
//#endif

    // [NEW]
    /**
     * Sets the MathContext used by this format.
     * @param newValue desired MathContext
     * @see #mathContext
     * @see #getMathContext
     * @draft ICU 4.2
     * @provisional This API might change or be removed in a future release.
     */
    public void setMathContextICU(MathContext newValue) {
        mathContext = newValue;
    }

//#if defined(FOUNDATION10) || defined(J2SE13) || defined(J2SE14) || defined(ECLIPSE_FRAGMENT)
//#else
    // [NEW]
    /**
     * Sets the MathContext used by this format.
     * @param newValue desired MathContext
     * @see #mathContext
     * @see #getMathContext
     * @draft ICU 4.2
     * @provisional This API might change or be removed in a future release.
     */
    public void setMathContext(java.math.MathContext newValue)
    {
        mathContext = new MathContext(newValue.getPrecision(),
                                      MathContext.SCIENTIFIC,
                                      false,
                                      (newValue.getRoundingMode()).ordinal()
                                      );
    }
//#endif

    /**
     * Allows you to get the behavior of the decimal separator with integers.
     * (The decimal separator will always appear with decimals.)
     * <P>Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
     * @stable ICU 2.0
     */
    public boolean isDecimalSeparatorAlwaysShown() {
        return decimalSeparatorAlwaysShown;
    }

    /**
     * Allows you to set the behavior of the decimal separator with integers.
     * (The decimal separator will always appear with decimals.)
     *
     * <p>This only affects formatting, and only where
     * there might be no digits after the decimal point, e.g.,
     * if true,  3456.00 -> "3,456."
     * if false, 3456.00 -> "3456"
     * This is independent of parsing.  If you want parsing to stop at the decimal
     * point, use setParseIntegerOnly.
     *
     * <P>Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
     * @stable ICU 2.0
     */
    public void setDecimalSeparatorAlwaysShown(boolean newValue) {
        decimalSeparatorAlwaysShown = newValue;
    }

    /**
     * Returns a copy of the CurrencyPluralInfo
     * used by this format.
     * It might return null if the decimal format is not a plural type
     * currency decimal format.
     * Plural type currency decimal format means either
     * the pattern in the decimal format contains 3 currency signs,
     * or the decimal format is initialized with PLURALCURRENCYSTYLE.
     * @return desired CurrencyPluralInfo
     * @see CurrencyPluralInfo
     * @draft ICU 4.2
     * @provisional This API might change or be removed in a future release.
     */
    public CurrencyPluralInfo getCurrencyPluralInfo() {
        try {
            // don't allow multiple references
            return currencyPluralInfo == null ?
                   null :
                   (CurrencyPluralInfo) currencyPluralInfo.clone();
        } catch (Exception foo) {
            return null; // should never happen
        }
    }


    /**
     * Sets the CurrencyPluralInfo used by this format.  The
     * format uses a copy of the provided information.
     * @param newInfo desired CurrencyPluralInfo
     * @see CurrencyPluralInfo
     * @draft ICU 4.2
     * @provisional This API might change or be removed in a future release.
     */
    public void setCurrencyPluralInfo(CurrencyPluralInfo newInfo) {
        currencyPluralInfo = (CurrencyPluralInfo) newInfo.clone();
        isReadyForParsing = false;
    }

    /**
     * Standard override; no change in semantics.
     * @stable ICU 2.0
     */
    public Object clone() {
        try {
            DecimalFormat other = (DecimalFormat) super.clone();
            other.symbols = (DecimalFormatSymbols) symbols.clone();
            other.digitList = new DigitList(); // fix for JB#5358
            if (currencyPluralInfo != null) {
                other.currencyPluralInfo = (CurrencyPluralInfo)currencyPluralInfo.clone();
            }
            /*
             * TODO: We need to figure out whether we share a single copy
             * of DigitList by multiple cloned copies.  format/subformat
             * are designed to use a single instance, but parse/subparse
             * implementation is not.
             */
            return other;
        } catch (Exception e) {
            throw new IllegalStateException();
        }
    }

    /**
     * Overrides equals
     * @stable ICU 2.0
     */
    public boolean equals(Object obj)
    {
        if (obj == null) return false;
        if (!super.equals(obj)) return false; // super does class check

        DecimalFormat other = (DecimalFormat) obj;
        /* Add the comparison of the four new added fields ,they are
         * posPrefixPattern, posSuffixPattern, negPrefixPattern, negSuffixPattern.
         * [Richard/GCL]
         */
        // following are added to accomodate changes for currency plural format.
        return currencySignCount == other.currencySignCount
            && (style != NumberFormat.PLURALCURRENCYSTYLE ||
                   equals(posPrefixPattern, other.posPrefixPattern)
                   && equals(posSuffixPattern, other.posSuffixPattern)
                   && equals(negPrefixPattern, other.negPrefixPattern)
                   && equals(negSuffixPattern, other.negSuffixPattern))
            && multiplier == other.multiplier
            && groupingSize == other.groupingSize
            && groupingSize2 == other.groupingSize2
            && decimalSeparatorAlwaysShown == other.decimalSeparatorAlwaysShown
            && useExponentialNotation == other.useExponentialNotation
            && (!useExponentialNotation ||
                minExponentDigits == other.minExponentDigits)
            && useSignificantDigits == other.useSignificantDigits
            && (!useSignificantDigits ||
                minSignificantDigits == other.minSignificantDigits &&
                maxSignificantDigits == other.maxSignificantDigits)
            && symbols.equals(other.symbols)
            && Utility.objectEquals(currencyPluralInfo, other.currencyPluralInfo);
    }

    //method to unquote the strings and compare
    private boolean equals(String pat1, String pat2){
        if (pat1 == null || pat2 == null) {
            return (pat1 == null && pat2 == null);
        }
        //fast path
        if(pat1.equals(pat2)){
            return true;
        }
        return unquote(pat1).equals(unquote(pat2));
    }
    private String unquote(String pat){
        StringBuffer buf = new StringBuffer(pat.length());
        int i=0;
        while(i<pat.length()){
            char ch = pat.charAt(i++);
            if(ch!=QUOTE){
                buf.append(ch);
            }
        }
        return buf.toString();
    }
//      protected void handleToString(StringBuffer buf) {
//          buf.append("\nposPrefixPattern: '" + posPrefixPattern + "'\n");
//          buf.append("positivePrefix: '" + positivePrefix + "'\n");
//          buf.append("posSuffixPattern: '" + posSuffixPattern + "'\n");
//          buf.append("positiveSuffix: '" + positiveSuffix + "'\n");
//          buf.append("negPrefixPattern: '" + com.ibm.icu.impl.Utility.format1ForSource(negPrefixPattern) + "'\n");
//          buf.append("negativePrefix: '" + com.ibm.icu.impl.Utility.format1ForSource(negativePrefix) + "'\n");
//          buf.append("negSuffixPattern: '" + negSuffixPattern + "'\n");
//          buf.append("negativeSuffix: '" + negativeSuffix + "'\n");
//          buf.append("multiplier: '" + multiplier + "'\n");
//          buf.append("groupingSize: '" + groupingSize + "'\n");
//          buf.append("groupingSize2: '" + groupingSize2 + "'\n");
//          buf.append("decimalSeparatorAlwaysShown: '" + decimalSeparatorAlwaysShown + "'\n");
//          buf.append("useExponentialNotation: '" + useExponentialNotation + "'\n");
//          buf.append("minExponentDigits: '" + minExponentDigits + "'\n");
//          buf.append("useSignificantDigits: '" + useSignificantDigits + "'\n");
//          buf.append("minSignificantDigits: '" + minSignificantDigits + "'\n");
//          buf.append("maxSignificantDigits: '" + maxSignificantDigits + "'\n");          
//          buf.append("symbols: '" + symbols + "'");
//      }

    /**
     * Overrides hashCode
     * @stable ICU 2.0
     */
    public int hashCode() {
        return super.hashCode() * 37 + positivePrefix.hashCode();
        // just enough fields for a reasonable distribution
    }

    /**
     * Synthesizes a pattern string that represents the current state
     * of this Format object.
     * @see #applyPattern
     * @stable ICU 2.0
     */
    public String toPattern() {
        if (style == NumberFormat.PLURALCURRENCYSTYLE) {
            // the prefix or suffix pattern might not be defined yet,
            // so they can not be synthesized,
            // instead, get them directly.
            // but it might not be the actual pattern used in formatting.
            // the actual pattern used in formatting depends on the
            // formatted number's plural count.
            return formatPattern;
        }
        return toPattern( false );
    }

    /**
     * Synthesizes a localized pattern string that represents the current
     * state of this Format object.
     * @see #applyPattern
     * @stable ICU 2.0
     */
    public String toLocalizedPattern() {
        if (style == NumberFormat.PLURALCURRENCYSTYLE) {
            return formatPattern;
        }
        return toPattern( true );
    }

    /**
     * Expand the affix pattern strings into the expanded affix strings.  If any
     * affix pattern string is null, do not expand it.  This method should be
     * called any time the symbols or the affix patterns change in order to keep
     * the expanded affix strings up to date.
     * This method also will be called before formatting if format currency
     * plural names, since the plural name is not a static one, it is
     * based on the currency plural count, the affix will be known only
     * after the currency plural count is know.
     * In which case, the parameter
     * 'pluralCount' will be a non-null currency plural count.
     * In all other cases, the 'pluralCount' is null, which means
     * it is not needed.
     */
    //Bug 4212072 [Richard/GCL]
    private void expandAffixes(String pluralCount) {
        // expandAffix() will set currencyChoice to a non-null value if
        // appropriate AND if it is null.
        currencyChoice = null;

        // Reuse one StringBuffer for better performance
        StringBuffer buffer = new StringBuffer();
        if (posPrefixPattern != null) {
            expandAffix(posPrefixPattern, pluralCount, buffer, false);
            positivePrefix = buffer.toString();
        }
        if (posSuffixPattern != null) {
            expandAffix(posSuffixPattern, pluralCount, buffer, false);
            positiveSuffix = buffer.toString();
        }
        if (negPrefixPattern != null) {
            expandAffix(negPrefixPattern, pluralCount, buffer, false);
            negativePrefix = buffer.toString();
        }
        if (negSuffixPattern != null) {
            expandAffix(negSuffixPattern, pluralCount, buffer, false);
            negativeSuffix = buffer.toString();
        }
    }

    /**
     * Expand an affix pattern into an affix string.  All characters in
     * the pattern are literal unless bracketed by QUOTEs.  The
     * following characters outside QUOTE are recognized:
     * PATTERN_PERCENT, PATTERN_PER_MILLE, PATTERN_MINUS, and
     * CURRENCY_SIGN.  If CURRENCY_SIGN is doubled, it is interpreted as
     * an international currency sign.  If CURRENCY_SIGN is tripled,
     * it is interpreted as currency plural long names, such as "US Dollars".
     * Any other character outside
     * QUOTE represents itself.  Quoted text must be well-formed.
     *
     * This method is used in two distinct ways.  First, it is used to expand
     * the stored affix patterns into actual affixes.  For this usage, doFormat
     * must be false.  Second, it is used to expand the stored affix patterns
     * given a specific number (doFormat == true), for those rare cases in
     * which a currency format references a ChoiceFormat (e.g., en_IN display
     * name for INR).  The number itself is taken from digitList.
     *
     * When used in the first way, this method has a side effect: It sets
     * currencyChoice to a ChoiceFormat object, if the currency's display name
     * in this locale is a ChoiceFormat pattern (very rare).  It only does this
     * if currencyChoice is null to start with.
     *
     * @param pattern the non-null, possibly empty pattern
     * @param pluralCount the plural count. It is only used for currency
     *                    plural format. In which case, it is the plural
     *                    count of the currency amount. For example,
     *                    in en_US, it is the singular "one", or the plural
     *                    "other". For all other cases, it is null, and
     *                    is not being used.
     * @param buffer a scratch StringBuffer; its contents will be lost
     * @param doFormat if false, then the pattern will be expanded, and if a
     * currency symbol is encountered that expands to a ChoiceFormat, the
     * currencyChoice member variable will be initialized if it is null.  If
     * doFormat is true, then it is assumed that the currencyChoice has been
     * created, and it will be used to format the value in digitList.
     * @return the expanded equivalent of pattern
     */
    //Bug 4212072 [Richard/GCL]
    private void expandAffix(String pattern,
                             String pluralCount,
                             StringBuffer buffer,
                             boolean doFormat) {
        buffer.setLength(0);
        for (int i=0; i<pattern.length(); ) {
            char c = pattern.charAt(i++);
            if (c == QUOTE) {
                for (;;) {
                    int j = pattern.indexOf(QUOTE, i);
                    if (j == i) {
                        buffer.append(QUOTE);
                        i = j+1;
                        break;
                    } else if (j > i) {
                        buffer.append(pattern.substring(i, j));
                        i = j+1;
                        if (i<pattern.length() &&
                            pattern.charAt(i)==QUOTE) {
                            buffer.append(QUOTE);
                            ++i;
                            // loop again
                        } else {
                            break;
                        }
                    } else {
                        // Unterminated quote; should be caught by apply
                        // pattern.
                        throw new RuntimeException();
                    }
                }
                continue;
            }

            switch (c) {
            case CURRENCY_SIGN:
                // As of ICU 2.2 we use the currency object, and
                // ignore the currency symbols in the DFS, unless
                // we have a null currency object.  This occurs if
                // resurrecting a pre-2.2 object or if the user
                // sets a custom DFS.
                boolean intl = i<pattern.length() &&
                    pattern.charAt(i) == CURRENCY_SIGN;
                boolean plural = false;
                if (intl) {
                    ++i;
                    if (i<pattern.length() &&
                        pattern.charAt(i) == CURRENCY_SIGN) {
                        plural = true;
                        intl = false;
                        ++i;
                    }
                }
                String s = null;
                Currency currency = getCurrency();
                if (currency != null) {
                    // plural name is only needed when pluralCount != null,
                    // which means when formatting currency plural names.
                    // For other cases, pluralCount == null,
                    // and plural names are not needed.
                    if (plural && pluralCount != null) {
                        boolean isChoiceFormat[] = new boolean[1];
                        s = currency.getName(symbols.getULocale(),
                                             Currency.PLURAL_LONG_NAME,
                                             pluralCount,
                                             isChoiceFormat);
                    }
                    else if (!intl) {
                        boolean isChoiceFormat[] = new boolean[1];
                        s = currency.getName(symbols.getULocale(),
                                             Currency.SYMBOL_NAME,
                                             isChoiceFormat);
                        if (isChoiceFormat[0]) {
                            // Two modes here: If doFormat is false, we set up
                            // currencyChoice.  If doFormat is true, we use the
                            // previously created currencyChoice to format the
                            // value in digitList.
                            if (!doFormat) {
                                // If the currency is handled by a ChoiceFormat,
                                // then we're not going to use the expanded
                                // patterns.  Instantiate the ChoiceFormat and
                                // return.
                                if (currencyChoice == null) {
                                    currencyChoice = new ChoiceFormat(s);
                                }
                                // We could almost return null or "" here, since the
                                // expanded affixes are almost not used at all
                                // in this situation.  However, one method --
                                // toPattern() -- still does use the expanded
                                // affixes, in order to set up a padding
                                // pattern.  We use the CURRENCY_SIGN as a
                                // placeholder.
                                s = String.valueOf(CURRENCY_SIGN);
                            } else {
                                FieldPosition pos = new FieldPosition(0); // ignored
                                currencyChoice.format(digitList.getDouble(), buffer, pos);
                                continue;
                            }
                        }
                    } else {
                        s = currency.getCurrencyCode();
                    }
                } else {
                    s = intl ? symbols.getInternationalCurrencySymbol()
                        : symbols.getCurrencySymbol();
                }
                buffer.append(s);
                continue;
            case PATTERN_PERCENT:
                c = symbols.getPercent();
                break;
            case PATTERN_PER_MILLE:
                c = symbols.getPerMill();
                break;
            case PATTERN_MINUS:
                c = symbols.getMinusSign();
                break;
            }
            buffer.append(c);
        }
    }

    /**
     * Append an affix to the given StringBuffer.
     * @param buf buffer to append to
     * @param isNegative
     * @param isPrefix
     */
    private int appendAffix(StringBuffer buf, boolean isNegative,
            boolean isPrefix, boolean parseAttr) {
        if (currencyChoice != null) {
            String affixPat = null;
            if (isPrefix) {
                affixPat = isNegative ? negPrefixPattern : posPrefixPattern;
            } else {
                affixPat = isNegative ? negSuffixPattern : posSuffixPattern;
            }
            StringBuffer affixBuf = new StringBuffer();
            expandAffix(affixPat, null, affixBuf, true);
            buf.append(affixBuf.toString());
            return affixBuf.length();
        }

        String affix = null;
        if (isPrefix) {
            affix = isNegative ? negativePrefix : positivePrefix;
        } else {
            affix = isNegative ? negativeSuffix : positiveSuffix;
        }
//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
        // [Spark/CDL] Invoke formatAffix2Attribute to add attributes for affix
        if (parseAttr) {
            int offset = affix.indexOf(symbols.getCurrencySymbol());
            if (-1 == offset) {
                offset = affix.indexOf(symbols.getPercent());
                if(-1 == offset) {
                    offset = 0;
                }
            }
            formatAffix2Attribute(affix, buf.length() + offset, buf.length()
                    + affix.length());
        }
//#endif
        buf.append(affix);
        return affix.length();
    }

//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
    /*
     * [Spark/CDL] This is a newly added method, used to add attributes for
     * prefix and suffix.
     */
    private void formatAffix2Attribute(String affix, int begin, int end) {
        // [Spark/CDL] It is the invoker's responsibility to ensure that, before
        // the invocation of
        // this method, attributes is not null.
        // if( attributes == null ) return;
        if (affix.indexOf(symbols.getCurrencySymbol()) > -1) {
            addAttribute(Field.CURRENCY, begin, end);
        } else if (affix.indexOf(symbols.getMinusSign()) > -1) {
            addAttribute(Field.SIGN, begin, end);
        } else if (affix.indexOf(symbols.getPercent()) > -1) {
            addAttribute(Field.PERCENT, begin, end);
        } else if (affix.indexOf(symbols.getPerMill()) > -1) {
            addAttribute(Field.PERMILLE, begin, end);
        }
    }
//#endif

//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
    /*
     * [Spark/CDL] Use this method to add attribute.
     */
    private void addAttribute(Field field, int begin, int end) {
        FieldPosition pos = new FieldPosition(field);
        pos.setBeginIndex(begin);
        pos.setEndIndex(end);
        attributes.add(pos);
    }
//#endif

//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
    /**
     * Format the object to an attributed string, and return the corresponding iterator
     * Overrides superclass method.
     * @stable ICU 3.6
     */
    // [Spark/CDL]
    public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
        if (!(obj instanceof Number))
            throw new IllegalArgumentException();
        Number number = (Number) obj;
        StringBuffer text = null;
        attributes.clear();
        if (obj instanceof BigInteger) {
            text = format((BigInteger) number, new StringBuffer(),
                    new FieldPosition(0), true);
        } else if (obj instanceof java.math.BigDecimal) {
            text = format((java.math.BigDecimal) number, new StringBuffer(),
                    new FieldPosition(0), true);
        } else if (obj instanceof Double) {
            text = format(number.doubleValue(), new StringBuffer(),
                    new FieldPosition(0), true);
        } else if (obj instanceof Integer || obj instanceof Long) {
            text = format(number.longValue(), new StringBuffer(),
                    new FieldPosition(0), true);
        }

        AttributedString as = new AttributedString(text.toString());

        // add NumberFormat field attributes to the AttributedString
        for (int i = 0; i < attributes.size(); i++) {
            FieldPosition pos = (FieldPosition) attributes.get(i);
            Format.Field attribute = pos.getFieldAttribute();
            as.addAttribute(attribute, attribute, pos.getBeginIndex(), pos
                    .getEndIndex());
        }

        // return the CharacterIterator from AttributedString
        return as.getIterator();
    }
//#endif
    /**
     * Append an affix pattern to the given StringBuffer.  Localize unquoted
     * specials.
     */
    private void appendAffixPattern(StringBuffer buffer,
                                    boolean isNegative, boolean isPrefix,
                                    boolean localized) {
        String affixPat = null;
        if (isPrefix) {
            affixPat = isNegative ? negPrefixPattern : posPrefixPattern;
        } else {
            affixPat = isNegative ? negSuffixPattern : posSuffixPattern;
        }

        // When there is a null affix pattern, we use the affix itself.
        if (affixPat == null) {
            String affix = null;
            if (isPrefix) {
                affix = isNegative ? negativePrefix : positivePrefix;
            } else {
                affix = isNegative ? negativeSuffix : positiveSuffix;
            }
            // Do this crudely for now:  Wrap everything in quotes.
            buffer.append(QUOTE);
            for (int i=0; i<affix.length(); ++i) {
                char ch = affix.charAt(i);
                if (ch == QUOTE) {
                    buffer.append(ch);
                }
                buffer.append(ch);
            }
            buffer.append(QUOTE);
            return;
        }

        if (!localized) {
            buffer.append(affixPat);
        } else {
            int i, j;
            for (i=0; i<affixPat.length(); ++i) {
                char ch = affixPat.charAt(i);
                switch (ch) {
                case QUOTE:
                    j = affixPat.indexOf(QUOTE, i+1);
                    if (j < 0) {
                        throw new IllegalArgumentException("Malformed affix pattern: " + affixPat);
                    }
                    buffer.append(affixPat.substring(i, j+1));
                    i = j;
                    continue;
                case PATTERN_PER_MILLE:
                    ch = symbols.getPerMill();
                    break;
                case PATTERN_PERCENT:
                    ch = symbols.getPercent();
                    break;
                case PATTERN_MINUS:
                    ch = symbols.getMinusSign();
                    break;
                }
                //check if char is same as any other symbol
                if(ch==symbols.getDecimalSeparator() ||
                   ch==symbols.getGroupingSeparator() ){
                    buffer.append(QUOTE);
                    buffer.append(ch);
                    buffer.append(QUOTE);
                }else{
                    buffer.append(ch);
                }
            }
        }
    }

    /**
     * <strong><font face=helvetica color=red>CHANGED</font></strong>
     * Does the real work of generating a pattern.
     */
    private String toPattern(boolean localized) {
        StringBuffer result = new StringBuffer();
        char zero = localized ? symbols.getZeroDigit() : PATTERN_ZERO_DIGIT;
        char digit = localized ? symbols.getDigit() : PATTERN_DIGIT;
        char sigDigit = 0;
        boolean useSigDig = areSignificantDigitsUsed();
        if (useSigDig) {
            sigDigit = localized ? symbols.getSignificantDigit() : PATTERN_SIGNIFICANT_DIGIT;
        }
        char group = localized ? symbols.getGroupingSeparator()
                               : PATTERN_GROUPING_SEPARATOR;
        int i;
        int roundingDecimalPos = 0; // Pos of decimal in roundingDigits
        String roundingDigits = null;
        int padPos = (formatWidth > 0) ? padPosition : -1;
        String padSpec = (formatWidth > 0)
            ? new StringBuffer(2).
                append(localized ? symbols.getPadEscape() : PATTERN_PAD_ESCAPE).
                append(pad).toString()
            : null;
        if (roundingIncrementICU != null) {
            i = roundingIncrementICU.scale();
            roundingDigits = roundingIncrementICU.movePointRight(i).toString();
            roundingDecimalPos = roundingDigits.length() - i;
        }
        for (int part=0; part<2; ++part) {
            // variable not used int partStart = result.length();
            if (padPos == PAD_BEFORE_PREFIX) {
                result.append(padSpec);
            }
            /* Use original symbols read from resources in pattern
             * eg. use "\u00A4" instead of "$" in Locale.US [Richard/GCL]
             */
            appendAffixPattern(result, part!=0, true, localized);
            if (padPos == PAD_AFTER_PREFIX) {
                result.append(padSpec);
            }
            int sub0Start = result.length();
            int g = isGroupingUsed() ? Math.max(0, groupingSize) : 0;
            if (g > 0 && groupingSize2 > 0 && groupingSize2 != groupingSize) {
                g += groupingSize2;
            }
            int maxDig = 0, minDig = 0, maxSigDig = 0;
            if (useSigDig) {
                minDig = getMinimumSignificantDigits();
                maxDig = maxSigDig = getMaximumSignificantDigits();
            } else {
                minDig = getMinimumIntegerDigits();
                maxDig = getMaximumIntegerDigits();
            }
            if (useExponentialNotation) {
                if (maxDig > MAX_SCIENTIFIC_INTEGER_DIGITS) {
                    maxDig = 1;
                }
            } else if (useSigDig) {
                maxDig = Math.max(maxDig, g+1);
            } else {
                maxDig = Math.max(Math.max(g, getMinimumIntegerDigits()),
                                  roundingDecimalPos) + 1;
            }
            for (i = maxDig; i > 0; --i) {
                if (!useExponentialNotation && i<maxDig &&
                    isGroupingPosition(i)) {
                    result.append(group);
                }
                if (useSigDig) {
                    //  #@,@###   (maxSigDig == 5, minSigDig == 2)
                    //  65 4321   (1-based pos, count from the right)
                    // Use # if pos > maxSigDig or 1 <= pos <= (maxSigDig - minSigDig)
                    // Use @ if (maxSigDig - minSigDig) < pos <= maxSigDig
                    result.append((maxSigDig >= i && i > (maxSigDig - minDig)) ? sigDigit : digit);
                } else {
                    if (roundingDigits != null) {
                        int pos = roundingDecimalPos - i;
                        if (pos >= 0 && pos < roundingDigits.length()) {
                            result.append((char) (roundingDigits.charAt(pos) - '0' + zero));
                            continue;
                        }
                    }
                    result.append(i<=minDig ? zero : digit);
                }
            }
            if (!useSigDig) {
                if (getMaximumFractionDigits() > 0 || decimalSeparatorAlwaysShown) {
                    result.append(localized ? symbols.getDecimalSeparator() :
                                  PATTERN_DECIMAL_SEPARATOR);
                }
                int pos = roundingDecimalPos;
                for (i = 0; i < getMaximumFractionDigits(); ++i) {
                    if (roundingDigits != null &&
                        pos < roundingDigits.length()) {
                        result.append(pos < 0 ? zero :
                                      (char) (roundingDigits.charAt(pos) - '0' + zero));
                        ++pos;
                        continue;
                    }
                    result.append(i<getMinimumFractionDigits() ? zero : digit);
                }
            }
            if (useExponentialNotation) {
                if(localized ){
                    result.append(symbols.getExponentSeparator() );
                }else{
                    result.append(PATTERN_EXPONENT);
                }
                if (exponentSignAlwaysShown) {
                    result.append(localized ? symbols.getPlusSign() :
                                  PATTERN_PLUS_SIGN);
                }
                for (i=0; i<minExponentDigits; ++i) {
                    result.append(zero);
                }
            }
            if (padSpec != null && !useExponentialNotation) {
                int add = formatWidth - result.length() + sub0Start
                    - ((part == 0)
                       ? positivePrefix.length() + positiveSuffix.length()
                       : negativePrefix.length() + negativeSuffix.length());
                while (add > 0) {
                    result.insert(sub0Start, digit);
                    ++maxDig;
                    --add;
                    // Only add a grouping separator if we have at least
                    // 2 additional characters to be added, so we don't
                    // end up with ",###".
                    if (add>1 && isGroupingPosition(maxDig)) {
                        result.insert(sub0Start, group);
                        --add;                       
                    }
                }
            }
            if (padPos == PAD_BEFORE_SUFFIX) {
                result.append(padSpec);
            }
            /* Use original symbols read from resources in pattern
             * eg. use "\u00A4" instead of "$" in Locale.US [Richard/GCL]
             */
            appendAffixPattern(result, part!=0, false, localized);
            if (padPos == PAD_AFTER_SUFFIX) {
                result.append(padSpec);
            }
            if (part == 0) {
                if (negativeSuffix.equals(positiveSuffix) &&
                    negativePrefix.equals( PATTERN_MINUS + positivePrefix)) {
                    break;
                } else {
                    result.append(localized ? symbols.getPatternSeparator() :
                                  PATTERN_SEPARATOR);
                }
            }
        }
        return result.toString();
    }

    /**
     * Apply the given pattern to this Format object.  A pattern is a
     * short-hand specification for the various formatting properties.
     * These properties can also be changed individually through the
     * various setter methods.
     * <p>
     * There is no limit to integer digits are set
     * by this routine, since that is the typical end-user desire;
     * use setMaximumInteger if you want to set a real value.
     * For negative numbers, use a second pattern, separated by a semicolon
     * <P>Example "#,#00.0#" -> 1,234.56
     * <P>This means a minimum of 2 integer digits, 1 fraction digit, and
     * a maximum of 2 fraction digits.
     * <p>Example: "#,#00.0#;(#,#00.0#)" for negatives in parentheses.
     * <p>In negative patterns, the minimum and maximum counts are ignored;
     * these are presumed to be set in the positive pattern.
     * @stable ICU 2.0
     */
    public void applyPattern( String pattern ) {
        applyPattern( pattern, false );
    }

    /**
     * Apply the given pattern to this Format object.  The pattern
     * is assumed to be in a localized notation. A pattern is a
     * short-hand specification for the various formatting properties.
     * These properties can also be changed individually through the
     * various setter methods.
     * <p>
     * There is no limit to integer digits are set
     * by this routine, since that is the typical end-user desire;
     * use setMaximumInteger if you want to set a real value.
     * For negative numbers, use a second pattern, separated by a semicolon
     * <P>Example "#,#00.0#" -> 1,234.56
     * <P>This means a minimum of 2 integer digits, 1 fraction digit, and
     * a maximum of 2 fraction digits.
     * <p>Example: "#,#00.0#;(#,#00.0#)" for negatives in parantheses.
     * <p>In negative patterns, the minimum and maximum counts are ignored;
     * these are presumed to be set in the positive pattern.
     * @stable ICU 2.0
     */
    public void applyLocalizedPattern( String pattern ) {
        applyPattern( pattern, true );
    }

  
    /**
     * <strong><font face=helvetica color=red>CHANGED</font></strong>
     * Does the real work of applying a pattern.
     */
    private void applyPattern(String pattern, boolean localized) {
        applyPatternWithoutExpandAffix(pattern, localized);
        expandAffixAdjustWidth(null);
    }

    private void expandAffixAdjustWidth(String pluralCount) {
        /*Bug 4212072
          Update the affix strings according to symbols in order to keep
          the affix strings up to date.
          [Richard/GCL]
        */
        expandAffixes(pluralCount);

        // Now that we have the actual prefix and suffix, fix up formatWidth
        if (formatWidth > 0) {
            formatWidth += positivePrefix.length() + positiveSuffix.length();
        }
    }

    private void applyPatternWithoutExpandAffix(String pattern, boolean localized) {
        char zeroDigit         = PATTERN_ZERO_DIGIT; // '0'
        char sigDigit          = PATTERN_SIGNIFICANT_DIGIT; // '@'
        char groupingSeparator = PATTERN_GROUPING_SEPARATOR;
        char decimalSeparator  = PATTERN_DECIMAL_SEPARATOR;
        char percent           = PATTERN_PERCENT;
        char perMill           = PATTERN_PER_MILLE;
        char digit             = PATTERN_DIGIT; // '#'
        char separator         = PATTERN_SEPARATOR;
        String exponent        = String.valueOf(PATTERN_EXPONENT);
        char plus              = PATTERN_PLUS_SIGN;
        char padEscape         = PATTERN_PAD_ESCAPE;
        char minus             = PATTERN_MINUS; //Bug 4212072 [Richard/GCL]
        if (localized) {
            zeroDigit         = symbols.getZeroDigit();
            sigDigit          = symbols.getSignificantDigit();
            groupingSeparator = symbols.getGroupingSeparator();
            decimalSeparator  = symbols.getDecimalSeparator();
            percent           = symbols.getPercent();
            perMill           = symbols.getPerMill();
            digit             = symbols.getDigit();
            separator         = symbols.getPatternSeparator();
            exponent          = symbols.getExponentSeparator();
            plus              = symbols.getPlusSign();
            padEscape         = symbols.getPadEscape();
            minus             = symbols.getMinusSign(); //Bug 4212072 [Richard/GCL]
        }
        char nineDigit = (char) (zeroDigit + 9);

        boolean gotNegative = false;

        int pos = 0;
        // Part 0 is the positive pattern.  Part 1, if present, is the negative
        // pattern.
        for (int part=0; part<2 && pos<pattern.length(); ++part) {
            // The subpart ranges from 0 to 4: 0=pattern proper, 1=prefix,
            // 2=suffix, 3=prefix in quote, 4=suffix in quote.  Subpart 0 is
            // between the prefix and suffix, and consists of pattern
            // characters.  In the prefix and suffix, percent, permille, and
            // currency symbols are recognized and translated.
            int subpart = 1, sub0Start = 0, sub0Limit = 0, sub2Limit = 0;

            // It's important that we don't change any fields of this object
            // prematurely.  We set the following variables for the multiplier,
            // grouping, etc., and then only change the actual object fields if
            // everything parses correctly.  This also lets us register
            // the data from part 0 and ignore the part 1, except for the
            // prefix and suffix.
            StringBuffer prefix = new StringBuffer();
            StringBuffer suffix = new StringBuffer();
            int decimalPos = -1;
            int multpl = 1;
            int digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0, sigDigitCount = 0;
            byte groupingCount = -1;
            byte groupingCount2 = -1;
            int padPos = -1;
            char padChar = 0;
            int incrementPos = -1;
            long incrementVal = 0;
            byte expDigits = -1;
            boolean expSignAlways = false;

            // The affix is either the prefix or the suffix.
            StringBuffer affix = prefix;

            int start = pos;

        PARTLOOP:
            for (; pos < pattern.length(); ++pos) {
                char ch = pattern.charAt(pos);
                switch (subpart) {
                case 0: // Pattern proper subpart (between prefix & suffix)
                    // Process the digits, decimal, and grouping characters.  We
                    // record five pieces of information.  We expect the digits
                    // to occur in the pattern ####00.00####, and we record the
                    // number of left digits, zero (central) digits, and right
                    // digits.  The position of the last grouping character is
                    // recorded (should be somewhere within the first two blocks
                    // of characters), as is the position of the decimal point,
                    // if any (should be in the zero digits).  If there is no
                    // decimal point, then there should be no right digits.
                    if (ch == digit) {
                        if (zeroDigitCount > 0 || sigDigitCount > 0) {
                            ++digitRightCount;
                        } else {
                            ++digitLeftCount;
                        }
                        if (groupingCount >= 0 && decimalPos < 0) {
                            ++groupingCount;
                        }
                    } else if ((ch >= zeroDigit && ch <= nineDigit) ||
                               ch == sigDigit) {
                        if (digitRightCount > 0) {
                            patternError("Unexpected '" + ch + '\'', pattern);
                        }
                        if (ch == sigDigit) {
                            ++sigDigitCount;
                        } else {
                            ++zeroDigitCount;
                            if (ch != zeroDigit) {
                                int p = digitLeftCount + zeroDigitCount
                                    + digitRightCount;
                                if (incrementPos >= 0) {
                                    while (incrementPos < p) {
                                        incrementVal *= 10;
                                        ++incrementPos;
                                    }
                                } else {
                                    incrementPos = p;
                                }
                                incrementVal += ch - zeroDigit;
                            }
                        }
                        if (groupingCount >= 0 && decimalPos < 0) {
                            ++groupingCount;
                        }
                    } else if (ch == groupingSeparator) {
                        /*Bug 4212072
                          process the Localized pattern like "'Fr. '#'##0.05;'Fr.-'#'##0.05"
                          (Locale="CH", groupingSeparator == QUOTE)                         
                          [Richard/GCL]
                        */
                        if (ch == QUOTE && (pos+1) < pattern.length()) {
                            char after = pattern.charAt(pos+1);
                            if (!(after == digit || (after >= zeroDigit && after <= nineDigit))) {
                                // A quote outside quotes indicates either the opening
                                // quote or two quotes, which is a quote literal.  That is,
                                // we have the first quote in 'do' or o''clock.
                                if (after == QUOTE) {
                                    ++pos;
                                    // Fall through to append(ch)
                                } else {
                                    if (groupingCount < 0) {
                                        subpart = 3; // quoted prefix subpart
                                    } else {
                                      // Transition to suffix subpart
                                      subpart = 2; // suffix subpart
                                      affix = suffix;
                                      sub0Limit = pos--;
                                    }
                                    continue;
                                }
                            }
                        }
                       
                        if (decimalPos >= 0) {
                            patternError("Grouping separator after decimal", pattern);
                        }
                        groupingCount2 = groupingCount;
                        groupingCount = 0;
                    } else if (ch == decimalSeparator) {
                        if (decimalPos >= 0) {
                            patternError("Multiple decimal separators", pattern);
                        }
                        // Intentionally incorporate the digitRightCount,
                        // even though it is illegal for this to be > 0
                        // at this point.  We check pattern syntax below.
                        decimalPos = digitLeftCount + zeroDigitCount + digitRightCount;
                    } else {
                        if (pattern.regionMatches(pos, exponent, 0, exponent.length())) {
                            if (expDigits >= 0) {
                                patternError("Multiple exponential symbols", pattern);
                            }
                            if (groupingCount >= 0) {
                                patternError("Grouping separator in exponential", pattern);
                            }
                            pos += exponent.length();
                            // Check for positive prefix
                            if (pos < pattern.length()
                                && pattern.charAt(pos) == plus) {
                                expSignAlways = true;
                                ++pos;
                            }
                            // Use lookahead to parse out the exponential part of the
                            // pattern, then jump into suffix subpart.
                            expDigits = 0;
                            while (pos < pattern.length() &&
                                   pattern.charAt(pos) == zeroDigit) {
                                ++expDigits;
                                ++pos;
                            }
                           
                            // 1. Require at least one mantissa pattern digit
                            // 2. Disallow "#+ @" in mantissa
                            // 3. Require at least one exponent pattern digit
                            if (((digitLeftCount + zeroDigitCount) < 1 &&
                                 (sigDigitCount + digitRightCount) < 1) ||
                                (sigDigitCount > 0 && digitLeftCount > 0) ||
                                expDigits < 1) {
                                patternError("Malformed exponential", pattern);
                            }
                        }
                        // Transition to suffix subpart
                        subpart = 2; // suffix subpart
                        affix = suffix;
                        sub0Limit = pos--; // backup: for() will increment
                        continue;
                    }
                    break;
                case 1: // Prefix subpart
                case 2: // Suffix subpart
                    // Process the prefix / suffix characters
                    // Process unquoted characters seen in prefix or suffix
                    // subpart.
                   
                    // Several syntax characters implicitly begins the
                    // next subpart if we are in the prefix; otherwise
                    // they are illegal if unquoted.
                    if (ch == digit ||
                        ch == groupingSeparator ||
                        ch == decimalSeparator ||
                        (ch >= zeroDigit && ch <= nineDigit) ||
                        ch == sigDigit) {
                        // Any of these characters implicitly begins the
                        // next subpart if we are in the prefix
                        if (subpart == 1) { // prefix subpart
                            subpart = 0; // pattern proper subpart
                            sub0Start = pos--; // Reprocess this character
                            continue;
                        } else if (ch == QUOTE) {
                            /*Bug 4212072
                              process the Localized pattern like "'Fr. '#'##0.05;'Fr.-'#'##0.05"
                              (Locale="CH", groupingSeparator == QUOTE)                         
                              [Richard/GCL]
                            */
                            // A quote outside quotes indicates either the opening
                            // quote or two quotes, which is a quote literal.  That is,
                            // we have the first quote in 'do' or o''clock.
                            if ((pos+1) < pattern.length() &&
                                pattern.charAt(pos+1) == QUOTE) {
                                ++pos;
                                affix.append(ch);
                            } else {
                                subpart += 2; // open quote
                            }
                            continue;
                        }
                        patternError("Unquoted special character '" + ch + '\'', pattern);
                    } else if (ch == CURRENCY_SIGN) {
                        // Use lookahead to determine if the currency sign is
                        // doubled or not.
                        boolean doubled = (pos + 1) < pattern.length() &&
                            pattern.charAt(pos + 1) == CURRENCY_SIGN;
                        /*Bug 4212072
                         To meet the need of expandAffix(String, StirngBuffer)
                         [Richard/GCL]
                        */
                        if (doubled) {
                            ++pos; // Skip over the doubled character
                            affix.append(ch); // append two: one here, one below
                            if ((pos + 1) < pattern.length() &&
                                pattern.charAt(pos + 1) == CURRENCY_SIGN) {
                                ++pos; // Skip over the tripled character
                                affix.append(ch); // append again
                                currencySignCount = CURRENCY_SIGN_COUNT_IN_PLURAL_FORMAT;
                            } else {
                                currencySignCount = CURRENCY_SIGN_COUNT_IN_ISO_FORMAT;
                            }
                        } else {
                            currencySignCount = CURRENCY_SIGN_COUNT_IN_SYMBOL_FORMAT;
                        }
                        // Fall through to append(ch)
                    } else if (ch == QUOTE) {
                        // A quote outside quotes indicates either the opening
                        // quote or two quotes, which is a quote literal.  That is,
                        // we have the first quote in 'do' or o''clock.
                        if((pos+1) < pattern.length()&&
                            pattern.charAt(pos+1)==QUOTE){
                            ++pos;
                            affix.append(ch); // append two: one here, one below
                        }else{
                            subpart += 2; // open quote
                        }
                        // Fall through to append(ch)
                    } else if (ch == separator) {
                        // Don't allow separators in the prefix, and don't allow
                        // separators in the second pattern (part == 1).
                        if (subpart == 1 || part == 1) {
                            patternError("Unquoted special character '" + ch + '\'', pattern);
                        }
                        sub2Limit = pos++;
                        break PARTLOOP; // Go to next part
                    } else if (ch == percent || ch == perMill) {
                        // Next handle characters which are appended directly.
                        if (multpl != 1) {
                            patternError("Too many percent/permille characters", pattern);
                        }
                        multpl = (ch == percent) ? 100 : 1000;
                        // Convert to non-localized pattern
                        ch = (ch == percent) ? PATTERN_PERCENT : PATTERN_PER_MILLE;
                        // Fall through to append(ch)
                    } else if (ch == minus) {
                        // Convert to non-localized pattern
                        ch = PATTERN_MINUS;
                        // Fall through to append(ch)
                    } else if (ch == padEscape) {
                        if (padPos >= 0) {
                            patternError("Multiple pad specifiers", pattern);
                        }
                        if ((pos+1) == pattern.length()) {
                            patternError("Invalid pad specifier", pattern);
                        }
                        padPos = pos++; // Advance past pad char
                        padChar = pattern.charAt(pos);
                        continue;
                    }
                    affix.append(ch);
                    break;
                case 3: // Prefix subpart, in quote
                case 4: // Suffix subpart, in quote
                    // A quote within quotes indicates either the closing
                    // quote or two quotes, which is a quote literal.  That is,
                    // we have the second quote in 'do' or 'don''t'.
                    if (ch == QUOTE) {
                        if ((pos+1) < pattern.length() &&
                            pattern.charAt(pos+1) == QUOTE) {
                            ++pos;
                            affix.append(ch);
                        } else {
                            subpart -= 2; // close quote
                        }
                        // Fall through to append(ch)
                    }
                    // NOTE: In ICU 2.2 there was code here to parse quoted
                    // percent and permille characters _within quotes_ and give
                    // them special meaning.  This is incorrect, since quoted
                    // characters are literals without special meaning.
                    affix.append(ch);
                    break;                   
                }
            }
           
            if (subpart == 3 || subpart == 4) {
                patternError("Unterminated quote", pattern);
            }

            if (sub0Limit == 0) {
                sub0Limit = pattern.length();
            }

            if (sub2Limit == 0) {
                sub2Limit = pattern.length();
            }

            /* Handle patterns with no '0' pattern character.  These patterns
             * are legal, but must be recodified to make sense.  "##.###" ->
             * "#0.###".  ".###" -> ".0##".
             *
             * We allow patterns of the form "####" to produce a zeroDigitCount
             * of zero (got that?); although this seems like it might make it
             * possible for format() to produce empty strings, format() checks
             * for this condition and outputs a zero digit in this situation.
             * Having a zeroDigitCount of zero yields a minimum integer digits
             * of zero, which allows proper round-trip patterns.  We don't want
             * "#" to become "#0" when toPattern() is called (even though that's
             * what it really is, semantically).
             */
            if (zeroDigitCount == 0 && sigDigitCount == 0 &&
                digitLeftCount > 0 && decimalPos >= 0) {
                // Handle "###.###" and "###." and ".###"
                int n = decimalPos;
                if (n == 0) ++n; // Handle ".###"
                digitRightCount = digitLeftCount - n;
                digitLeftCount = n - 1;
                zeroDigitCount = 1;
            }

            // Do syntax checking on the digits, decimal points, and quotes.
            if ((decimalPos < 0 && digitRightCount > 0 && sigDigitCount == 0) ||
                (decimalPos >= 0 &&
                 (sigDigitCount > 0 ||
                  decimalPos < digitLeftCount ||
                  decimalPos > (digitLeftCount + zeroDigitCount))) ||
                groupingCount == 0 || groupingCount2 == 0 ||
                (sigDigitCount > 0 && zeroDigitCount > 0) ||
                subpart > 2) { // subpart > 2 == unmatched quote
                patternError("Malformed pattern", pattern);
            }

            // Make sure pad is at legal position before or after affix.
            if (padPos >= 0) {
                if (padPos == start) {
                    padPos = PAD_BEFORE_PREFIX;
                } else if (padPos+2 == sub0Start) {
                    padPos = PAD_AFTER_PREFIX;
                } else if (padPos == sub0Limit) {
                    padPos = PAD_BEFORE_SUFFIX;
                } else if (padPos+2 == sub2Limit) {
                    padPos = PAD_AFTER_SUFFIX;
                } else {
                    patternError("Illegal pad position", pattern);
                }
            }

            if (part == 0) {
                // Set negative affixes temporarily to match the positive
                // affixes.  Fix this up later after processing both parts.
                /*Bug 4212072
                  To meet the need of expandAffix(String, StirngBuffer)
                  [Richard/GCL]
                */
                posPrefixPattern = negPrefixPattern = prefix.toString();
                posSuffixPattern = negSuffixPattern = suffix.toString();

                useExponentialNotation = (expDigits >= 0);
                if (useExponentialNotation) {
                    minExponentDigits = expDigits;
                    exponentSignAlwaysShown = expSignAlways;
                }
                int digitTotalCount = digitLeftCount + zeroDigitCount + digitRightCount;
                // The effectiveDecimalPos is the position the decimal is at or
                // would be at if there is no decimal.  Note that if
                // decimalPos<0, then digitTotalCount == digitLeftCount +
                // zeroDigitCount.
                int effectiveDecimalPos = decimalPos >= 0 ? decimalPos : digitTotalCount;
                boolean useSigDig = (sigDigitCount > 0);
                setSignificantDigitsUsed(useSigDig);
                if (useSigDig) {
                    setMinimumSignificantDigits(sigDigitCount);
                    setMaximumSignificantDigits(sigDigitCount + digitRightCount);
                } else {
                    int minInt = effectiveDecimalPos - digitLeftCount;
                    setMinimumIntegerDigits(minInt);
                    /*Upper limit on integer and fraction digits for a Java double
                      [Richard/GCL]
                    */
                    setMaximumIntegerDigits(useExponentialNotation
                        ? digitLeftCount + minInt : DOUBLE_INTEGER_DIGITS);
                    setMaximumFractionDigits(decimalPos >= 0
                        ? (digitTotalCount - decimalPos) : 0);
                    setMinimumFractionDigits(decimalPos >= 0
                        ? (digitLeftCount + zeroDigitCount - decimalPos) : 0);
                }
                setGroupingUsed(groupingCount > 0);
                this.groupingSize = (groupingCount > 0) ? groupingCount : 0;
                this.groupingSize2 = (groupingCount2 > 0 && groupingCount2 != groupingCount)
                    ? groupingCount2 : 0;
                this.multiplier = multpl;
                setDecimalSeparatorAlwaysShown(decimalPos == 0
                        || decimalPos == digitTotalCount);
                if (padPos >= 0) {
                    padPosition = padPos;
                    formatWidth = sub0Limit - sub0Start; // to be fixed up below
                    pad = padChar;
                } else {
                    formatWidth = 0;
                }
                if (incrementVal != 0) {
                    // BigDecimal scale cannot be negative (even though
                    // this makes perfect sense), so we need to handle this.
                    int scale = incrementPos - effectiveDecimalPos;
                    roundingIncrementICU =
                        BigDecimal.valueOf(incrementVal, scale > 0 ? scale : 0);
                    if (scale < 0) {
                        roundingIncrementICU =
                            roundingIncrementICU.movePointRight(-scale);
                    }
                    setRoundingDouble();
                    roundingMode = BigDecimal.ROUND_HALF_EVEN;
                } else {
                    setRoundingIncrement((BigDecimal)null);
                }
            } else {
                /*Bug 4212072
                  To meet the need of expandAffix(String, StirngBuffer)
                  [Richard/GCL]
                */
                negPrefixPattern = prefix.toString();
                negSuffixPattern = suffix.toString();
                gotNegative = true;
            }
        }

        /*Bug 4140009
          Process the empty pattern
          [Richard/GCL]
        */
        if (pattern.length() == 0) {
            posPrefixPattern = posSuffixPattern = "";
            setMinimumIntegerDigits(0);
            setMaximumIntegerDigits(DOUBLE_INTEGER_DIGITS);
            setMinimumFractionDigits(0);
            setMaximumFractionDigits(DOUBLE_FRACTION_DIGITS);
        }
       
        // If there was no negative pattern, or if the negative pattern is
        // identical to the positive pattern, then prepend the minus sign to the
        // positive pattern to form the negative pattern.
        /*Bug 4212072
          To meet the need of expandAffix(String, StirngBuffer)
          [Richard/GCL]
        */
        if (!gotNegative ||
            (negPrefixPattern.equals(posPrefixPattern)
             && negSuffixPattern.equals(posSuffixPattern))) {
            negSuffixPattern = posSuffixPattern;
            negPrefixPattern = PATTERN_MINUS + posPrefixPattern;
        }
        setLocale(null, null);
        // save the pattern
        formatPattern = pattern;
        // initialize currencyPluralInfo if needed
        if (currencySignCount == CURRENCY_SIGN_COUNT_IN_PLURAL_FORMAT &&
            currencyPluralInfo == null) {
            currencyPluralInfo = new CurrencyPluralInfo(symbols.getLocale());
        }
    }

    /**
     * Centralizes the setting of the roundingDouble and roundingDoubleReciprocal.
     */
    private void setRoundingDouble() {
        if (roundingIncrementICU == null) {
            roundingDouble = 0.0d;
            roundingDoubleReciprocal = 0.0d;
        } else {
            roundingDouble = roundingIncrementICU.doubleValue();
            setRoundingDoubleReciprocal(BigDecimal.ONE.divide(roundingIncrementICU,BigDecimal.ROUND_HALF_EVEN).doubleValue());
        }
    }

    private void patternError(String msg, String pattern) {
        throw new IllegalArgumentException(msg + " in pattern \"" + pattern + '"');
    }

    /*Rewrite the following 4 "set" methods
      Upper limit on integer and fraction digits for a Java double
      [Richard/GCL]
    */
    /**
     * Sets the maximum number of digits allowed in the integer portion of a
     * number. This override limits the integer digit count to 309.
     * @see NumberFormat#setMaximumIntegerDigits
     * @stable ICU 2.0
     */
    public void setMaximumIntegerDigits(int newValue) {
        super.setMaximumIntegerDigits(Math.min(newValue, DOUBLE_INTEGER_DIGITS));
    }

    /**
     * Sets the minimum number of digits allowed in the integer portion of a
     * number. This override limits the integer digit count to 309.
     * @see NumberFormat#setMinimumIntegerDigits
     * @stable ICU 2.0
     */
    public void setMinimumIntegerDigits(int newValue) {
        super.setMinimumIntegerDigits(Math.min(newValue, DOUBLE_INTEGER_DIGITS));
    }

    /**
     * Returns the minimum number of significant digits that will be
     * displayed. This value has no effect unless areSignificantDigitsUsed()
     * returns true.
     * @return the fewest significant digits that will be shown
     * @stable ICU 3.0
     */
    public int getMinimumSignificantDigits() {
        return minSignificantDigits;
    }

    /**
     * Returns the maximum number of significant digits that will be
     * displayed. This value has no effect unless areSignificantDigitsUsed()
     * returns true.
     * @return the most significant digits that will be shown
     * @stable ICU 3.0
     */
    public int getMaximumSignificantDigits() {
        return maxSignificantDigits;
    }

    /**
     * Sets the minimum number of significant digits that will be
     * displayed.  If <code>min</code> is less than one then it is set
     * to one.  If the maximum significant digits count is less than
     * <code>min</code>, then it is set to <code>min</code>. This
     * value has no effect unless areSignificantDigitsUsed() returns true.
     * @param min the fewest significant digits to be shown
     * @stable ICU 3.0
     */
    public void setMinimumSignificantDigits(int min) {
        if (min < 1) {
            min = 1;  
        }
        // pin max sig dig to >= min
        int max = Math.max(maxSignificantDigits, min);
        minSignificantDigits = min;
        maxSignificantDigits = max;
    }

    /**
     * Sets the maximum number of significant digits that will be
     * displayed.  If <code>max</code> is less than one then it is set
     * to one.  If the minimum significant digits count is greater
     * than <code>max</code>, then it is set to <code>max</code>. This
     * value has no effect unless areSignificantDigitsUsed() returns true.
     * @param max the most significant digits to be shown
     * @stable ICU 3.0
     */
    public void setMaximumSignificantDigits(int max) {
        if (max < 1) {
            max = 1;
        }
        // pin min sig dig to 1..max
        int min = Math.min(minSignificantDigits, max);
        minSignificantDigits = min;
        maxSignificantDigits = max;
    }

    /**
     * Returns true if significant digits are in use or false if
     * integer and fraction digit counts are in use.
     * @return true if significant digits are in use
     * @stable ICU 3.0
     */
    public boolean areSignificantDigitsUsed() {
        return useSignificantDigits;
    }

    /**
     * Sets whether significant digits are in use, or integer and
     * fraction digit counts are in use.
     * @param useSignificantDigits true to use significant digits, or
     * false to use integer and fraction digit counts
     * @stable ICU 3.0
     */
    public void setSignificantDigitsUsed(boolean useSignificantDigits) {
        this.useSignificantDigits = useSignificantDigits;
    }

    /**
     * Sets the <tt>Currency</tt> object used to display currency
     * amounts.  This takes effect immediately, if this format is a
     * currency format.  If this format is not a currency format, then
     * the currency object is used if and when this object becomes a
     * currency format through the application of a new pattern.
     * @param theCurrency new currency object to use.  Must not be
     * null.
     * @stable ICU 2.2
     */
    public void setCurrency(Currency theCurrency) {
        // If we are a currency format, then modify our affixes to
        // encode the currency symbol for the given currency in our
        // locale, and adjust the decimal digits and rounding for the
        // given currency.

        super.setCurrency(theCurrency);
        if (theCurrency != null) {
            boolean[] isChoiceFormat = new boolean[1];
            String s = theCurrency.getName(symbols.getULocale(),
                    Currency.SYMBOL_NAME,
                    isChoiceFormat);
                symbols.setCurrencySymbol(s);
                symbols.setInternationalCurrencySymbol(theCurrency.getCurrencyCode());
        }

        if (currencySignCount > 0) {
            if (theCurrency != null) {
                setRoundingIncrement(theCurrency.getRoundingIncrement());
                int d = theCurrency.getDefaultFractionDigits();
                setMinimumFractionDigits(d);
                setMaximumFractionDigits(d);
            }
            expandAffixes(null);
        }
    }

    /**
     * Returns the currency in effect for this formatter.  Subclasses
     * should override this method as needed.  Unlike getCurrency(),
     * this method should never return null.
     * @internal
     * @deprecated This API is ICU internal only.
     */
    protected Currency getEffectiveCurrency() {
        Currency c = getCurrency();
        if (c == null) {
            c = Currency.getInstance(symbols.getInternationalCurrencySymbol());
        }
        return c;
    }

    /**
     * Sets the maximum number of digits allowed in the fraction portion of a
     * number. This override limits the fraction digit count to 340.
     * @see NumberFormat#setMaximumFractionDigits
     * @stable ICU 2.0
     */
    public void setMaximumFractionDigits(int newValue) {
        super.setMaximumFractionDigits(Math.min(newValue, DOUBLE_FRACTION_DIGITS));
    }

    /**
     * Sets the minimum number of digits allowed in the fraction portion of a
     * number. This override limits the fraction digit count to 340.
     * @see NumberFormat#setMinimumFractionDigits
     * @stable ICU 2.0
     */
    public void setMinimumFractionDigits(int newValue) {
        super.setMinimumFractionDigits(Math.min(newValue, DOUBLE_FRACTION_DIGITS));
    }

    /**
     * Sets whether {@link #parse(String, ParsePosition)} method returns BigDecimal.
     * The default value is false.
     * @param value true if {@link #parse(String, ParsePosition)} method returns
     * BigDecimal.
     * @stable ICU 3.6
     */
    public void setParseBigDecimal(boolean value) {
        parseBigDecimal = value;
    }

    /**
     * Returns whether {@link #parse(String, ParsePosition)} method returns BigDecimal.
     * @return true if {@link #parse(String, ParsePosition)} method returns BigDecimal.
     * @stable ICU 3.6
     */
    public boolean isParseBigDecimal() {
        return parseBigDecimal;
    }

//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
    private void writeObject(ObjectOutputStream stream) throws IOException {
// Doug, do we need this anymore?
//            if (roundingIncrementICU != null) {
//                roundingIncrement = roundingIncrementICU.toBigDecimal();
//            }

        // Ticket#6449
        // Format.Field instances are not serializable.  When formatToCharacterIterator
        // is called, attributes (ArrayList) stores FieldPosition instances with
        // NumberFormat.Field.  Because NumberFormat.Field is not serializable, we need
        // to clear the contents of the list when writeObject is called.  We could remove
        // the field or make it transient, but it will break serialization compatibility.
        attributes.clear();

        stream.defaultWriteObject();
    }
//#endif

    /**
     * First, read the default serializable fields from the stream.  Then
     * if <code>serialVersionOnStream</code> is less than 1, indicating that
     * the stream was written by JDK 1.1, initialize <code>useExponentialNotation</code>
     * to false, since it was not present in JDK 1.1.
     * Finally, set serialVersionOnStream back to the maximum allowed value so that
     * default serialization will work properly if this object is streamed out again.
     */
    private void readObject(ObjectInputStream stream)
         throws IOException, ClassNotFoundException
    {
        stream.defaultReadObject();
        /*Bug 4185761 validate fields
          [Richard/GCL]
        */
        // We only need to check the maximum counts because NumberFormat
        // .readObject has already ensured that the maximum is greater than the
        // minimum count.
        /*Commented for compatibility with previous version, and reserved for further use
        if (getMaximumIntegerDigits() > DOUBLE_INTEGER_DIGITS ||
            getMaximumFractionDigits() > DOUBLE_FRACTION_DIGITS) {
            throw new InvalidObjectException("Digit count out of range");
        }*/
        /* Truncate the maximumIntegerDigits to DOUBLE_INTEGER_DIGITS and maximumFractionDigits
         * to DOUBLE_FRACTION_DIGITS
         */
        if (getMaximumIntegerDigits() > DOUBLE_INTEGER_DIGITS) {
             setMaximumIntegerDigits(DOUBLE_INTEGER_DIGITS);
        }
        if (getMaximumFractionDigits() > DOUBLE_FRACTION_DIGITS) {
            setMaximumFractionDigits(DOUBLE_FRACTION_DIGITS);
        }
        if (serialVersionOnStream < 2) {
            exponentSignAlwaysShown = false;
            setInternalRoundingIncrement(null);
            setRoundingDouble();
            roundingMode = BigDecimal.ROUND_HALF_EVEN;
            formatWidth = 0;
            pad = ' ';
            padPosition = PAD_BEFORE_PREFIX;
            if (serialVersionOnStream < 1) {
                // Didn't have exponential fields
                useExponentialNotation = false;
            }
        }
        if (serialVersionOnStream < 3) {
            // Versions prior to 3 do not store a currency object.
            // Create one to match the DecimalFormatSymbols object.
            setCurrencyForSymbols();
        }
        serialVersionOnStream = currentSerialVersion;
        digitList = new DigitList();

//#if defined(FOUNDATION10)
//#else
        if (roundingIncrement != null) {
            setInternalRoundingIncrement(new BigDecimal(roundingIncrement));
            setRoundingDouble();
        }  
//#endif
    }


    private void setInternalRoundingIncrement(BigDecimal value) {
        roundingIncrementICU = value;
//#if defined(FOUNDATION10)
//#else
        roundingIncrement = value == null ? null : value.toBigDecimal();
//#endif
    }

    //----------------------------------------------------------------------
    // INSTANCE VARIABLES
    //----------------------------------------------------------------------

    private transient DigitList digitList = new DigitList();

    /**
     * The symbol used as a prefix when formatting positive numbers, e.g. "+".
     *
     * @serial
     * @see #getPositivePrefix
     */
    private String  positivePrefix = "";

    /**
     * The symbol used as a suffix when formatting positive numbers.
     * This is often an empty string.
     *
     * @serial
     * @see #getPositiveSuffix
     */
    private String  positiveSuffix = "";

    /**
     * The symbol used as a prefix when formatting negative numbers, e.g. "-".
     *
     * @serial
     * @see #getNegativePrefix
     */
    private String  negativePrefix = "-";

    /**
     * The symbol used as a suffix when formatting negative numbers.
     * This is often an empty string.
     *
     * @serial
     * @see #getNegativeSuffix
     */
    private String  negativeSuffix = "";
   
    /**
     * The prefix pattern for non-negative numbers.  This variable corresponds
     * to <code>positivePrefix</code>.
     *
     * <p>This pattern is expanded by the method <code>expandAffix()</code> to
     * <code>positivePrefix</code> to update the latter to reflect changes in
     * <code>symbols</code>.  If this variable is <code>null</code> then
     * <code>positivePrefix</code> is taken as a literal value that does not
     * change when <code>symbols</code> changes.  This variable is always
     * <code>null</code> for <code>DecimalFormat</code> objects older than
     * stream version 2 restored from stream.
     *
     * @serial
     */
    //[Richard/GCL]
    private String posPrefixPattern;

    /**
     * The suffix pattern for non-negative numbers.  This variable corresponds
     * to <code>positiveSuffix</code>.  This variable is analogous to
     * <code>posPrefixPattern</code>; see that variable for further
     * documentation.
     *
     * @serial
     */
    //[Richard/GCL]
    private String posSuffixPattern;

    /**
     * The prefix pattern for negative numbers.  This variable corresponds
     * to <code>negativePrefix</code>.  This variable is analogous to
     * <code>posPrefixPattern</code>; see that variable for further
     * documentation.
     *
     * @serial
     */
    //[Richard/GCL]
    private String negPrefixPattern;

    /**
     * The suffix pattern for negative numbers.  This variable corresponds
     * to <code>negativeSuffix</code>.  This variable is analogous to
     * <code>posPrefixPattern</code>; see that variable for further
     * documentation.
     *
     * @serial
     */
    //[Richard/GCL]
    private String negSuffixPattern;



    /**
     * Formatter for ChoiceFormat-based currency names.  If this field
     * is not null, then delegate to it to format currency symbols.
     * @since ICU 2.6
     */
    private ChoiceFormat currencyChoice;

    /**
     * The multiplier for use in percent, permill, etc.
     *
     * @serial
     * @see #getMultiplier
     */
    private int     multiplier = 1;
   
    /**
     * The number of digits between grouping separators in the integer
     * portion of a number.  Must be greater than 0 if
     * <code>NumberFormat.groupingUsed</code> is true.
     *
     * @serial
     * @see #getGroupingSize
     * @see NumberFormat#isGroupingUsed
     */
    private byte    groupingSize = 3// invariant, > 0 if useThousands

    // [NEW]
    /**
     * The secondary grouping size.  This is only used for Hindi
     * numerals, which use a primary grouping of 3 and a secondary
     * grouping of 2, e.g., "12,34,567".  If this value is less than
     * 1, then secondary grouping is equal to the primary grouping.
     *
     */
    private byte    groupingSize2 = 0;
   
    /**
     * If true, forces the decimal separator to always appear in a formatted
     * number, even if the fractional part of the number is zero.
     *
     * @serial
     * @see #isDecimalSeparatorAlwaysShown
     */
    private boolean decimalSeparatorAlwaysShown = false;
   
   
    /**
     * The <code>DecimalFormatSymbols</code> object used by this format.
     * It contains the symbols used to format numbers, e.g. the grouping separator,
     * decimal separator, and so on.
     *
     * @serial
     * @see #setDecimalFormatSymbols
     * @see DecimalFormatSymbols
     */
    private DecimalFormatSymbols symbols = null; // LIU new DecimalFormatSymbols();

    /**
     * True to use significant digits rather than integer and fraction
     * digit counts.
     * @serial
     * @since ICU 3.0
     */
    private boolean useSignificantDigits = false;

    /**
     * The minimum number of significant digits to show.  Must be >= 1
     * and <= maxSignificantDigits.  Ignored unless
     * useSignificantDigits == true.
     * @serial
     * @since ICU 3.0
     */
    private int minSignificantDigits = 1;

    /**
     * The maximum number of significant digits to show.  Must be >=
     * minSignficantDigits.  Ignored unless useSignificantDigits ==
     * true.
     * @serial
     * @since ICU 3.0
     */
    private int maxSignificantDigits = 6;

    /**
     * True to force the use of exponential (i.e. scientific) notation when formatting
     * numbers.
     * <p>
     * Note that the JDK 1.2 public API provides no way to set this field,
     * even though it is supported by the implementation and the stream format.
     * The intent is that this will be added to the API in the future.
     *
     * @serial
     */
    private boolean useExponentialNotation;  // Newly persistent in JDK 1.2

    /**
     * The minimum number of digits used to display the exponent when a number is
     * formatted in exponential notation.  This field is ignored if
     * <code>useExponentialNotation</code> is not true.
     * <p>
     * Note that the JDK 1.2 public API provides no way to set this field,
     * even though it is supported by the implementation and the stream format.
     * The intent is that this will be added to the API in the future.
     *
     * @serial
     */
    private byte    minExponentDigits;       // Newly persistent in JDK 1.2

    // [NEW]
    /**
     * If true, the exponent is always prefixed with either the plus
     * sign or the minus sign.  Otherwise, only negative exponents are
     * prefixed with the minus sign.  This has no effect unless
     * <code>useExponentialNotation</code> is true.
     * @serial
     * @since AlphaWorks NumberFormat
     */
    private boolean exponentSignAlwaysShown = false;

//#if defined(FOUNDATION10)
//#else
    // [NEW]
    /**
     * The value to which numbers are rounded during formatting.  For example,
     * if the rounding increment is 0.05, then 13.371 would be formatted as
     * 13.350, assuming 3 fraction digits.  Has the value <code>null</code> if
     * rounding is not in effect, or a positive value if rounding is in effect.
     * Default value <code>null</code>.
     * @serial
     * @since AlphaWorks NumberFormat
     */
    // Note: this is kept in sync with roundingIncrementICU.
    // it is only kept around to avoid a conversion when formatting a java.math.BigDecimal
    private java.math.BigDecimal roundingIncrement = null;
//#endif

    // [NEW]
    /**
     * The value to which numbers are rounded during formatting.  For example,
     * if the rounding increment is 0.05, then 13.371 would be formatted as
     * 13.350, assuming 3 fraction digits.  Has the value <code>null</code> if
     * rounding is not in effect, or a positive value if rounding is in effect.
     * Default value <code>null</code>.
     * WARNING: the roundingIncrement value is the one serialized.
     * @serial
     * @since AlphaWorks NumberFormat
     */
    private transient BigDecimal roundingIncrementICU = null;

    // [NEW]
    /**
     * The rounding increment as a double.  If this value is <= 0, then no
     * rounding is done.  This value is
     * <code>roundingIncrementICU.doubleValue()</code>.  Default value 0.0.
     */
    private transient double roundingDouble = 0.0;

    // [NEW]
    /**
     * If the roundingDouble is the reciprocal of an integer (the most common case!),
     * this is set to be that integer. Otherwise it is 0.0.
     */
    private transient double roundingDoubleReciprocal = 0.0;

    // [NEW]
    /**
     * The rounding mode.  This value controls any rounding operations which
     * occur when applying a rounding increment or when reducing the number of
     * fraction digits to satisfy a maximum fraction digits limit.  The value
     * may assume any of the <code>BigDecimal</code> rounding mode values.
     * Default value <code>BigDecimal.ROUND_HALF_EVEN</code>.
     * @serial
     * @since AlphaWorks NumberFormat
     */
    private int roundingMode = BigDecimal.ROUND_HALF_EVEN;

    // [NEW]
    /**
     * Operations on <code>BigDecimal</code> numbers are controlled by a
     * {@link MathContext} object, which provides the context (precision and
     * other information) for the operation. The default <code>MathContext</code>
     * settings are <code>digits=0, form=PLAIN, lostDigits=false,
     * roundingMode=ROUND_HALF_UP</code>; these settings perform fixed point
     * arithmetic with unlimited precision, as defined for the original BigDecimal
     * class in Java 1.1 and Java 1.2
     */
    private MathContext mathContext = new MathContext(0, MathContext.PLAIN); // context for plain unlimited math

    // [NEW]
    /**
     * The padded format width, or zero if there is no padding.  Must
     * be >= 0.  Default value zero.
     * @serial
     * @since AlphaWorks NumberFormat
     */
    private int formatWidth = 0;

    // [NEW]
    /**
     * The character used to pad the result of format to
     * <code>formatWidth</code>, if padding is in effect.  Default value ' '.
     * @serial
     * @since AlphaWorks NumberFormat
     */
    private char pad = ' ';

    // [NEW]
    /**
     * The position in the string at which the <code>pad</code> character
     * will be inserted, if padding is in effect.  Must have a value from
     * <code>PAD_BEFORE_PREFIX</code> to <code>PAD_AFTER_SUFFIX</code>.
     * Default value <code>PAD_BEFORE_PREFIX</code>.
     * @serial
     * @since AlphaWorks NumberFormat
     */
    private int padPosition = PAD_BEFORE_PREFIX;

    /**
     * True if {@link #parse(String, ParsePosition)} to return BigDecimal
     * rather than Long, Double or BigDecimal except special values.
     * This property is introduced for J2SE 5 compatibility support.
     * @serial
     * @since ICU 3.6
     * @see #setParseBigDecimal(boolean)
     * @see #isParseBigDecimal()
     */
    private boolean parseBigDecimal = false;

    //----------------------------------------------------------------------

    static final int currentSerialVersion = 3;

    /**
     * The internal serial version which says which version was written
     * Possible values are:
     * <ul>
     * <li><b>0</b> (default): versions before JDK 1.2
     * <li><b>1</b>: version from JDK 1.2 and later, which includes the two new fields
     *      <code>useExponentialNotation</code> and <code>minExponentDigits</code>.
     * <li><b>2</b>: version on AlphaWorks, which adds roundingMode, formatWidth,
     *      pad, padPosition, exponentSignAlwaysShown, roundingIncrement.
     * <li><b>3</b>: ICU 2.2.  Adds currency object.
     * </ul>
     * @serial */
    private int serialVersionOnStream = currentSerialVersion;

    //----------------------------------------------------------------------
    // CONSTANTS
    //----------------------------------------------------------------------

    // [NEW]
    /**
     * Constant for <code>getPadPosition()</code> and
     * <code>setPadPosition()</code> specifying pad characters inserted before
     * the prefix.
     * @see #setPadPosition
     * @see #getPadPosition
     * @see #PAD_AFTER_PREFIX
     * @see #PAD_BEFORE_SUFFIX
     * @see #PAD_AFTER_SUFFIX
     * @stable ICU 2.0
     */
    public static final int PAD_BEFORE_PREFIX = 0;

    // [NEW]
    /**
     * Constant for <code>getPadPosition()</code> and
     * <code>setPadPosition()</code> specifying pad characters inserted after
     * the prefix.
     * @see #setPadPosition
     * @see #getPadPosition
     * @see #PAD_BEFORE_PREFIX
     * @see #PAD_BEFORE_SUFFIX
     * @see #PAD_AFTER_SUFFIX
     * @stable ICU 2.0
     */
    public static final int PAD_AFTER_PREFIX  = 1;

    // [NEW]
    /**
     * Constant for <code>getPadPosition()</code> and
     * <code>setPadPosition()</code> specifying pad characters inserted before
     * the suffix.
     * @see #setPadPosition
     * @see #getPadPosition
     * @see #PAD_BEFORE_PREFIX
     * @see #PAD_AFTER_PREFIX
     * @see #PAD_AFTER_SUFFIX
     * @stable ICU 2.0
     */
    public static final int PAD_BEFORE_SUFFIX = 2;

    // [NEW]
    /**
     * Constant for <code>getPadPosition()</code> and
     * <code>setPadPosition()</code> specifying pad characters inserted after
     * the suffix.
     * @see #setPadPosition
     * @see #getPadPosition
     * @see #PAD_BEFORE_PREFIX
     * @see #PAD_AFTER_PREFIX
     * @see #PAD_BEFORE_SUFFIX
     * @stable ICU 2.0
     */
    public static final int PAD_AFTER_SUFFIX  = 3;

    // Constants for characters used in programmatic (unlocalized) patterns.
    private static final char       PATTERN_ZERO_DIGIT         = '0';
    private static final char       PATTERN_GROUPING_SEPARATOR = ',';
    private static final char       PATTERN_DECIMAL_SEPARATOR  = '.';
    private static final char       PATTERN_DIGIT              = '#';
            static final char       PATTERN_SIGNIFICANT_DIGIT  = '@';
            static final char       PATTERN_EXPONENT           = 'E'; // [NEW]
            static final char       PATTERN_PLUS_SIGN          = '+'; // [NEW]

    // Affix
    private static final char       PATTERN_PER_MILLE          = '\u2030';
    private static final char       PATTERN_PERCENT            = '%';
            static final char       PATTERN_PAD_ESCAPE         = '*'; // [NEW]
    /*Bug 4212072
      To meet the need of expandAffix(String, StirngBuffer)
      [Richard/GCL]
    */
    private static final char       PATTERN_MINUS              = '-'; //[Richard/GCL]

    // Other   
    private static final char       PATTERN_SEPARATOR          = ';';

    // Pad escape is package private to allow access by DecimalFormatSymbols.
    // Also plus sign.  Also exponent.

    /**
     * The CURRENCY_SIGN is the standard Unicode symbol for currency.  It
     * is used in patterns and substitued with either the currency symbol,
     * or if it is doubled, with the international currency symbol.  If the
     * CURRENCY_SIGN is seen in a pattern, then the decimal separator is
     * replaced with the monetary decimal separator.
     *
     * The CURRENCY_SIGN is not localized.
     */
    private static final char       CURRENCY_SIGN = '\u00A4';

    private static final char       QUOTE = '\'';
   
    /* Upper limit on integer and fraction digits for a Java double
       [Richard/GCL]
    */
    static final int DOUBLE_INTEGER_DIGITS  = 309;
    static final int DOUBLE_FRACTION_DIGITS = 340;

    /**
     * When someone turns on scientific mode, we assume that more than this
     * number of digits is due to flipping from some other mode that didn't
     * restrict the maximum, and so we force 1 integer digit.  We don't bother
     * to track and see if someone is using exponential notation with more than
     * this number, it wouldn't make sense anyway, and this is just to make sure
     * that someone turning on scientific mode with default settings doesn't
     * end up with lots of zeroes.
     */
    static final int MAX_SCIENTIFIC_INTEGER_DIGITS = 8;

//#if defined(FOUNDATION10)
//##    // we're not compatible with other versions, since we have no java.math.BigDecimal field
//##    private static final long serialVersionUID = 2;
//#else
    // Proclaim JDK 1.1 serial compatibility.
    private static final long serialVersionUID = 864413376551465018L;
//#endif

//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
    private ArrayList attributes = new ArrayList();
//#endif

    /*
     * Following are used in currency format
     */
/*
    // triple currency sign char array
    private static final char[] tripleCurrencySign = {0xA4, 0xA4, 0xA4};
    // triple currency sign string
    private static final String tripleCurrencyStr = new String(tripleCurrencySign);

    // default currency plural pattern char array
    private static final char[] defaultCurrencyPluralPatternChar = {0, '.', '#', '#', ' ', 0xA4, 0xA4, 0xA4};
    // default currency plural pattern string
    private static final String defaultCurrencyPluralPattern = new String(defaultCurrencyPluralPatternChar);
*/

    // pattern used in this formatter
    private String formatPattern = "";
    // style is only valid when decimal formatter is constructed by
    // DecimalFormat(pattern, decimalFormatSymbol, style)
    private int style = NumberFormat.NUMBERSTYLE;
    /*
     * Represents whether this is a currency format, and which
     * currency format style.
     * 0: not currency format type;
     * 1: currency style -- symbol name, such as "$" for US dollar.
     * 2: currency style -- ISO name, such as USD for US dollar.
     * 3: currency style -- plural long name, such as "US Dollar" for
     *                      "1.00 US Dollar", or "US Dollars" for
     *                      "3.00 US Dollars".
     */
    private int currencySignCount = 0;


    /* For parsing purose,
     * Need to remember all prefix patterns and suffix patterns of
     * every currency format pattern,
     * including the pattern of default currecny style, ISO currency style,
     * and plural currency style. And the patterns are set through applyPattern.
     * Following are used to represent the affix patterns in currency plural
     * formats.
     */
    private static final class AffixForCurrency {
        // negative prefix pattern
        private String negPrefixPatternForCurrency = null;
        // negative suffix pattern
        private String negSuffixPatternForCurrency = null;
        // positive prefix pattern
        private String posPrefixPatternForCurrency = null;
        // positive suffix pattern
        private String posSuffixPatternForCurrency = null;
        private int patternType;
       
        public AffixForCurrency() {
            patternType = Currency.SYMBOL_NAME;
        }

        public AffixForCurrency(String negPrefix, String negSuffix,
                                String posPrefix, String posSuffix,
                                int type) {
            negPrefixPatternForCurrency = negPrefix;
            negSuffixPatternForCurrency = negSuffix;
            posPrefixPatternForCurrency = posPrefix;
            posSuffixPatternForCurrency = posSuffix;
            patternType = type;
        }

        public String getNegPrefix() {
            return negPrefixPatternForCurrency;
        }

        public String getNegSuffix() {
            return negSuffixPatternForCurrency;
        }

        public String getPosPrefix() {
            return posPrefixPatternForCurrency;
        }

        public String getPosSuffix() {
            return posSuffixPatternForCurrency;
        }

        public int getPatternType() {
            return patternType;
        }
    }
    // Affix patter set for currency.
    // It is a set of AffixForCurrency,
    // each element of the set saves the negative prefix,
    // negative suffix, positive prefix, and positive suffix of a pattern.
    private transient Set affixPatternsForCurrency = null;

    // For currency parsing, since currency parsing need to parse
    // against all currency patterns, before the parsing, need to set up
    // the affix patterns for currency.
    private transient boolean isReadyForParsing = false;

    // Information needed for DecimalFormat to format/parse currency plural.
    private CurrencyPluralInfo currencyPluralInfo = null;

}

//eof
TOP

Related Classes of com.ibm.icu.text.DecimalFormat$AffixForCurrency

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.