10596faeddefbf198de137d5e893708495ab1584cFredrik Roubert// © 2016 and later: Unicode, Inc. and others.
264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html
3c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert/*
4c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * Copyright (C) 2015, International Business Machines
5c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * Corporation and others.  All Rights Reserved.
6c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert *
7c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * file name: digitaffixesandpadding.cpp
8c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert */
9c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert
10c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert#include "unicode/utypes.h"
11c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert
12c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert#if !UCONFIG_NO_FORMATTING
13c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert
14c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert#include "unicode/plurrule.h"
15c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert#include "charstr.h"
16c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert#include "digitaffix.h"
17c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert#include "digitaffixesandpadding.h"
18c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert#include "digitlst.h"
19c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert#include "uassert.h"
20c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert#include "valueformatter.h"
21c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert#include "visibledigits.h"
22c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert
23c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik RoubertU_NAMESPACE_BEGIN
24c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert
25c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik RoubertUBool
26c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik RoubertDigitAffixesAndPadding::needsPluralRules() const {
27c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    return (
28c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert            fPositivePrefix.hasMultipleVariants() ||
29c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert            fPositiveSuffix.hasMultipleVariants() ||
30c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert            fNegativePrefix.hasMultipleVariants() ||
31c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert            fNegativeSuffix.hasMultipleVariants());
32c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert}
33c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert
34c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik RoubertUnicodeString &
35c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik RoubertDigitAffixesAndPadding::formatInt32(
36c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        int32_t value,
37c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        const ValueFormatter &formatter,
38c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        FieldPositionHandler &handler,
39c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        const PluralRules *optPluralRules,
40c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        UnicodeString &appendTo,
41c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        UErrorCode &status) const {
42c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    if (U_FAILURE(status)) {
43c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        return appendTo;
44c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    }
45c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    if (optPluralRules != NULL || fWidth > 0 || !formatter.isFastFormattable(value)) {
46c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        VisibleDigitsWithExponent digits;
47c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        formatter.toVisibleDigitsWithExponent(
48c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert                (int64_t) value, digits, status);
49c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        return format(
50c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert                digits,
51c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert                formatter,
52c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert                handler,
53c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert                optPluralRules,
54c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert                appendTo,
55c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert                status);
56c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    }
57c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    UBool bPositive = value >= 0;
58c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    const DigitAffix *prefix = bPositive ? &fPositivePrefix.getOtherVariant() : &fNegativePrefix.getOtherVariant();
59c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    const DigitAffix *suffix = bPositive ? &fPositiveSuffix.getOtherVariant() : &fNegativeSuffix.getOtherVariant();
60c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    if (value < 0) {
61c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        value = -value;
62c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    }
63c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    prefix->format(handler, appendTo);
64c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    formatter.formatInt32(value, handler, appendTo);
65c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    return suffix->format(handler, appendTo);
66c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert}
67c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert
68c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubertstatic UnicodeString &
69c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik RoubertformatAffix(
70c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        const DigitAffix *affix,
71c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        FieldPositionHandler &handler,
72c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        UnicodeString &appendTo) {
73c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    if (affix) {
74c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        affix->format(handler, appendTo);
75c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    }
76c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    return appendTo;
77c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert}
78c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert
79c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubertstatic int32_t
80c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik RoubertcountAffixChar32(const DigitAffix *affix) {
81c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    if (affix) {
82c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        return affix->countChar32();
83c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    }
84c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    return 0;
85c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert}
86c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert
87c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik RoubertUnicodeString &
88c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik RoubertDigitAffixesAndPadding::format(
89c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        const VisibleDigitsWithExponent &digits,
90c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        const ValueFormatter &formatter,
91c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        FieldPositionHandler &handler,
92c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        const PluralRules *optPluralRules,
93c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        UnicodeString &appendTo,
94c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        UErrorCode &status) const {
95c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    if (U_FAILURE(status)) {
96c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        return appendTo;
97c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    }
98c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    const DigitAffix *prefix = NULL;
99c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    const DigitAffix *suffix = NULL;
100c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    if (!digits.isNaN()) {
101c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        UBool bPositive = !digits.isNegative();
102c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        const PluralAffix *pluralPrefix = bPositive ? &fPositivePrefix : &fNegativePrefix;
103c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        const PluralAffix *pluralSuffix = bPositive ? &fPositiveSuffix : &fNegativeSuffix;
104c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        if (optPluralRules == NULL || digits.isInfinite()) {
105c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert            prefix = &pluralPrefix->getOtherVariant();
106c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert            suffix = &pluralSuffix->getOtherVariant();
107c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        } else {
108c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert            UnicodeString count(optPluralRules->select(digits));
109c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert            prefix = &pluralPrefix->getByCategory(count);
110c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert            suffix = &pluralSuffix->getByCategory(count);
111c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        }
112c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    }
113c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    if (fWidth <= 0) {
114c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        formatAffix(prefix, handler, appendTo);
115c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        formatter.format(digits, handler, appendTo);
116c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        return formatAffix(suffix, handler, appendTo);
117c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    }
118c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    int32_t codePointCount = countAffixChar32(prefix) + formatter.countChar32(digits) + countAffixChar32(suffix);
119c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    int32_t paddingCount = fWidth - codePointCount;
120c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    switch (fPadPosition) {
121c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    case kPadBeforePrefix:
122c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        appendPadding(paddingCount, appendTo);
123c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        formatAffix(prefix, handler, appendTo);
124c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        formatter.format(digits, handler, appendTo);
125c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        return formatAffix(suffix, handler, appendTo);
126c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    case kPadAfterPrefix:
127c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        formatAffix(prefix, handler, appendTo);
128c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        appendPadding(paddingCount, appendTo);
129c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        formatter.format(digits, handler, appendTo);
130c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        return formatAffix(suffix, handler, appendTo);
131c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    case kPadBeforeSuffix:
132c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        formatAffix(prefix, handler, appendTo);
133c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        formatter.format(digits, handler, appendTo);
134c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        appendPadding(paddingCount, appendTo);
135c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        return formatAffix(suffix, handler, appendTo);
136c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    case kPadAfterSuffix:
137c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        formatAffix(prefix, handler, appendTo);
138c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        formatter.format(digits, handler, appendTo);
139c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        formatAffix(suffix, handler, appendTo);
140c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        return appendPadding(paddingCount, appendTo);
141c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    default:
142c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        U_ASSERT(FALSE);
143c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        return appendTo;
144c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    }
145c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert}
146c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert
147c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik RoubertUnicodeString &
148c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik RoubertDigitAffixesAndPadding::format(
149c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        DigitList &value,
150c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        const ValueFormatter &formatter,
151c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        FieldPositionHandler &handler,
152c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        const PluralRules *optPluralRules,
153c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        UnicodeString &appendTo,
154c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        UErrorCode &status) const {
155c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    VisibleDigitsWithExponent digits;
156c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    formatter.toVisibleDigitsWithExponent(
157c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert            value, digits, status);
158c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    if (U_FAILURE(status)) {
159c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        return appendTo;
160c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    }
161c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    return format(
162c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert            digits, formatter, handler, optPluralRules, appendTo, status);
163c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert}
164c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert
165c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik RoubertUnicodeString &
166c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik RoubertDigitAffixesAndPadding::appendPadding(int32_t paddingCount, UnicodeString &appendTo) const {
167c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    for (int32_t i = 0; i < paddingCount; ++i) {
168c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        appendTo.append(fPadChar);
169c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    }
170c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    return appendTo;
171c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert}
172c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert
173c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert
174c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik RoubertU_NAMESPACE_END
175c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert#endif /* #if !UCONFIG_NO_FORMATTING */
176