/*
 * Copyright (C) 2015, International Business Machines
 * Corporation and others.  All Rights Reserved.
 *
 * file name: digitformatter.cpp
 */

#include "unicode/utypes.h"

#if !UCONFIG_NO_FORMATTING
#include "starboard/client_porting/poem/string_poem.h"

#include "unicode/dcfmtsym.h"
#include "unicode/unum.h"

#include "digitformatter.h"
#include "digitgrouping.h"
#include "digitinterval.h"
#include "digitlst.h"
#include "fphdlimp.h"
#include "smallintformatter.h"
#include "unistrappender.h"
#include "visibledigits.h"

U_NAMESPACE_BEGIN

DigitFormatter::DigitFormatter()
        : fGroupingSeparator(",", -1, US_INV), fDecimal(".", -1, US_INV),
          fNegativeSign("-", -1, US_INV), fPositiveSign("+", -1, US_INV),
          fIsStandardDigits(TRUE), fExponent("E", -1, US_INV) {
    for (int32_t i = 0; i < 10; ++i) {
        fLocalizedDigits[i] = (UChar32) (0x30 + i);
    }
    fInfinity.setTo(UnicodeString("Inf", -1, US_INV), UNUM_INTEGER_FIELD);
    fNan.setTo(UnicodeString("Nan", -1, US_INV), UNUM_INTEGER_FIELD);
}

DigitFormatter::DigitFormatter(const DecimalFormatSymbols &symbols) {
    setDecimalFormatSymbols(symbols);
}

void
DigitFormatter::setOtherDecimalFormatSymbols(
        const DecimalFormatSymbols &symbols) {
    fLocalizedDigits[0] = symbols.getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0);
    fLocalizedDigits[1] = symbols.getConstSymbol(DecimalFormatSymbols::kOneDigitSymbol).char32At(0);
    fLocalizedDigits[2] = symbols.getConstSymbol(DecimalFormatSymbols::kTwoDigitSymbol).char32At(0);
    fLocalizedDigits[3] = symbols.getConstSymbol(DecimalFormatSymbols::kThreeDigitSymbol).char32At(0);
    fLocalizedDigits[4] = symbols.getConstSymbol(DecimalFormatSymbols::kFourDigitSymbol).char32At(0);
    fLocalizedDigits[5] = symbols.getConstSymbol(DecimalFormatSymbols::kFiveDigitSymbol).char32At(0);
    fLocalizedDigits[6] = symbols.getConstSymbol(DecimalFormatSymbols::kSixDigitSymbol).char32At(0);
    fLocalizedDigits[7] = symbols.getConstSymbol(DecimalFormatSymbols::kSevenDigitSymbol).char32At(0);
    fLocalizedDigits[8] = symbols.getConstSymbol(DecimalFormatSymbols::kEightDigitSymbol).char32At(0);
    fLocalizedDigits[9] = symbols.getConstSymbol(DecimalFormatSymbols::kNineDigitSymbol).char32At(0);
    fIsStandardDigits = isStandardDigits();
    fNegativeSign = symbols.getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
    fPositiveSign = symbols.getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
    fInfinity.setTo(symbols.getConstSymbol(DecimalFormatSymbols::kInfinitySymbol), UNUM_INTEGER_FIELD);
    fNan.setTo(symbols.getConstSymbol(DecimalFormatSymbols::kNaNSymbol), UNUM_INTEGER_FIELD);
    fExponent = symbols.getConstSymbol(DecimalFormatSymbols::kExponentialSymbol);
}

void
DigitFormatter::setDecimalFormatSymbolsForMonetary(
        const DecimalFormatSymbols &symbols) {
    setOtherDecimalFormatSymbols(symbols);
    fGroupingSeparator = symbols.getConstSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol);
    fDecimal = symbols.getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol);
}

void
DigitFormatter::setDecimalFormatSymbols(
        const DecimalFormatSymbols &symbols) {
    setOtherDecimalFormatSymbols(symbols);
    fGroupingSeparator = symbols.getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol);
    fDecimal = symbols.getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
}

static void appendField(
        int32_t fieldId,
        const UnicodeString &value,
        FieldPositionHandler &handler,
        UnicodeString &appendTo) {
    int32_t currentLength = appendTo.length();
    appendTo.append(value);
    handler.addAttribute(
            fieldId,
            currentLength,
            appendTo.length());
}

int32_t DigitFormatter::countChar32(
        const DigitGrouping &grouping,
        const DigitInterval &interval,
        const DigitFormatterOptions &options) const {
    int32_t result = interval.length();

    // We always emit '0' in lieu of no digits.
    if (result == 0) {
        result = 1;
    }
    if (options.fAlwaysShowDecimal || interval.getLeastSignificantInclusive() < 0) {
        result += fDecimal.countChar32();
    }
    result += grouping.getSeparatorCount(interval.getIntDigitCount()) * fGroupingSeparator.countChar32();
    return result;
}

int32_t
DigitFormatter::countChar32(
        const VisibleDigits &digits,
        const DigitGrouping &grouping,
        const DigitFormatterOptions &options) const {
    if (digits.isNaN()) {
        return countChar32ForNaN();
    }   
    if (digits.isInfinite()) {
        return countChar32ForInfinity();
    }   
    return countChar32(
            grouping,
            digits.getInterval(),
            options);
}

int32_t
DigitFormatter::countChar32(
        const VisibleDigitsWithExponent &digits,
        const SciFormatterOptions &options) const {
    if (digits.isNaN()) {
        return countChar32ForNaN();
    }
    if (digits.isInfinite()) {
        return countChar32ForInfinity();
    }
    const VisibleDigits *exponent = digits.getExponent();
    if (exponent == NULL) {
        DigitGrouping grouping;
        return countChar32(
                grouping,
                digits.getMantissa().getInterval(),
                options.fMantissa);
    }
    return countChar32(
            *exponent, digits.getMantissa().getInterval(), options);
}

int32_t
DigitFormatter::countChar32(
        const VisibleDigits &exponent,
        const DigitInterval &mantissaInterval,
        const SciFormatterOptions &options) const {
    DigitGrouping grouping;
    int32_t count = countChar32(
            grouping, mantissaInterval, options.fMantissa);
    count += fExponent.countChar32();
    count += countChar32ForExponent(
            exponent, options.fExponent);
    return count;
}

UnicodeString &DigitFormatter::format(
        const VisibleDigits &digits,
        const DigitGrouping &grouping,
        const DigitFormatterOptions &options,
        FieldPositionHandler &handler,
        UnicodeString &appendTo) const {
    if (digits.isNaN()) {
        return formatNaN(handler, appendTo);
    }
    if (digits.isInfinite()) {
        return formatInfinity(handler, appendTo);
    }

    const DigitInterval &interval = digits.getInterval();
    int32_t digitsLeftOfDecimal = interval.getMostSignificantExclusive();
    int32_t lastDigitPos = interval.getLeastSignificantInclusive();
    int32_t intBegin = appendTo.length();
    int32_t fracBegin;

    // Emit "0" instead of empty string.
    if (digitsLeftOfDecimal == 0 && lastDigitPos == 0) {
        appendTo.append(fLocalizedDigits[0]);
        handler.addAttribute(UNUM_INTEGER_FIELD, intBegin, appendTo.length());
        if (options.fAlwaysShowDecimal) {
            appendField(
                    UNUM_DECIMAL_SEPARATOR_FIELD,
                    fDecimal,
                    handler,
                    appendTo);
        }
        return appendTo;
    }
    {
        UnicodeStringAppender appender(appendTo);
        for (int32_t i = interval.getMostSignificantExclusive() - 1;
                i >= interval.getLeastSignificantInclusive(); --i) {
            if (i == -1) {
                appender.flush();
                appendField(
                        UNUM_DECIMAL_SEPARATOR_FIELD,
                        fDecimal,
                        handler,
                        appendTo);
                fracBegin = appendTo.length();
            }
            appender.append(fLocalizedDigits[digits.getDigitByExponent(i)]);
            if (grouping.isSeparatorAt(digitsLeftOfDecimal, i)) {
                appender.flush();
                appendField(
                        UNUM_GROUPING_SEPARATOR_FIELD,
                        fGroupingSeparator,
                        handler,
                        appendTo);
            }
            if (i == 0) {
                appender.flush();
                if (digitsLeftOfDecimal > 0) {
                    handler.addAttribute(UNUM_INTEGER_FIELD, intBegin, appendTo.length());
                }
            }
        }
        if (options.fAlwaysShowDecimal && lastDigitPos == 0) {
            appender.flush();
            appendField(
                    UNUM_DECIMAL_SEPARATOR_FIELD,
                    fDecimal,
                    handler,
                    appendTo);
        }
    }
    // lastDigitPos is never > 0 so we are guaranteed that kIntegerField
    // is already added.
    if (lastDigitPos < 0) {
        handler.addAttribute(UNUM_FRACTION_FIELD, fracBegin, appendTo.length());
    }
    return appendTo;
}

UnicodeString &
DigitFormatter::format(
        const VisibleDigitsWithExponent &digits,
        const SciFormatterOptions &options,
        FieldPositionHandler &handler,
        UnicodeString &appendTo) const {
    DigitGrouping grouping;
    format(
            digits.getMantissa(),
            grouping,
            options.fMantissa,
            handler,
            appendTo);
    const VisibleDigits *exponent = digits.getExponent();
    if (exponent == NULL) {
        return appendTo;
    }
    int32_t expBegin = appendTo.length();
    appendTo.append(fExponent);
    handler.addAttribute(
            UNUM_EXPONENT_SYMBOL_FIELD, expBegin, appendTo.length());
    return formatExponent(
            *exponent,
            options.fExponent,
            UNUM_EXPONENT_SIGN_FIELD,
            UNUM_EXPONENT_FIELD,
            handler,
            appendTo);
}

static int32_t formatInt(
        int32_t value, uint8_t *digits) {
    int32_t idx = 0;
    while (value > 0) {
        digits[idx++] = (uint8_t) (value % 10);
        value /= 10;
    }
    return idx;
}

UnicodeString &
DigitFormatter::formatDigits(
        const uint8_t *digits,
        int32_t count,
        const IntDigitCountRange &range,
        int32_t intField,
        FieldPositionHandler &handler,
        UnicodeString &appendTo) const {
    int32_t i = range.pin(count) - 1;
    int32_t begin = appendTo.length();

    // Always emit '0' as placeholder for empty string.
    if (i == -1) {
        appendTo.append(fLocalizedDigits[0]);
        handler.addAttribute(intField, begin, appendTo.length());
        return appendTo;
    }
    {
        UnicodeStringAppender appender(appendTo);
        for (; i >= count; --i) {
            appender.append(fLocalizedDigits[0]);
        }
        for (; i >= 0; --i) {
            appender.append(fLocalizedDigits[digits[i]]);
        }
    }
    handler.addAttribute(intField, begin, appendTo.length());
    return appendTo;
}

UnicodeString &
DigitFormatter::formatExponent(
        const VisibleDigits &digits,
        const DigitFormatterIntOptions &options,
        int32_t signField,
        int32_t intField,
        FieldPositionHandler &handler,
        UnicodeString &appendTo) const {
    UBool neg = digits.isNegative();
    if (neg || options.fAlwaysShowSign) {
        appendField(
                signField,
                neg ? fNegativeSign : fPositiveSign,
                handler,
                appendTo);
    }
    int32_t begin = appendTo.length();
    DigitGrouping grouping;
    DigitFormatterOptions expOptions;
    FieldPosition fpos(FieldPosition::DONT_CARE);
    FieldPositionOnlyHandler noHandler(fpos);
    format(
            digits,
            grouping,
            expOptions,
            noHandler,
            appendTo);
    handler.addAttribute(intField, begin, appendTo.length());
    return appendTo;
}

int32_t
DigitFormatter::countChar32ForExponent(
        const VisibleDigits &exponent,
        const DigitFormatterIntOptions &options) const {
    int32_t result = 0;
    UBool neg = exponent.isNegative();
    if (neg || options.fAlwaysShowSign) {
        result += neg ? fNegativeSign.countChar32() : fPositiveSign.countChar32();
    }
    DigitGrouping grouping;
    DigitFormatterOptions expOptions;
    result += countChar32(grouping, exponent.getInterval(), expOptions);
    return result;
}

UnicodeString &
DigitFormatter::formatPositiveInt32(
        int32_t positiveValue,
        const IntDigitCountRange &range,
        FieldPositionHandler &handler,
        UnicodeString &appendTo) const {
    // super fast path
    if (fIsStandardDigits && SmallIntFormatter::canFormat(positiveValue, range)) {
        int32_t begin = appendTo.length();
        SmallIntFormatter::format(positiveValue, range, appendTo);
        handler.addAttribute(UNUM_INTEGER_FIELD, begin, appendTo.length());
        return appendTo;
    }
    uint8_t digits[10];
    int32_t count = formatInt(positiveValue, digits);
    return formatDigits(
            digits,
            count,
            range,
            UNUM_INTEGER_FIELD,
            handler,
            appendTo);
}

UBool DigitFormatter::isStandardDigits() const {
    UChar32 cdigit = 0x30;
    for (int32_t i = 0; i < UPRV_LENGTHOF(fLocalizedDigits); ++i) {
        if (fLocalizedDigits[i] != cdigit) {
            return FALSE;
        }
        ++cdigit;
    }
    return TRUE;
}

UBool
DigitFormatter::equals(const DigitFormatter &rhs) const {
    UBool result = (fGroupingSeparator == rhs.fGroupingSeparator) &&
                   (fDecimal == rhs.fDecimal) &&
                   (fNegativeSign == rhs.fNegativeSign) &&
                   (fPositiveSign == rhs.fPositiveSign) &&
                   (fInfinity.equals(rhs.fInfinity)) &&
                   (fNan.equals(rhs.fNan)) &&
                   (fIsStandardDigits == rhs.fIsStandardDigits) &&
                   (fExponent == rhs.fExponent);

    if (!result) {
        return FALSE;
    }
    for (int32_t i = 0; i < UPRV_LENGTHOF(fLocalizedDigits); ++i) {
        if (fLocalizedDigits[i] != rhs.fLocalizedDigits[i]) {
            return FALSE;
        }
    }
    return TRUE;
}


U_NAMESPACE_END

#endif /* #if !UCONFIG_NO_FORMATTING */
