// © 2017 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html

#include "unicode/utypes.h"

#if !UCONFIG_NO_FORMATTING

#include "unicode/numberformatter.h"
#include "number_types.h"
#include "formatted_string_builder.h"
#include "number_decimfmtprops.h"

using namespace icu;
using namespace icu::number;
using namespace icu::number::impl;

namespace {

int32_t
addPaddingHelper(UChar32 paddingCp, int32_t requiredPadding, FormattedStringBuilder &string, int32_t index,
                 UErrorCode &status) {
    for (int32_t i = 0; i < requiredPadding; i++) {
        // TODO: If appending to the end, this will cause actual insertion operations. Improve.
        string.insertCodePoint(index, paddingCp, kUndefinedField, status);
    }
    return U16_LENGTH(paddingCp) * requiredPadding;
}

}

Padder::Padder(UChar32 cp, int32_t width, UNumberFormatPadPosition position) : fWidth(width) {
    // TODO(13034): Consider making this a string instead of code point.
    fUnion.padding.fCp = cp;
    fUnion.padding.fPosition = position;
}

Padder::Padder(int32_t width) : fWidth(width) {}

Padder Padder::none() {
    return {-1};
}

Padder Padder::codePoints(UChar32 cp, int32_t targetWidth, UNumberFormatPadPosition position) {
    // TODO: Validate the code point?
    if (targetWidth >= 0) {
        return {cp, targetWidth, position};
    } else {
        return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
    }
}

Padder Padder::forProperties(const DecimalFormatProperties& properties) {
    UChar32 padCp;
    if (properties.padString.length() > 0) {
        padCp = properties.padString.char32At(0);
    } else {
        padCp = kFallbackPaddingString[0];
    }
    return {padCp, properties.formatWidth, properties.padPosition.getOrDefault(UNUM_PAD_BEFORE_PREFIX)};
}

int32_t Padder::padAndApply(const Modifier &mod1, const Modifier &mod2,
                            FormattedStringBuilder &string, int32_t leftIndex, int32_t rightIndex,
                            UErrorCode &status) const {
    int32_t modLength = mod1.getCodePointCount() + mod2.getCodePointCount();
    int32_t requiredPadding = fWidth - modLength - string.codePointCount();
    U_ASSERT(leftIndex == 0 &&
             rightIndex == string.length()); // fix the previous line to remove this assertion

    int length = 0;
    if (requiredPadding <= 0) {
        // Padding is not required.
        length += mod1.apply(string, leftIndex, rightIndex, status);
        length += mod2.apply(string, leftIndex, rightIndex + length, status);
        return length;
    }

    PadPosition position = fUnion.padding.fPosition;
    UChar32 paddingCp = fUnion.padding.fCp;
    if (position == UNUM_PAD_AFTER_PREFIX) {
        length += addPaddingHelper(paddingCp, requiredPadding, string, leftIndex, status);
    } else if (position == UNUM_PAD_BEFORE_SUFFIX) {
        length += addPaddingHelper(paddingCp, requiredPadding, string, rightIndex + length, status);
    }
    length += mod1.apply(string, leftIndex, rightIndex + length, status);
    length += mod2.apply(string, leftIndex, rightIndex + length, status);
    if (position == UNUM_PAD_BEFORE_PREFIX) {
        length += addPaddingHelper(paddingCp, requiredPadding, string, leftIndex, status);
    } else if (position == UNUM_PAD_AFTER_SUFFIX) {
        length += addPaddingHelper(paddingCp, requiredPadding, string, rightIndex + length, status);
    }

    return length;
}

#endif /* #if !UCONFIG_NO_FORMATTING */
