105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert/* GENERATED SOURCE. DO NOT MODIFY. */
205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert// © 2017 and later: Unicode, Inc. and others.
305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html#License
405fa7802d0874812c234a29745586677ee5837eaFredrik Roubertpackage android.icu.impl.number;
505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
605fa7802d0874812c234a29745586677ee5837eaFredrik Roubertimport android.icu.impl.StandardPlural;
705fa7802d0874812c234a29745586677ee5837eaFredrik Roubertimport android.icu.impl.number.AffixUtils.SymbolProvider;
805fa7802d0874812c234a29745586677ee5837eaFredrik Roubertimport android.icu.number.NumberFormatter.SignDisplay;
905fa7802d0874812c234a29745586677ee5837eaFredrik Roubertimport android.icu.number.NumberFormatter.UnitWidth;
1005fa7802d0874812c234a29745586677ee5837eaFredrik Roubertimport android.icu.text.DecimalFormatSymbols;
1105fa7802d0874812c234a29745586677ee5837eaFredrik Roubertimport android.icu.text.PluralRules;
1205fa7802d0874812c234a29745586677ee5837eaFredrik Roubertimport android.icu.util.Currency;
1305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
1405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert/**
1505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert * This class is a {@link Modifier} that wraps a decimal format pattern. It applies the pattern's affixes in
1605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert * {@link Modifier#apply}.
1705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert *
1805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert * <p>
1905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert * In addition to being a Modifier, this class contains the business logic for substituting the correct locale symbols
2005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert * into the affixes of the decimal format pattern.
2105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert *
2205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert * <p>
2305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert * In order to use this class, create a new instance and call the following four setters: {@link #setPatternInfo},
2405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert * {@link #setPatternAttributes}, {@link #setSymbols}, and {@link #setNumberProperties}. After calling these four
2505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert * setters, the instance will be ready for use as a Modifier.
2605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert *
2705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert * <p>
2805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert * This is a MUTABLE, NON-THREAD-SAFE class designed for performance. Do NOT save references to this or attempt to use
2905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert * it from multiple threads! Instead, you can obtain a safe, immutable decimal format pattern modifier by calling
3005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert * {@link MutablePatternModifier#createImmutable}, in effect treating this instance as a builder for the immutable
3105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert * variant.
3205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert * @hide Only a subset of ICU is exposed in Android
3305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert */
3405fa7802d0874812c234a29745586677ee5837eaFredrik Roubertpublic class MutablePatternModifier implements Modifier, SymbolProvider, CharSequence, MicroPropsGenerator {
3505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
3605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    // Modifier details
3705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    final boolean isStrong;
3805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
3905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    // Pattern details
4005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    AffixPatternProvider patternInfo;
4105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    SignDisplay signDisplay;
4205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    boolean perMilleReplacesPercent;
4305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
4405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    // Symbol details
4505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    DecimalFormatSymbols symbols;
4605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    UnitWidth unitWidth;
4705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    Currency currency;
4805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    PluralRules rules;
4905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
5005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    // Number details
5105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    boolean isNegative;
5205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    StandardPlural plural;
5305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
5405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    // QuantityChain details
5505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    MicroPropsGenerator parent;
5605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
5705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    // Transient CharSequence fields
5805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    boolean inCharSequenceMode;
5905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    int flags;
6005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    int length;
6105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    boolean prependSign;
6205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    boolean plusReplacesMinusSign;
6305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
6405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    /**
6505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * @param isStrong
6605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     *            Whether the modifier should be considered strong. For more information, see
6705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     *            {@link Modifier#isStrong()}. Most of the time, decimal format pattern modifiers should be considered
6805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     *            as non-strong.
6905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     */
7005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    public MutablePatternModifier(boolean isStrong) {
7105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        this.isStrong = isStrong;
7205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    }
7305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
7405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    /**
7505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * Sets a reference to the parsed decimal format pattern, usually obtained from
7605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * {@link PatternStringParser#parseToPatternInfo(String)}, but any implementation of {@link AffixPatternProvider} is
7705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * accepted.
7805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     */
7905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    public void setPatternInfo(AffixPatternProvider patternInfo) {
8005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        this.patternInfo = patternInfo;
8105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    }
8205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
8305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    /**
8405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * Sets attributes that imply changes to the literal interpretation of the pattern string affixes.
8505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     *
8605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * @param signDisplay
8705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     *            Whether to force a plus sign on positive numbers.
8805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * @param perMille
8905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     *            Whether to substitute the percent sign in the pattern with a permille sign.
9005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     */
9105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    public void setPatternAttributes(SignDisplay signDisplay, boolean perMille) {
9205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        this.signDisplay = signDisplay;
9305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        this.perMilleReplacesPercent = perMille;
9405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    }
9505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
9605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    /**
9705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * Sets locale-specific details that affect the symbols substituted into the pattern string affixes.
9805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     *
9905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * @param symbols
10005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     *            The desired instance of DecimalFormatSymbols.
10105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * @param currency
10205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     *            The currency to be used when substituting currency values into the affixes.
10305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * @param unitWidth
10405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     *            The width used to render currencies.
10505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * @param rules
10605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     *            Required if the triple currency sign, "¤¤¤", appears in the pattern, which can be determined from the
10705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     *            convenience method {@link #needsPlurals()}.
10805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     */
10905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    public void setSymbols(DecimalFormatSymbols symbols, Currency currency, UnitWidth unitWidth, PluralRules rules) {
11005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        assert (rules != null) == needsPlurals();
11105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        this.symbols = symbols;
11205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        this.currency = currency;
11305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        this.unitWidth = unitWidth;
11405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        this.rules = rules;
11505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    }
11605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
11705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    /**
11805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * Sets attributes of the current number being processed.
11905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     *
12005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * @param isNegative
12105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     *            Whether the number is negative.
12205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * @param plural
12305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     *            The plural form of the number, required only if the pattern contains the triple currency sign, "¤¤¤"
12405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     *            (and as indicated by {@link #needsPlurals()}).
12505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     */
12605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    public void setNumberProperties(boolean isNegative, StandardPlural plural) {
12705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        assert (plural != null) == needsPlurals();
12805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        this.isNegative = isNegative;
12905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        this.plural = plural;
13005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    }
13105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
13205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    /**
13305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * Returns true if the pattern represented by this MurkyModifier requires a plural keyword in order to localize.
13405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * This is currently true only if there is a currency long name placeholder in the pattern ("¤¤¤").
13505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     */
13605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    public boolean needsPlurals() {
13705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        return patternInfo.containsSymbolType(AffixUtils.TYPE_CURRENCY_TRIPLE);
13805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    }
13905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
14005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    /**
14105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * Creates a new quantity-dependent Modifier that behaves the same as the current instance, but which is immutable
14205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * and can be saved for future use. The number properties in the current instance are mutated; all other properties
14305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * are left untouched.
14405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     *
14505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * <p>
14605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * The resulting modifier cannot be used in a QuantityChain.
14705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     *
14805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * @return An immutable that supports both positive and negative numbers.
14905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     */
15005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    public ImmutablePatternModifier createImmutable() {
15105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        return createImmutableAndChain(null);
15205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    }
15305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
15405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    /**
15505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * Creates a new quantity-dependent Modifier that behaves the same as the current instance, but which is immutable
15605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * and can be saved for future use. The number properties in the current instance are mutated; all other properties
15705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * are left untouched.
15805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     *
15905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * @param parent
16005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     *            The QuantityChain to which to chain this immutable.
16105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * @return An immutable that supports both positive and negative numbers.
16205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     */
16305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    public ImmutablePatternModifier createImmutableAndChain(MicroPropsGenerator parent) {
16405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        NumberStringBuilder a = new NumberStringBuilder();
16505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        NumberStringBuilder b = new NumberStringBuilder();
16605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        if (needsPlurals()) {
16705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            // Slower path when we require the plural keyword.
16805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            ParameterizedModifier pm = new ParameterizedModifier();
16905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            for (StandardPlural plural : StandardPlural.VALUES) {
17005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert                setNumberProperties(false, plural);
17105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert                pm.setModifier(false, plural, createConstantModifier(a, b));
17205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert                setNumberProperties(true, plural);
17305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert                pm.setModifier(true, plural, createConstantModifier(a, b));
17405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            }
17505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            pm.freeze();
17605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            return new ImmutablePatternModifier(pm, rules, parent);
17705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        } else {
17805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            // Faster path when plural keyword is not needed.
17905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            setNumberProperties(false, null);
18005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            Modifier positive = createConstantModifier(a, b);
18105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            setNumberProperties(true, null);
18205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            Modifier negative = createConstantModifier(a, b);
18305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            ParameterizedModifier pm = new ParameterizedModifier(positive, negative);
18405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            return new ImmutablePatternModifier(pm, null, parent);
18505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        }
18605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    }
18705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
18805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    /**
18905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * Uses the current properties to create a single {@link ConstantMultiFieldModifier} with currency spacing support
19005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * if required.
19105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     *
19205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * @param a
19305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     *            A working NumberStringBuilder object; passed from the outside to prevent the need to create many new
19405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     *            instances if this method is called in a loop.
19505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * @param b
19605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     *            Another working NumberStringBuilder object.
19705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * @return The constant modifier object.
19805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     */
19905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    private ConstantMultiFieldModifier createConstantModifier(NumberStringBuilder a, NumberStringBuilder b) {
20005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        insertPrefix(a.clear(), 0);
20105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        insertSuffix(b.clear(), 0);
20205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        if (patternInfo.hasCurrencySign()) {
20305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            return new CurrencySpacingEnabledModifier(a, b, isStrong, symbols);
20405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        } else {
20505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            return new ConstantMultiFieldModifier(a, b, isStrong);
20605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        }
20705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    }
20805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
20905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    public static class ImmutablePatternModifier implements MicroPropsGenerator {
21005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        final ParameterizedModifier pm;
21105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        final PluralRules rules;
21205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        final MicroPropsGenerator parent;
21305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
21405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        ImmutablePatternModifier(ParameterizedModifier pm, PluralRules rules, MicroPropsGenerator parent) {
21505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            this.pm = pm;
21605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            this.rules = rules;
21705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            this.parent = parent;
21805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        }
21905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
22005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        @Override
22105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        public MicroProps processQuantity(DecimalQuantity quantity) {
22205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            MicroProps micros = parent.processQuantity(quantity);
22305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            applyToMicros(micros, quantity);
22405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            return micros;
22505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        }
22605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
22705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        public void applyToMicros(MicroProps micros, DecimalQuantity quantity) {
22805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            if (rules == null) {
22905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert                micros.modMiddle = pm.getModifier(quantity.isNegative());
23005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            } else {
23105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert                // TODO: Fix this. Avoid the copy.
23205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert                DecimalQuantity copy = quantity.createCopy();
23305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert                copy.roundToInfinity();
23405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert                StandardPlural plural = copy.getStandardPlural(rules);
23505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert                micros.modMiddle = pm.getModifier(quantity.isNegative(), plural);
23605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            }
23705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        }
23805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    }
23905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
24005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    /** Used by the unsafe code path. */
24105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    public MicroPropsGenerator addToChain(MicroPropsGenerator parent) {
24205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        this.parent = parent;
24305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        return this;
24405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    }
24505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
24605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    @Override
24705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    public MicroProps processQuantity(DecimalQuantity fq) {
24805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        MicroProps micros = parent.processQuantity(fq);
24905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        if (needsPlurals()) {
25005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            // TODO: Fix this. Avoid the copy.
25105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            DecimalQuantity copy = fq.createCopy();
25205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            micros.rounding.apply(copy);
25305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            setNumberProperties(fq.isNegative(), copy.getStandardPlural(rules));
25405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        } else {
25505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            setNumberProperties(fq.isNegative(), null);
25605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        }
25705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        micros.modMiddle = this;
25805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        return micros;
25905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    }
26005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
26105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    @Override
26205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    public int apply(NumberStringBuilder output, int leftIndex, int rightIndex) {
26305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        int prefixLen = insertPrefix(output, leftIndex);
26405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        int suffixLen = insertSuffix(output, rightIndex + prefixLen);
26505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        CurrencySpacingEnabledModifier.applyCurrencySpacing(output, leftIndex, prefixLen, rightIndex + prefixLen,
26605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert                suffixLen, symbols);
26705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        return prefixLen + suffixLen;
26805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    }
26905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
27005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    @Override
27105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    public int getPrefixLength() {
27205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        // Enter and exit CharSequence Mode to get the length.
27305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        enterCharSequenceMode(true);
27405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        int result = AffixUtils.unescapedCodePointCount(this, this);  // prefix length
27505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        exitCharSequenceMode();
27605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        return result;
27705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    }
27805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
27905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    @Override
28005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    public int getCodePointCount() {
28105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        // Enter and exit CharSequence Mode to get the length.
28205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        enterCharSequenceMode(true);
28305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        int result = AffixUtils.unescapedCodePointCount(this, this);  // prefix length
28405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        exitCharSequenceMode();
28505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        enterCharSequenceMode(false);
28605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        result += AffixUtils.unescapedCodePointCount(this, this);  // suffix length
28705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        exitCharSequenceMode();
28805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        return result;
28905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    }
29005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
29105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    @Override
29205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    public boolean isStrong() {
29305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        return isStrong;
29405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    }
29505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
29605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    private int insertPrefix(NumberStringBuilder sb, int position) {
29705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        enterCharSequenceMode(true);
29805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        int length = AffixUtils.unescape(this, sb, position, this);
29905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        exitCharSequenceMode();
30005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        return length;
30105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    }
30205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
30305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    private int insertSuffix(NumberStringBuilder sb, int position) {
30405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        enterCharSequenceMode(false);
30505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        int length = AffixUtils.unescape(this, sb, position, this);
30605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        exitCharSequenceMode();
30705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        return length;
30805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    }
30905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
31005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    /**
31105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     * Returns the string that substitutes a given symbol type in a pattern.
31205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert     */
31305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    @Override
31405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    public CharSequence getSymbol(int type) {
31505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        switch (type) {
31605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        case AffixUtils.TYPE_MINUS_SIGN:
31705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            return symbols.getMinusSignString();
31805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        case AffixUtils.TYPE_PLUS_SIGN:
31905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            return symbols.getPlusSignString();
32005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        case AffixUtils.TYPE_PERCENT:
32105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            return symbols.getPercentString();
32205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        case AffixUtils.TYPE_PERMILLE:
32305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            return symbols.getPerMillString();
32405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        case AffixUtils.TYPE_CURRENCY_SINGLE:
32505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            // UnitWidth ISO, HIDDEN, or NARROW overrides the singular currency symbol.
32605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            if (unitWidth == UnitWidth.ISO_CODE) {
32705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert                return currency.getCurrencyCode();
32805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            } else if (unitWidth == UnitWidth.HIDDEN) {
32905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert                return "";
33005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            } else if (unitWidth == UnitWidth.NARROW) {
33105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert                return currency.getName(symbols.getULocale(), Currency.NARROW_SYMBOL_NAME, null);
33205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            } else {
33305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert                return currency.getName(symbols.getULocale(), Currency.SYMBOL_NAME, null);
33405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            }
33505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        case AffixUtils.TYPE_CURRENCY_DOUBLE:
33605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            return currency.getCurrencyCode();
33705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        case AffixUtils.TYPE_CURRENCY_TRIPLE:
33805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            // NOTE: This is the code path only for patterns containing "¤¤¤".
33905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            // Plural currencies set via the API are formatted in LongNameHandler.
34005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            // This code path is used by DecimalFormat via CurrencyPluralInfo.
34105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            assert plural != null;
34205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            return currency.getName(symbols.getULocale(), Currency.PLURAL_LONG_NAME, plural.getKeyword(), null);
34305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        case AffixUtils.TYPE_CURRENCY_QUAD:
34405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            return "\uFFFD";
34505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        case AffixUtils.TYPE_CURRENCY_QUINT:
34605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            return currency.getName(symbols.getULocale(), Currency.NARROW_SYMBOL_NAME, null);
34705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        default:
34805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            throw new AssertionError();
34905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        }
35005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    }
35105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
35205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    /** This method contains the heart of the logic for rendering LDML affix strings. */
35305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    private void enterCharSequenceMode(boolean isPrefix) {
35405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        assert !inCharSequenceMode;
35505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        inCharSequenceMode = true;
35605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
35705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        // Should the output render '+' where '-' would normally appear in the pattern?
35805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        plusReplacesMinusSign = !isNegative
35905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert                && (signDisplay == SignDisplay.ALWAYS || signDisplay == SignDisplay.ACCOUNTING_ALWAYS)
36005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert                && patternInfo.positiveHasPlusSign() == false;
36105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
36205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        // Should we use the affix from the negative subpattern? (If not, we will use the positive subpattern.)
36305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        boolean useNegativeAffixPattern = patternInfo.hasNegativeSubpattern()
36405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert                && (isNegative || (patternInfo.negativeHasMinusSign() && plusReplacesMinusSign));
36505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
36605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        // Resolve the flags for the affix pattern.
36705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        flags = 0;
36805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        if (useNegativeAffixPattern) {
36905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            flags |= AffixPatternProvider.Flags.NEGATIVE_SUBPATTERN;
37005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        }
37105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        if (isPrefix) {
37205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            flags |= AffixPatternProvider.Flags.PREFIX;
37305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        }
37405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        if (plural != null) {
37505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            assert plural.ordinal() == (AffixPatternProvider.Flags.PLURAL_MASK & plural.ordinal());
37605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            flags |= plural.ordinal();
37705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        }
37805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
37905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        // Should we prepend a sign to the pattern?
38005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        if (!isPrefix || useNegativeAffixPattern) {
38105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            prependSign = false;
38205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        } else if (isNegative) {
38305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            prependSign = signDisplay != SignDisplay.NEVER;
38405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        } else {
38505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            prependSign = plusReplacesMinusSign;
38605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        }
38705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
38805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        // Finally, compute the length of the affix pattern.
38905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        length = patternInfo.length(flags) + (prependSign ? 1 : 0);
39005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    }
39105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
39205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    private void exitCharSequenceMode() {
39305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        assert inCharSequenceMode;
39405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        inCharSequenceMode = false;
39505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    }
39605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
39705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    @Override
39805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    public int length() {
39905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        assert inCharSequenceMode;
40005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        return length;
40105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    }
40205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
40305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    @Override
40405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    public char charAt(int index) {
40505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        assert inCharSequenceMode;
40605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        char candidate;
40705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        if (prependSign && index == 0) {
40805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            candidate = '-';
40905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        } else if (prependSign) {
41005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            candidate = patternInfo.charAt(flags, index - 1);
41105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        } else {
41205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            candidate = patternInfo.charAt(flags, index);
41305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        }
41405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        if (plusReplacesMinusSign && candidate == '-') {
41505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            return '+';
41605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        }
41705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        if (perMilleReplacesPercent && candidate == '%') {
41805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert            return '‰';
41905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        }
42005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        return candidate;
42105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    }
42205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
42305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    @Override
42405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    public CharSequence subSequence(int start, int end) {
42505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        // Never called by AffixUtils
42605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        throw new AssertionError();
42705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    }
42805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert}
429