// Copyright (C) 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
 * Copyright (C) 2015, International Business Machines
 * Corporation and others.  All Rights Reserved.
 *
 * file name: decimfmtimpl.cpp
 */

#include "unicode/utypes.h"

#if !UCONFIG_NO_FORMATTING

#include <math.h>
#include "unicode/numfmt.h"
#include "unicode/plurrule.h"
#include "unicode/ustring.h"
#include "decimalformatpattern.h"
#include "decimalformatpatternimpl.h"
#include "decimfmtimpl.h"
#include "fphdlimp.h"
#include "plurrule_impl.h"
#include "valueformatter.h"
#include "visibledigits.h"

U_NAMESPACE_BEGIN

static const int32_t kMaxScientificIntegerDigits = 8;

static const int32_t kFormattingPosPrefix = (1 << 0);
static const int32_t kFormattingNegPrefix = (1 << 1);
static const int32_t kFormattingPosSuffix = (1 << 2);
static const int32_t kFormattingNegSuffix = (1 << 3);
static const int32_t kFormattingSymbols = (1 << 4);
static const int32_t kFormattingCurrency = (1 << 5);
static const int32_t kFormattingUsesCurrency = (1 << 6);
static const int32_t kFormattingPluralRules = (1 << 7);
static const int32_t kFormattingAffixParser = (1 << 8);
static const int32_t kFormattingCurrencyAffixInfo = (1 << 9);
static const int32_t kFormattingAll = (1 << 10) - 1;
static const int32_t kFormattingAffixes =
        kFormattingPosPrefix | kFormattingPosSuffix |
        kFormattingNegPrefix | kFormattingNegSuffix;
static const int32_t kFormattingAffixParserWithCurrency =
        kFormattingAffixParser | kFormattingCurrencyAffixInfo;

DecimalFormatImpl::DecimalFormatImpl(
        NumberFormat *super,
        const Locale &locale,
        const UnicodeString &pattern,
        UErrorCode &status)
        : fSuper(super),
          fScale(0),
          fRoundingMode(DecimalFormat::kRoundHalfEven),
          fSymbols(NULL),
          fCurrencyUsage(UCURR_USAGE_STANDARD),
          fRules(NULL),
          fMonetary(FALSE) {
    if (U_FAILURE(status)) {
        return;
    }
    fSymbols = new DecimalFormatSymbols(
            locale, status);
    if (fSymbols == NULL) {
        status = U_MEMORY_ALLOCATION_ERROR;
        return;
    }
    UParseError parseError;
    applyPattern(pattern, FALSE, parseError, status);
    updateAll(status);
}

DecimalFormatImpl::DecimalFormatImpl(
        NumberFormat *super,
        const UnicodeString &pattern,
        DecimalFormatSymbols *symbolsToAdopt,
        UParseError &parseError,
        UErrorCode &status)
        : fSuper(super),
          fScale(0),
          fRoundingMode(DecimalFormat::kRoundHalfEven),
          fSymbols(symbolsToAdopt),
          fCurrencyUsage(UCURR_USAGE_STANDARD),
          fRules(NULL),
          fMonetary(FALSE) {
    applyPattern(pattern, FALSE, parseError, status);
    updateAll(status);
}

DecimalFormatImpl::DecimalFormatImpl(
    NumberFormat *super, const DecimalFormatImpl &other, UErrorCode &status) :
          fSuper(super),
          fMultiplier(other.fMultiplier),
          fScale(other.fScale),
          fRoundingMode(other.fRoundingMode),
          fMinSigDigits(other.fMinSigDigits),
          fMaxSigDigits(other.fMaxSigDigits),
          fUseScientific(other.fUseScientific),
          fUseSigDigits(other.fUseSigDigits),
          fGrouping(other.fGrouping),
          fPositivePrefixPattern(other.fPositivePrefixPattern),
          fNegativePrefixPattern(other.fNegativePrefixPattern),
          fPositiveSuffixPattern(other.fPositiveSuffixPattern),
          fNegativeSuffixPattern(other.fNegativeSuffixPattern),
          fSymbols(other.fSymbols),
          fCurrencyUsage(other.fCurrencyUsage),
          fRules(NULL),
          fMonetary(other.fMonetary),
          fAffixParser(other.fAffixParser),
          fCurrencyAffixInfo(other.fCurrencyAffixInfo),
          fEffPrecision(other.fEffPrecision),
          fEffGrouping(other.fEffGrouping),
          fOptions(other.fOptions),
          fFormatter(other.fFormatter),
          fAffixes(other.fAffixes) {
    fSymbols = new DecimalFormatSymbols(*fSymbols);
    if (fSymbols == NULL && U_SUCCESS(status)) {
        status = U_MEMORY_ALLOCATION_ERROR;
    }
    if (other.fRules != NULL) {
        fRules = new PluralRules(*other.fRules);
        if (fRules == NULL && U_SUCCESS(status)) {
            status = U_MEMORY_ALLOCATION_ERROR;
        }
    }
}


DecimalFormatImpl &
DecimalFormatImpl::assign(const DecimalFormatImpl &other, UErrorCode &status) {
    if (U_FAILURE(status) || this == &other) {
        return (*this);
    }
    UObject::operator=(other);
    fMultiplier = other.fMultiplier;
    fScale = other.fScale;
    fRoundingMode = other.fRoundingMode;
    fMinSigDigits = other.fMinSigDigits;
    fMaxSigDigits = other.fMaxSigDigits;
    fUseScientific = other.fUseScientific;
    fUseSigDigits = other.fUseSigDigits;
    fGrouping = other.fGrouping;
    fPositivePrefixPattern = other.fPositivePrefixPattern;
    fNegativePrefixPattern = other.fNegativePrefixPattern;
    fPositiveSuffixPattern = other.fPositiveSuffixPattern;
    fNegativeSuffixPattern = other.fNegativeSuffixPattern;
    fCurrencyUsage = other.fCurrencyUsage;
    fMonetary = other.fMonetary;
    fAffixParser = other.fAffixParser;
    fCurrencyAffixInfo = other.fCurrencyAffixInfo;
    fEffPrecision = other.fEffPrecision;
    fEffGrouping = other.fEffGrouping;
    fOptions = other.fOptions;
    fFormatter = other.fFormatter;
    fAffixes = other.fAffixes;
    *fSymbols = *other.fSymbols;
    if (fRules != NULL && other.fRules != NULL) {
        *fRules = *other.fRules;
    } else {
        delete fRules;
        fRules = other.fRules;
        if (fRules != NULL) {
            fRules = new PluralRules(*fRules);
            if (fRules == NULL) {
                status = U_MEMORY_ALLOCATION_ERROR;
                return *this;
            }
        }
    }
    return *this;
}

UBool
DecimalFormatImpl::operator==(const DecimalFormatImpl &other) const {
    if (this == &other) {
        return TRUE;
    }
    return (fMultiplier == other.fMultiplier)
            && (fScale == other.fScale)
            && (fRoundingMode == other.fRoundingMode)
            && (fMinSigDigits == other.fMinSigDigits)
            && (fMaxSigDigits == other.fMaxSigDigits)
            && (fUseScientific == other.fUseScientific)
            && (fUseSigDigits == other.fUseSigDigits)
            && fGrouping.equals(other.fGrouping)
            && fPositivePrefixPattern.equals(other.fPositivePrefixPattern)
            && fNegativePrefixPattern.equals(other.fNegativePrefixPattern)
            && fPositiveSuffixPattern.equals(other.fPositiveSuffixPattern)
            && fNegativeSuffixPattern.equals(other.fNegativeSuffixPattern)
            && fCurrencyUsage == other.fCurrencyUsage
            && fAffixParser.equals(other.fAffixParser)
            && fCurrencyAffixInfo.equals(other.fCurrencyAffixInfo)
            && fEffPrecision.equals(other.fEffPrecision)
            && fEffGrouping.equals(other.fEffGrouping)
            && fOptions.equals(other.fOptions)
            && fFormatter.equals(other.fFormatter)
            && fAffixes.equals(other.fAffixes)
            && (*fSymbols == *other.fSymbols)
            && ((fRules == other.fRules) || (
                    (fRules != NULL) && (other.fRules != NULL)
                    && (*fRules == *other.fRules)))
            && (fMonetary == other.fMonetary);
}

DecimalFormatImpl::~DecimalFormatImpl() {
    delete fSymbols;
    delete fRules;
}

ValueFormatter &
DecimalFormatImpl::prepareValueFormatter(ValueFormatter &vf) const {
    if (fUseScientific) {
        vf.prepareScientificFormatting(
                fFormatter, fEffPrecision, fOptions);
        return vf;
    }
    vf.prepareFixedDecimalFormatting(
            fFormatter, fEffGrouping, fEffPrecision.fMantissa, fOptions.fMantissa);
    return vf;
}

int32_t
DecimalFormatImpl::getPatternScale() const {
    UBool usesPercent = fPositivePrefixPattern.usesPercent() || 
            fPositiveSuffixPattern.usesPercent() || 
            fNegativePrefixPattern.usesPercent() || 
            fNegativeSuffixPattern.usesPercent();
    if (usesPercent) {
        return 2;
    }
    UBool usesPermill = fPositivePrefixPattern.usesPermill() || 
            fPositiveSuffixPattern.usesPermill() || 
            fNegativePrefixPattern.usesPermill() || 
            fNegativeSuffixPattern.usesPermill();
    if (usesPermill) {
        return 3;
    }
    return 0;
}
    
void
DecimalFormatImpl::setMultiplierScale(int32_t scale) {
    if (scale == 0) {
        // Needed to preserve equality. fMultiplier == 0 means
        // multiplier is 1.
        fMultiplier.set((int32_t)0);
    } else {
        fMultiplier.set((int32_t)1);
        fMultiplier.shiftDecimalRight(scale);
    }
}

UnicodeString &
DecimalFormatImpl::format(
        int32_t number,
        UnicodeString &appendTo,
        FieldPosition &pos,
        UErrorCode &status) const {
    FieldPositionOnlyHandler handler(pos);
    return formatInt32(number, appendTo, handler, status);
}

UnicodeString &
DecimalFormatImpl::format(
        int32_t number,
        UnicodeString &appendTo,
        FieldPositionIterator *posIter,
        UErrorCode &status) const {
    FieldPositionIteratorHandler handler(posIter, status);
    return formatInt32(number, appendTo, handler, status);
}

template<class T>
UBool DecimalFormatImpl::maybeFormatWithDigitList(
        T number,
        UnicodeString &appendTo,
        FieldPositionHandler &handler,
        UErrorCode &status) const {
    if (!fMultiplier.isZero()) {
        DigitList digits;
        digits.set(number);
        digits.mult(fMultiplier, status);
        digits.shiftDecimalRight(fScale);
        formatAdjustedDigitList(digits, appendTo, handler, status);
        return TRUE;
    }
    if (fScale != 0) {
        DigitList digits;
        digits.set(number);
        digits.shiftDecimalRight(fScale);
        formatAdjustedDigitList(digits, appendTo, handler, status);
        return TRUE;
    }
    return FALSE;
}

template<class T>
UBool DecimalFormatImpl::maybeInitVisibleDigitsFromDigitList(
        T number,
        VisibleDigitsWithExponent &visibleDigits,
        UErrorCode &status) const {
    if (!fMultiplier.isZero()) {
        DigitList digits;
        digits.set(number);
        digits.mult(fMultiplier, status);
        digits.shiftDecimalRight(fScale);
        initVisibleDigitsFromAdjusted(digits, visibleDigits, status);
        return TRUE;
    }
    if (fScale != 0) {
        DigitList digits;
        digits.set(number);
        digits.shiftDecimalRight(fScale);
        initVisibleDigitsFromAdjusted(digits, visibleDigits, status);
        return TRUE;
    }
    return FALSE;
}

UnicodeString &
DecimalFormatImpl::formatInt32(
        int32_t number,
        UnicodeString &appendTo,
        FieldPositionHandler &handler,
        UErrorCode &status) const {
    if (maybeFormatWithDigitList(number, appendTo, handler, status)) {
        return appendTo;
    }
    ValueFormatter vf;
    return fAffixes.formatInt32(
            number,
            prepareValueFormatter(vf),
            handler,
            fRules,
            appendTo,
            status);
}

UnicodeString &
DecimalFormatImpl::formatInt64(
        int64_t number,
        UnicodeString &appendTo,
        FieldPositionHandler &handler,
        UErrorCode &status) const {
    if (number >= INT32_MIN && number <= INT32_MAX) {
        return formatInt32((int32_t) number, appendTo, handler, status);
    }
    VisibleDigitsWithExponent digits;
    initVisibleDigitsWithExponent(number, digits, status);
    return formatVisibleDigitsWithExponent(
            digits, appendTo, handler, status);
}

UnicodeString &
DecimalFormatImpl::formatDouble(
        double number,
        UnicodeString &appendTo,
        FieldPositionHandler &handler,
        UErrorCode &status) const {
    VisibleDigitsWithExponent digits;
    initVisibleDigitsWithExponent(number, digits, status);
    return formatVisibleDigitsWithExponent(
            digits, appendTo, handler, status);
}

UnicodeString &
DecimalFormatImpl::format(
        double number,
        UnicodeString &appendTo,
        FieldPosition &pos,
        UErrorCode &status) const {
    FieldPositionOnlyHandler handler(pos);
    return formatDouble(number, appendTo, handler, status);
}

UnicodeString &
DecimalFormatImpl::format(
        const DigitList &number,
        UnicodeString &appendTo,
        FieldPosition &pos,
        UErrorCode &status) const {
    DigitList dl(number);
    FieldPositionOnlyHandler handler(pos);
    return formatDigitList(dl, appendTo, handler, status);
}

UnicodeString &
DecimalFormatImpl::format(
        int64_t number,
        UnicodeString &appendTo,
        FieldPosition &pos,
        UErrorCode &status) const {
    FieldPositionOnlyHandler handler(pos);
    return formatInt64(number, appendTo, handler, status);
}

UnicodeString &
DecimalFormatImpl::format(
        int64_t number,
        UnicodeString &appendTo,
        FieldPositionIterator *posIter,
        UErrorCode &status) const {
    FieldPositionIteratorHandler handler(posIter, status);
    return formatInt64(number, appendTo, handler, status);
}

UnicodeString &
DecimalFormatImpl::format(
        double number,
        UnicodeString &appendTo,
        FieldPositionIterator *posIter,
        UErrorCode &status) const {
    FieldPositionIteratorHandler handler(posIter, status);
    return formatDouble(number, appendTo, handler, status);
}

UnicodeString &
DecimalFormatImpl::format(
        const DigitList &number,
        UnicodeString &appendTo,
        FieldPositionIterator *posIter,
        UErrorCode &status) const {
    DigitList dl(number);
    FieldPositionIteratorHandler handler(posIter, status);
    return formatDigitList(dl, appendTo, handler, status);
}

UnicodeString &
DecimalFormatImpl::format(
        StringPiece number,
        UnicodeString &appendTo,
        FieldPositionIterator *posIter,
        UErrorCode &status) const {
    DigitList dl;
    dl.set(number, status);
    FieldPositionIteratorHandler handler(posIter, status);
    return formatDigitList(dl, appendTo, handler, status);
}

UnicodeString &
DecimalFormatImpl::format(
        const VisibleDigitsWithExponent &digits,
        UnicodeString &appendTo,
        FieldPosition &pos,
        UErrorCode &status) const {
    FieldPositionOnlyHandler handler(pos);
    return formatVisibleDigitsWithExponent(
            digits, appendTo, handler, status);
}

UnicodeString &
DecimalFormatImpl::format(
        const VisibleDigitsWithExponent &digits,
        UnicodeString &appendTo,
        FieldPositionIterator *posIter,
        UErrorCode &status) const {
    FieldPositionIteratorHandler handler(posIter, status);
    return formatVisibleDigitsWithExponent(
            digits, appendTo, handler, status);
}

DigitList &
DecimalFormatImpl::adjustDigitList(
        DigitList &number, UErrorCode &status) const {
    number.setRoundingMode(fRoundingMode);
    if (!fMultiplier.isZero()) {
        number.mult(fMultiplier, status);
    }
    if (fScale != 0) {
        number.shiftDecimalRight(fScale);
    }
    number.reduce();
    return number;
}

UnicodeString &
DecimalFormatImpl::formatDigitList(
        DigitList &number,
        UnicodeString &appendTo,
        FieldPositionHandler &handler,
        UErrorCode &status) const {
    VisibleDigitsWithExponent digits;
    initVisibleDigitsWithExponent(number, digits, status);
    return formatVisibleDigitsWithExponent(
            digits, appendTo, handler, status);
}

UnicodeString &
DecimalFormatImpl::formatAdjustedDigitList(
        DigitList &number,
        UnicodeString &appendTo,
        FieldPositionHandler &handler,
        UErrorCode &status) const {
    ValueFormatter vf;
    return fAffixes.format(
            number,
            prepareValueFormatter(vf),
            handler,
            fRules,
            appendTo,
            status);
}

UnicodeString &
DecimalFormatImpl::formatVisibleDigitsWithExponent(
        const VisibleDigitsWithExponent &digits,
        UnicodeString &appendTo,
        FieldPositionHandler &handler,
        UErrorCode &status) const {
    ValueFormatter vf;
    return fAffixes.format(
            digits,
            prepareValueFormatter(vf),
            handler,
            fRules,
            appendTo,
            status);
}

static FixedDecimal &initFixedDecimal(
        const VisibleDigits &digits, FixedDecimal &result) {
    result.source = 0.0;
    result.isNegative = digits.isNegative();
    result.isNanOrInfinity = digits.isNaNOrInfinity();
    digits.getFixedDecimal(
            result.source, result.intValue, result.decimalDigits,
            result.decimalDigitsWithoutTrailingZeros,
            result.visibleDecimalDigitCount, result.hasIntegerValue);
    return result;
}

FixedDecimal &
DecimalFormatImpl::getFixedDecimal(double number, FixedDecimal &result, UErrorCode &status) const {
    if (U_FAILURE(status)) {
        return result;
    }
    VisibleDigits digits;
    fEffPrecision.fMantissa.initVisibleDigits(number, digits, status);
    return initFixedDecimal(digits, result);
}

FixedDecimal &
DecimalFormatImpl::getFixedDecimal(
        DigitList &number, FixedDecimal &result, UErrorCode &status) const {
    if (U_FAILURE(status)) {
        return result;
    }
    VisibleDigits digits;
    fEffPrecision.fMantissa.initVisibleDigits(number, digits, status);
    return initFixedDecimal(digits, result);
}

VisibleDigitsWithExponent &
DecimalFormatImpl::initVisibleDigitsWithExponent(
        int64_t number,
        VisibleDigitsWithExponent &digits,
        UErrorCode &status) const {
    if (maybeInitVisibleDigitsFromDigitList(
            number, digits, status)) {
        return digits;
    }
    if (fUseScientific) {
        fEffPrecision.initVisibleDigitsWithExponent(
                number, digits, status);
    } else {
        fEffPrecision.fMantissa.initVisibleDigitsWithExponent(
                number, digits, status);
    }
    return digits;
}

VisibleDigitsWithExponent &
DecimalFormatImpl::initVisibleDigitsWithExponent(
        double number,
        VisibleDigitsWithExponent &digits,
        UErrorCode &status) const {
    if (maybeInitVisibleDigitsFromDigitList(
            number, digits, status)) {
        return digits;
    }
    if (fUseScientific) {
        fEffPrecision.initVisibleDigitsWithExponent(
                number, digits, status);
    } else {
        fEffPrecision.fMantissa.initVisibleDigitsWithExponent(
                number, digits, status);
    }
    return digits;
}

VisibleDigitsWithExponent &
DecimalFormatImpl::initVisibleDigitsWithExponent(
        DigitList &number,
        VisibleDigitsWithExponent &digits,
        UErrorCode &status) const {
    adjustDigitList(number, status);
    return initVisibleDigitsFromAdjusted(number, digits, status);
}

VisibleDigitsWithExponent &
DecimalFormatImpl::initVisibleDigitsFromAdjusted(
        DigitList &number,
        VisibleDigitsWithExponent &digits,
        UErrorCode &status) const {
    if (fUseScientific) {
        fEffPrecision.initVisibleDigitsWithExponent(
                number, digits, status);
    } else {
        fEffPrecision.fMantissa.initVisibleDigitsWithExponent(
                number, digits, status);
    }
    return digits;
}

DigitList &
DecimalFormatImpl::round(
        DigitList &number, UErrorCode &status) const {
    if (number.isNaN() || number.isInfinite()) {
        return number;
    }
    adjustDigitList(number, status);
    ValueFormatter vf;
    prepareValueFormatter(vf);
    return vf.round(number, status);
}

void
DecimalFormatImpl::setMinimumSignificantDigits(int32_t newValue) {
    fMinSigDigits = newValue;
    fUseSigDigits = TRUE; // ticket 9936
    updatePrecision();
}
        
void
DecimalFormatImpl::setMaximumSignificantDigits(int32_t newValue) {
    fMaxSigDigits = newValue;
    fUseSigDigits = TRUE; // ticket 9936
    updatePrecision();
}

void
DecimalFormatImpl::setMinMaxSignificantDigits(int32_t min, int32_t max) {
    fMinSigDigits = min;
    fMaxSigDigits = max;
    fUseSigDigits = TRUE; // ticket 9936
    updatePrecision();
}

void
DecimalFormatImpl::setScientificNotation(UBool newValue) {
    fUseScientific = newValue;
    updatePrecision();
}
        
void
DecimalFormatImpl::setSignificantDigitsUsed(UBool newValue) {
    fUseSigDigits = newValue;
    updatePrecision();
}
        
void
DecimalFormatImpl::setGroupingSize(int32_t newValue) {
    fGrouping.fGrouping = newValue;
    updateGrouping();
}

void
DecimalFormatImpl::setSecondaryGroupingSize(int32_t newValue) {
    fGrouping.fGrouping2 = newValue;
    updateGrouping();
}

void
DecimalFormatImpl::setMinimumGroupingDigits(int32_t newValue) {
    fGrouping.fMinGrouping = newValue;
    updateGrouping();
}

void
DecimalFormatImpl::setCurrencyUsage(
        UCurrencyUsage currencyUsage, UErrorCode &status) {
    fCurrencyUsage = currencyUsage;
    updateFormatting(kFormattingCurrency, status);
}

void
DecimalFormatImpl::setRoundingIncrement(double d) {
    if (d > 0.0) {
        fEffPrecision.fMantissa.fRoundingIncrement.set(d);
    } else {
        fEffPrecision.fMantissa.fRoundingIncrement.set(0.0);
    }
}

double
DecimalFormatImpl::getRoundingIncrement() const {
    return fEffPrecision.fMantissa.fRoundingIncrement.getDouble();
}

int32_t
DecimalFormatImpl::getMultiplier() const {
    if (fMultiplier.isZero()) {
        return 1;
    }
    return (int32_t) fMultiplier.getDouble();
}

void
DecimalFormatImpl::setMultiplier(int32_t m) {
    if (m == 0 || m == 1) {
        fMultiplier.set((int32_t)0);
    } else {
        fMultiplier.set(m);
    }
}

void
DecimalFormatImpl::setPositivePrefix(const UnicodeString &str) {
    fPositivePrefixPattern.remove();
    fPositivePrefixPattern.addLiteral(str.getBuffer(), 0, str.length());
    UErrorCode status = U_ZERO_ERROR;
    updateFormatting(kFormattingPosPrefix, status);
}

void
DecimalFormatImpl::setPositiveSuffix(const UnicodeString &str) {
    fPositiveSuffixPattern.remove();
    fPositiveSuffixPattern.addLiteral(str.getBuffer(), 0, str.length());
    UErrorCode status = U_ZERO_ERROR;
    updateFormatting(kFormattingPosSuffix, status);
}

void
DecimalFormatImpl::setNegativePrefix(const UnicodeString &str) {
    fNegativePrefixPattern.remove();
    fNegativePrefixPattern.addLiteral(str.getBuffer(), 0, str.length());
    UErrorCode status = U_ZERO_ERROR;
    updateFormatting(kFormattingNegPrefix, status);
}

void
DecimalFormatImpl::setNegativeSuffix(const UnicodeString &str) {
    fNegativeSuffixPattern.remove();
    fNegativeSuffixPattern.addLiteral(str.getBuffer(), 0, str.length());
    UErrorCode status = U_ZERO_ERROR;
    updateFormatting(kFormattingNegSuffix, status);
}

UnicodeString &
DecimalFormatImpl::getPositivePrefix(UnicodeString &result) const {
    result = fAffixes.fPositivePrefix.getOtherVariant().toString();
    return result;
}

UnicodeString &
DecimalFormatImpl::getPositiveSuffix(UnicodeString &result) const {
    result = fAffixes.fPositiveSuffix.getOtherVariant().toString();
    return result;
}

UnicodeString &
DecimalFormatImpl::getNegativePrefix(UnicodeString &result) const {
    result = fAffixes.fNegativePrefix.getOtherVariant().toString();
    return result;
}

UnicodeString &
DecimalFormatImpl::getNegativeSuffix(UnicodeString &result) const {
    result = fAffixes.fNegativeSuffix.getOtherVariant().toString();
    return result;
}

void
DecimalFormatImpl::adoptDecimalFormatSymbols(DecimalFormatSymbols *symbolsToAdopt) {
    if (symbolsToAdopt == NULL) {
        return;
    }
    delete fSymbols;
    fSymbols = symbolsToAdopt;
    UErrorCode status = U_ZERO_ERROR;
    updateFormatting(kFormattingSymbols, status);
}

void
DecimalFormatImpl::applyPatternFavorCurrencyPrecision(
        const UnicodeString &pattern, UErrorCode &status) {
    UParseError perror;
    applyPattern(pattern, FALSE, perror, status);
    updateForApplyPatternFavorCurrencyPrecision(status);
}

void
DecimalFormatImpl::applyPattern(
        const UnicodeString &pattern, UErrorCode &status) {
    UParseError perror;
    applyPattern(pattern, FALSE, perror, status);
    updateForApplyPattern(status);
}

void
DecimalFormatImpl::applyPattern(
        const UnicodeString &pattern,
        UParseError &perror, UErrorCode &status) {
    applyPattern(pattern, FALSE, perror, status);
    updateForApplyPattern(status);
}

void
DecimalFormatImpl::applyLocalizedPattern(
        const UnicodeString &pattern, UErrorCode &status) {
    UParseError perror;
    applyPattern(pattern, TRUE, perror, status);
    updateForApplyPattern(status);
}

void
DecimalFormatImpl::applyLocalizedPattern(
        const UnicodeString &pattern,
        UParseError &perror,  UErrorCode &status) {
    applyPattern(pattern, TRUE, perror, status);
    updateForApplyPattern(status);
}

void
DecimalFormatImpl::applyPattern(
        const UnicodeString &pattern,
        UBool localized, UParseError &perror, UErrorCode &status) {
    if (U_FAILURE(status)) {
        return;
    }
    DecimalFormatPatternParser patternParser;
    if (localized) {
        patternParser.useSymbols(*fSymbols);
    }
    DecimalFormatPattern out;
    patternParser.applyPatternWithoutExpandAffix(
            pattern, out, perror, status);
    if (U_FAILURE(status)) {
        return;
    }
    fUseScientific = out.fUseExponentialNotation;
    fUseSigDigits = out.fUseSignificantDigits;
    fSuper->NumberFormat::setMinimumIntegerDigits(out.fMinimumIntegerDigits);
    fSuper->NumberFormat::setMaximumIntegerDigits(out.fMaximumIntegerDigits);
    fSuper->NumberFormat::setMinimumFractionDigits(out.fMinimumFractionDigits);
    fSuper->NumberFormat::setMaximumFractionDigits(out.fMaximumFractionDigits);
    fMinSigDigits = out.fMinimumSignificantDigits;
    fMaxSigDigits = out.fMaximumSignificantDigits;
    fEffPrecision.fMinExponentDigits = out.fMinExponentDigits;
    fOptions.fExponent.fAlwaysShowSign = out.fExponentSignAlwaysShown;
    fSuper->NumberFormat::setGroupingUsed(out.fGroupingUsed);
    fGrouping.fGrouping = out.fGroupingSize;
    fGrouping.fGrouping2 = out.fGroupingSize2;
    fOptions.fMantissa.fAlwaysShowDecimal = out.fDecimalSeparatorAlwaysShown;
    if (out.fRoundingIncrementUsed) {
        fEffPrecision.fMantissa.fRoundingIncrement = out.fRoundingIncrement;
    } else {
        fEffPrecision.fMantissa.fRoundingIncrement.clear();
    }
    fAffixes.fPadChar = out.fPad;
    fNegativePrefixPattern = out.fNegPrefixAffix;
    fNegativeSuffixPattern = out.fNegSuffixAffix;
    fPositivePrefixPattern = out.fPosPrefixAffix;
    fPositiveSuffixPattern = out.fPosSuffixAffix;

    // Work around. Pattern parsing code and DecimalFormat code don't agree
    // on the definition of field width, so we have to translate from
    // pattern field width to decimal format field width here.
    fAffixes.fWidth = out.fFormatWidth == 0 ? 0 :
            out.fFormatWidth + fPositivePrefixPattern.countChar32()
            + fPositiveSuffixPattern.countChar32();
    switch (out.fPadPosition) {
    case DecimalFormatPattern::kPadBeforePrefix:
        fAffixes.fPadPosition = DigitAffixesAndPadding::kPadBeforePrefix;
        break;    
    case DecimalFormatPattern::kPadAfterPrefix:
        fAffixes.fPadPosition = DigitAffixesAndPadding::kPadAfterPrefix;
        break;    
    case DecimalFormatPattern::kPadBeforeSuffix:
        fAffixes.fPadPosition = DigitAffixesAndPadding::kPadBeforeSuffix;
        break;    
    case DecimalFormatPattern::kPadAfterSuffix:
        fAffixes.fPadPosition = DigitAffixesAndPadding::kPadAfterSuffix;
        break;    
    default:
        break;
    }
}

void
DecimalFormatImpl::updatePrecision() {
    if (fUseScientific) {
        updatePrecisionForScientific();
    } else {
        updatePrecisionForFixed();
    }
}

static void updatePrecisionForScientificMinMax(
        const DigitInterval &min,
        const DigitInterval &max,
        DigitInterval &resultMin,
        DigitInterval &resultMax,
        SignificantDigitInterval &resultSignificant) {
    resultMin.setIntDigitCount(0);
    resultMin.setFracDigitCount(0);
    resultSignificant.clear();
    resultMax.clear();
    
    int32_t maxIntDigitCount = max.getIntDigitCount();
    int32_t minIntDigitCount = min.getIntDigitCount();
    int32_t maxFracDigitCount = max.getFracDigitCount();
    int32_t minFracDigitCount = min.getFracDigitCount();


    // Not in spec: maxIntDigitCount > 8 assume
    // maxIntDigitCount = minIntDigitCount. Current DecimalFormat API has
    // no provision for unsetting maxIntDigitCount which would be useful for
    // scientific notation. The best we can do is assume that if
    // maxIntDigitCount is the default of 2000000000 or is "big enough" then
    // user did not intend to explicitly set it. The 8 was derived emperically
    // by extensive testing of legacy code.
    if (maxIntDigitCount > 8) {
        maxIntDigitCount = minIntDigitCount;
    }

    // Per the spec, exponent grouping happens if maxIntDigitCount is more
    // than 1 and more than minIntDigitCount.
    UBool bExponentGrouping = maxIntDigitCount > 1 && minIntDigitCount < maxIntDigitCount;
    if (bExponentGrouping) {
        resultMax.setIntDigitCount(maxIntDigitCount);

        // For exponent grouping minIntDigits is always treated as 1 even
        // if it wasn't set to 1!
        resultMin.setIntDigitCount(1);
    } else {
        // Fixed digit count left of decimal. minIntDigitCount doesn't have
        // to equal maxIntDigitCount i.e minIntDigitCount == 0 while
        // maxIntDigitCount == 1.
        int32_t fixedIntDigitCount = maxIntDigitCount;

        // If fixedIntDigitCount is 0 but
        // min or max fraction count is 0 too then use 1. This way we can get
        // unlimited precision for X.XXXEX
        if (fixedIntDigitCount == 0 && (minFracDigitCount == 0 || maxFracDigitCount == 0)) {
            fixedIntDigitCount = 1;
        }
        resultMax.setIntDigitCount(fixedIntDigitCount);
        resultMin.setIntDigitCount(fixedIntDigitCount);
    }
    // Spec says this is how we compute significant digits. 0 means
    // unlimited significant digits.
    int32_t maxSigDigits = minIntDigitCount + maxFracDigitCount;
    if (maxSigDigits > 0) {
        int32_t minSigDigits = minIntDigitCount + minFracDigitCount;
        resultSignificant.setMin(minSigDigits);
        resultSignificant.setMax(maxSigDigits);
    }
}

void
DecimalFormatImpl::updatePrecisionForScientific() {
    FixedPrecision *result = &fEffPrecision.fMantissa;
    if (fUseSigDigits) {
        result->fMax.setFracDigitCount(-1);
        result->fMax.setIntDigitCount(1);
        result->fMin.setFracDigitCount(0);
        result->fMin.setIntDigitCount(1);
        result->fSignificant.clear();
        extractSigDigits(result->fSignificant);
        return;
    }
    DigitInterval max;
    DigitInterval min;
    extractMinMaxDigits(min, max);
    updatePrecisionForScientificMinMax(
            min, max,
            result->fMin, result->fMax, result->fSignificant);
}

void
DecimalFormatImpl::updatePrecisionForFixed() {
    FixedPrecision *result = &fEffPrecision.fMantissa;
    if (!fUseSigDigits) {
        extractMinMaxDigits(result->fMin, result->fMax);
        result->fSignificant.clear();
    } else {
        extractSigDigits(result->fSignificant);
        result->fMin.setIntDigitCount(1);
        result->fMin.setFracDigitCount(0);
        result->fMax.clear();
    }
}

void
 DecimalFormatImpl::extractMinMaxDigits(
        DigitInterval &min, DigitInterval &max) const {
    min.setIntDigitCount(fSuper->getMinimumIntegerDigits());
    max.setIntDigitCount(fSuper->getMaximumIntegerDigits());
    min.setFracDigitCount(fSuper->getMinimumFractionDigits());
    max.setFracDigitCount(fSuper->getMaximumFractionDigits());
}

void
 DecimalFormatImpl::extractSigDigits(
        SignificantDigitInterval &sig) const {
    sig.setMin(fMinSigDigits < 0 ? 0 : fMinSigDigits);
    sig.setMax(fMaxSigDigits < 0 ? 0 : fMaxSigDigits);
}

void
DecimalFormatImpl::updateGrouping() {
    if (fSuper->isGroupingUsed()) {
        fEffGrouping = fGrouping;
    } else {
        fEffGrouping.clear();
    }
}

void
DecimalFormatImpl::updateCurrency(UErrorCode &status) {
    updateFormatting(kFormattingCurrency, TRUE, status);
}

void
DecimalFormatImpl::updateFormatting(
        int32_t changedFormattingFields,
        UErrorCode &status) {
    updateFormatting(changedFormattingFields, TRUE, status);
}

void
DecimalFormatImpl::updateFormatting(
        int32_t changedFormattingFields,
        UBool updatePrecisionBasedOnCurrency,
        UErrorCode &status) {
    if (U_FAILURE(status)) {
        return;
    }
    // Each function updates one field. Order matters. For instance,
    // updatePluralRules comes before updateCurrencyAffixInfo because the
    // fRules field is needed to update the fCurrencyAffixInfo field.
    updateFormattingUsesCurrency(changedFormattingFields);
    updateFormattingFixedPointFormatter(changedFormattingFields);
    updateFormattingAffixParser(changedFormattingFields);
    updateFormattingPluralRules(changedFormattingFields, status);
    updateFormattingCurrencyAffixInfo(
            changedFormattingFields,
            updatePrecisionBasedOnCurrency,
            status);
    updateFormattingLocalizedPositivePrefix(
            changedFormattingFields, status);
    updateFormattingLocalizedPositiveSuffix(
            changedFormattingFields, status);
    updateFormattingLocalizedNegativePrefix(
            changedFormattingFields, status);
    updateFormattingLocalizedNegativeSuffix(
            changedFormattingFields, status);
}

void
DecimalFormatImpl::updateFormattingUsesCurrency(
        int32_t &changedFormattingFields) {
    if ((changedFormattingFields & kFormattingAffixes) == 0) {
        // If no affixes changed, don't need to do any work
        return;
    }
    UBool newUsesCurrency =
            fPositivePrefixPattern.usesCurrency() ||
            fPositiveSuffixPattern.usesCurrency() ||
            fNegativePrefixPattern.usesCurrency() ||
            fNegativeSuffixPattern.usesCurrency();
    if (fMonetary != newUsesCurrency) {
        fMonetary = newUsesCurrency;
        changedFormattingFields |= kFormattingUsesCurrency;
    }
}

void
DecimalFormatImpl::updateFormattingPluralRules(
        int32_t &changedFormattingFields, UErrorCode &status) {
    if ((changedFormattingFields & (kFormattingSymbols | kFormattingUsesCurrency)) == 0) {
        // No work to do if both fSymbols and fMonetary
        // fields are unchanged
        return;
    }
    if (U_FAILURE(status)) {
        return;
    }
    PluralRules *newRules = NULL;
    if (fMonetary) {
        newRules = PluralRules::forLocale(fSymbols->getLocale(), status);
        if (U_FAILURE(status)) {
            return;
        }
    }
    // Its ok to say a field has changed when it really hasn't but not
    // the other way around. Here we assume the field changed unless it
    // was NULL before and is still NULL now
    if (fRules != newRules) {
        delete fRules;
        fRules = newRules;
        changedFormattingFields |= kFormattingPluralRules;
    }
}

void
DecimalFormatImpl::updateFormattingCurrencyAffixInfo(
        int32_t &changedFormattingFields,
        UBool updatePrecisionBasedOnCurrency,
        UErrorCode &status) {
    if ((changedFormattingFields & (
            kFormattingSymbols | kFormattingCurrency |
            kFormattingUsesCurrency | kFormattingPluralRules)) == 0) {
        // If all these fields are unchanged, no work to do.
        return;
    }
    if (U_FAILURE(status)) {
        return;
    }
    if (!fMonetary) {
        if (fCurrencyAffixInfo.isDefault()) {
            // In this case don't have to do any work
            return;
        }
        fCurrencyAffixInfo.set(NULL, NULL, NULL, status);
        if (U_FAILURE(status)) {
            return;
        }
        changedFormattingFields |= kFormattingCurrencyAffixInfo;
    } else {
        const UChar *currency = fSuper->getCurrency();
        UChar localeCurr[4];
        if (currency[0] == 0) {
            ucurr_forLocale(fSymbols->getLocale().getName(), localeCurr, UPRV_LENGTHOF(localeCurr), &status);
            if (U_SUCCESS(status)) {
                currency = localeCurr;
                fSuper->NumberFormat::setCurrency(currency, status);
            } else {
                currency = NULL;
                status = U_ZERO_ERROR;
            }
        }
        fCurrencyAffixInfo.set(
                fSymbols->getLocale().getName(), fRules, currency, status);
        if (U_FAILURE(status)) {
            return;
        }
        UBool customCurrencySymbol = FALSE;
        // If DecimalFormatSymbols has custom currency symbol, prefer
        // that over what we just read from the resource bundles
        if (fSymbols->isCustomCurrencySymbol()) {
            fCurrencyAffixInfo.setSymbol(
                    fSymbols->getConstSymbol(DecimalFormatSymbols::kCurrencySymbol));
            customCurrencySymbol = TRUE;
        }
        if (fSymbols->isCustomIntlCurrencySymbol()) {
            fCurrencyAffixInfo.setISO(
                    fSymbols->getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol));
            customCurrencySymbol = TRUE;
        }
        changedFormattingFields |= kFormattingCurrencyAffixInfo;
        if (currency && !customCurrencySymbol && updatePrecisionBasedOnCurrency) {
            FixedPrecision precision;
            CurrencyAffixInfo::adjustPrecision(
                    currency, fCurrencyUsage, precision, status);
            if (U_FAILURE(status)) {
                return;
            }
            fSuper->NumberFormat::setMinimumFractionDigits(
                    precision.fMin.getFracDigitCount());
            fSuper->NumberFormat::setMaximumFractionDigits(
                    precision.fMax.getFracDigitCount());
            updatePrecision();
            fEffPrecision.fMantissa.fRoundingIncrement =
                    precision.fRoundingIncrement;
        }
 
    }
}

void
DecimalFormatImpl::updateFormattingFixedPointFormatter(
        int32_t &changedFormattingFields) {
    if ((changedFormattingFields & (kFormattingSymbols | kFormattingUsesCurrency)) == 0) {
        // No work to do if fSymbols is unchanged
        return;
    }
    if (fMonetary) {
        fFormatter.setDecimalFormatSymbolsForMonetary(*fSymbols);
    } else {
        fFormatter.setDecimalFormatSymbols(*fSymbols);
    }
}

void
DecimalFormatImpl::updateFormattingAffixParser(
        int32_t &changedFormattingFields) {
    if ((changedFormattingFields & kFormattingSymbols) == 0) {
        // No work to do if fSymbols is unchanged
        return;
    }
    fAffixParser.setDecimalFormatSymbols(*fSymbols);
    changedFormattingFields |= kFormattingAffixParser;
}

void
DecimalFormatImpl::updateFormattingLocalizedPositivePrefix(
        int32_t &changedFormattingFields, UErrorCode &status) {
    if (U_FAILURE(status)) {
        return;
    }
    if ((changedFormattingFields & (
            kFormattingPosPrefix | kFormattingAffixParserWithCurrency)) == 0) {
        // No work to do
        return;
    }
    fAffixes.fPositivePrefix.remove();
    fAffixParser.parse(
            fPositivePrefixPattern,
            fCurrencyAffixInfo,
            fAffixes.fPositivePrefix,
            status);
}

void
DecimalFormatImpl::updateFormattingLocalizedPositiveSuffix(
        int32_t &changedFormattingFields, UErrorCode &status) {
    if (U_FAILURE(status)) {
        return;
    }
    if ((changedFormattingFields & (
            kFormattingPosSuffix | kFormattingAffixParserWithCurrency)) == 0) {
        // No work to do
        return;
    }
    fAffixes.fPositiveSuffix.remove();
    fAffixParser.parse(
            fPositiveSuffixPattern,
            fCurrencyAffixInfo,
            fAffixes.fPositiveSuffix,
            status);
}

void
DecimalFormatImpl::updateFormattingLocalizedNegativePrefix(
        int32_t &changedFormattingFields, UErrorCode &status) {
    if (U_FAILURE(status)) {
        return;
    }
    if ((changedFormattingFields & (
            kFormattingNegPrefix | kFormattingAffixParserWithCurrency)) == 0) {
        // No work to do
        return;
    }
    fAffixes.fNegativePrefix.remove();
    fAffixParser.parse(
            fNegativePrefixPattern,
            fCurrencyAffixInfo,
            fAffixes.fNegativePrefix,
            status);
}

void
DecimalFormatImpl::updateFormattingLocalizedNegativeSuffix(
        int32_t &changedFormattingFields, UErrorCode &status) {
    if (U_FAILURE(status)) {
        return;
    }
    if ((changedFormattingFields & (
            kFormattingNegSuffix | kFormattingAffixParserWithCurrency)) == 0) {
        // No work to do
        return;
    }
    fAffixes.fNegativeSuffix.remove();
    fAffixParser.parse(
            fNegativeSuffixPattern,
            fCurrencyAffixInfo,
            fAffixes.fNegativeSuffix,
            status);
}

void
DecimalFormatImpl::updateForApplyPatternFavorCurrencyPrecision(
        UErrorCode &status) {
    updateAll(kFormattingAll & ~kFormattingSymbols, TRUE, status);
}

void
DecimalFormatImpl::updateForApplyPattern(UErrorCode &status) {
    updateAll(kFormattingAll & ~kFormattingSymbols, FALSE, status);
}

void
DecimalFormatImpl::updateAll(UErrorCode &status) {
    updateAll(kFormattingAll, TRUE, status);
}

void
DecimalFormatImpl::updateAll(
        int32_t formattingFlags,
        UBool updatePrecisionBasedOnCurrency,
        UErrorCode &status) {
    if (U_FAILURE(status)) {
        return;
    }
    updatePrecision();
    updateGrouping();
    updateFormatting(
            formattingFlags, updatePrecisionBasedOnCurrency, status);
    setMultiplierScale(getPatternScale());
}


static int32_t
getMinimumLengthToDescribeGrouping(const DigitGrouping &grouping) {
    if (grouping.fGrouping <= 0) {
        return 0;
    }
    if (grouping.fGrouping2 <= 0) {
        return grouping.fGrouping + 1;
    }
    return grouping.fGrouping + grouping.fGrouping2 + 1;
}

/**
 * Given a grouping policy, calculates how many digits are needed left of
 * the decimal point to achieve a desired length left of the
 * decimal point.
 * @param grouping the grouping policy
 * @param desiredLength number of characters needed left of decimal point
 * @param minLeftDigits at least this many digits is returned
 * @param leftDigits the number of digits needed stored here
 *  which is >= minLeftDigits.
 * @return true if a perfect fit or false if having leftDigits would exceed
 *   desiredLength
 */
static UBool
getLeftDigitsForLeftLength(
        const DigitGrouping &grouping,
        int32_t desiredLength,
        int32_t minLeftDigits,
        int32_t &leftDigits) {
    leftDigits = minLeftDigits;
    int32_t lengthSoFar = leftDigits + grouping.getSeparatorCount(leftDigits);
    while (lengthSoFar < desiredLength) {
        lengthSoFar += grouping.isSeparatorAt(leftDigits + 1, leftDigits) ? 2 : 1;
        ++leftDigits;
    }
    return (lengthSoFar == desiredLength);
}

int32_t
DecimalFormatImpl::computeExponentPatternLength() const {
    if (fUseScientific) {
        return 1 + (fOptions.fExponent.fAlwaysShowSign ? 1 : 0) + fEffPrecision.fMinExponentDigits;
    }
    return 0;
}

int32_t
DecimalFormatImpl::countFractionDigitAndDecimalPatternLength(
        int32_t fracDigitCount) const {
    if (!fOptions.fMantissa.fAlwaysShowDecimal && fracDigitCount == 0) {
        return 0;
    }
    return fracDigitCount + 1;
}

UnicodeString&
DecimalFormatImpl::toNumberPattern(
        UBool hasPadding, int32_t minimumLength, UnicodeString& result) const {
    // Get a grouping policy like the one in this object that does not
    // have minimum grouping since toPattern doesn't support it.
    DigitGrouping grouping(fEffGrouping);
    grouping.fMinGrouping = 0;

    // Only for fixed digits, these are the digits that get 0's.
    DigitInterval minInterval;

    // Only for fixed digits, these are the digits that get #'s.
    DigitInterval maxInterval;

    // Only for significant digits
    int32_t sigMin;
    int32_t sigMax;

    // These are all the digits to be displayed. For significant digits,
    // this interval always starts at the 1's place an extends left.
    DigitInterval fullInterval;

    // Digit range of rounding increment. If rounding increment is .025.
    // then roundingIncrementLowerExp = -3 and roundingIncrementUpperExp = -1
    int32_t roundingIncrementLowerExp = 0;
    int32_t roundingIncrementUpperExp = 0;

    if (fUseSigDigits) {
        SignificantDigitInterval sigInterval;
        extractSigDigits(sigInterval);
        sigMax = sigInterval.getMax();
        sigMin = sigInterval.getMin();
        fullInterval.setFracDigitCount(0);
        fullInterval.setIntDigitCount(sigMax);
    } else {
        extractMinMaxDigits(minInterval, maxInterval);
        if (fUseScientific) {
           if (maxInterval.getIntDigitCount() > kMaxScientificIntegerDigits) {
               maxInterval.setIntDigitCount(1);
               minInterval.shrinkToFitWithin(maxInterval);
           }
        } else if (hasPadding) {
            // Make max int digits match min int digits for now, we
            // compute necessary padding later.
            maxInterval.setIntDigitCount(minInterval.getIntDigitCount());
        } else {
            // For some reason toPattern adds at least one leading '#'
            maxInterval.setIntDigitCount(minInterval.getIntDigitCount() + 1);
        }
        if (!fEffPrecision.fMantissa.fRoundingIncrement.isZero()) {
            roundingIncrementLowerExp = 
                    fEffPrecision.fMantissa.fRoundingIncrement.getLowerExponent();
            roundingIncrementUpperExp = 
                    fEffPrecision.fMantissa.fRoundingIncrement.getUpperExponent();
            // We have to include the rounding increment in what we display
            maxInterval.expandToContainDigit(roundingIncrementLowerExp);
            maxInterval.expandToContainDigit(roundingIncrementUpperExp - 1);
        }
        fullInterval = maxInterval;
    }
    // We have to include enough digits to show grouping strategy
    int32_t minLengthToDescribeGrouping =
           getMinimumLengthToDescribeGrouping(grouping);
    if (minLengthToDescribeGrouping > 0) {
        fullInterval.expandToContainDigit(
                getMinimumLengthToDescribeGrouping(grouping) - 1);
    }

    // If we have a minimum length, we have to add digits to the left to
    // depict padding.
    if (hasPadding) {
        // For non scientific notation,
        //  minimumLengthForMantissa = minimumLength
        int32_t minimumLengthForMantissa = 
                minimumLength - computeExponentPatternLength();
        int32_t mininumLengthForMantissaIntPart =
                minimumLengthForMantissa
                - countFractionDigitAndDecimalPatternLength(
                        fullInterval.getFracDigitCount());
        // Because of grouping, we may need fewer than expected digits to
        // achieve the length we need.
        int32_t digitsNeeded;
        if (getLeftDigitsForLeftLength(
                grouping,
                mininumLengthForMantissaIntPart,
                fullInterval.getIntDigitCount(),
                digitsNeeded)) {

            // In this case, we achieved the exact length that we want.
            fullInterval.setIntDigitCount(digitsNeeded);
        } else if (digitsNeeded > fullInterval.getIntDigitCount()) {

            // Having digitsNeeded digits goes over desired length which
            // means that to have desired length would mean starting on a
            // grouping sepearator e.g ,###,### so add a '#' and use one
            // less digit. This trick gives ####,### but that is the best
            // we can do.
            result.append(kPatternDigit);
            fullInterval.setIntDigitCount(digitsNeeded - 1);
        }
    }
    int32_t maxDigitPos = fullInterval.getMostSignificantExclusive();
    int32_t minDigitPos = fullInterval.getLeastSignificantInclusive();
    for (int32_t i = maxDigitPos - 1; i >= minDigitPos; --i) {
        if (!fOptions.fMantissa.fAlwaysShowDecimal && i == -1) {
            result.append(kPatternDecimalSeparator);
        }
        if (fUseSigDigits) {
            // Use digit symbol
            if (i >= sigMax || i < sigMax - sigMin) {
                result.append(kPatternDigit);
            } else {
                result.append(kPatternSignificantDigit);
            }
        } else {
            if (i < roundingIncrementUpperExp && i >= roundingIncrementLowerExp) {
                result.append((UChar)(fEffPrecision.fMantissa.fRoundingIncrement.getDigitByExponent(i) + kPatternZeroDigit));
            } else if (minInterval.contains(i)) {
                result.append(kPatternZeroDigit);
            } else {
                result.append(kPatternDigit);
            }
        }
        if (grouping.isSeparatorAt(i + 1, i)) {
            result.append(kPatternGroupingSeparator);
        }
        if (fOptions.fMantissa.fAlwaysShowDecimal && i == 0) {
            result.append(kPatternDecimalSeparator);
        }
    }
    if (fUseScientific) {
        result.append(kPatternExponent);
        if (fOptions.fExponent.fAlwaysShowSign) {
            result.append(kPatternPlus);
        }
        for (int32_t i = 0; i < 1 || i < fEffPrecision.fMinExponentDigits; ++i) {
            result.append(kPatternZeroDigit);
        }
    }
    return result;
}

UnicodeString&
DecimalFormatImpl::toPattern(UnicodeString& result) const {
    result.remove();
    UnicodeString padSpec;
    if (fAffixes.fWidth > 0) {
        padSpec.append(kPatternPadEscape);
        padSpec.append(fAffixes.fPadChar);
    }
    if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforePrefix) {
        result.append(padSpec);
    }
    fPositivePrefixPattern.toUserString(result);
    if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterPrefix) {
        result.append(padSpec);
    }
    toNumberPattern(
            fAffixes.fWidth > 0,
            fAffixes.fWidth - fPositivePrefixPattern.countChar32() - fPositiveSuffixPattern.countChar32(),
            result);
    if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforeSuffix) {
        result.append(padSpec);
    }
    fPositiveSuffixPattern.toUserString(result);
    if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterSuffix) {
        result.append(padSpec);
    }
    AffixPattern withNegative;
    withNegative.add(AffixPattern::kNegative);
    withNegative.append(fPositivePrefixPattern);
    if (!fPositiveSuffixPattern.equals(fNegativeSuffixPattern) ||
            !withNegative.equals(fNegativePrefixPattern)) {
        result.append(kPatternSeparator);
        if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforePrefix) {
            result.append(padSpec);
        }
        fNegativePrefixPattern.toUserString(result);
        if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterPrefix) {
            result.append(padSpec);
        }
        toNumberPattern(
                fAffixes.fWidth > 0,
                fAffixes.fWidth - fNegativePrefixPattern.countChar32() - fNegativeSuffixPattern.countChar32(),
                result);
        if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforeSuffix) {
            result.append(padSpec);
        }
        fNegativeSuffixPattern.toUserString(result);
        if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterSuffix) {
            result.append(padSpec);
        }
    }
    return result;
}

int32_t
DecimalFormatImpl::getOldFormatWidth() const {
    if (fAffixes.fWidth == 0) {
        return 0;
    }
    return fAffixes.fWidth - fPositiveSuffixPattern.countChar32() - fPositivePrefixPattern.countChar32();
}

const UnicodeString &
DecimalFormatImpl::getConstSymbol(
        DecimalFormatSymbols::ENumberFormatSymbol symbol) const {
   return fSymbols->getConstSymbol(symbol); 
}

UBool
DecimalFormatImpl::isParseFastpath() const {
    AffixPattern negative;
    negative.add(AffixPattern::kNegative);

    return fAffixes.fWidth == 0 &&
    fPositivePrefixPattern.countChar32() == 0 &&
    fNegativePrefixPattern.equals(negative) &&
    fPositiveSuffixPattern.countChar32() == 0 &&
    fNegativeSuffixPattern.countChar32() == 0;
}


U_NAMESPACE_END

#endif /* #if !UCONFIG_NO_FORMATTING */