164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert// Copyright (C) 2016 and later: Unicode, Inc. and others.
264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html
3fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius/*
4fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius******************************************************************************
58de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubert* Copyright (C) 2014-2016, International Business Machines
6fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius* Corporation and others.  All Rights Reserved.
7fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius******************************************************************************
8fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius* quantityformatter.cpp
9fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius*/
108ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer
118ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer#include "unicode/utypes.h"
128ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer
138ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer#if !UCONFIG_NO_FORMATTING
148ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer
158de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubert#include "unicode/simpleformatter.h"
16fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "quantityformatter.h"
17fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "uassert.h"
18fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/unistr.h"
19fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/decimfmt.h"
20fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "cstring.h"
21fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/plurrule.h"
22fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "charstr.h"
23fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/fmtable.h"
24fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/fieldpos.h"
250b3ec0516c035ea443fdc334025048597c740be1Markus Scherer#include "standardplural.h"
26c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert#include "visibledigits.h"
278ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer#include "uassert.h"
28fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
29fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusU_NAMESPACE_BEGIN
30fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
31fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusQuantityFormatter::QuantityFormatter() {
32f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
33fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        formatters[i] = NULL;
34fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
35fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
36fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
37fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusQuantityFormatter::QuantityFormatter(const QuantityFormatter &other) {
38f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
39fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if (other.formatters[i] == NULL) {
40fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            formatters[i] = NULL;
41fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        } else {
428de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubert            formatters[i] = new SimpleFormatter(*other.formatters[i]);
43fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
44fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
45fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
46fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
47fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusQuantityFormatter &QuantityFormatter::operator=(
48fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const QuantityFormatter& other) {
49fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (this == &other) {
50fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return *this;
51fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
52f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
53fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        delete formatters[i];
54fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if (other.formatters[i] == NULL) {
55fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            formatters[i] = NULL;
56fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        } else {
578de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubert            formatters[i] = new SimpleFormatter(*other.formatters[i]);
58fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
59fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
60fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    return *this;
61fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
62fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
63fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusQuantityFormatter::~QuantityFormatter() {
64f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
65fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        delete formatters[i];
66fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
67fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
68fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
69fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusvoid QuantityFormatter::reset() {
70f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
71fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        delete formatters[i];
72fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        formatters[i] = NULL;
73fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
74fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
75fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
768ce198ebe2317b05a969826d0b629cb2d0b894a2Markus SchererUBool QuantityFormatter::addIfAbsent(
77fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const char *variant,
787d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer        const UnicodeString &rawPattern,
79fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UErrorCode &status) {
800b3ec0516c035ea443fdc334025048597c740be1Markus Scherer    int32_t pluralIndex = StandardPlural::indexFromString(variant, status);
81fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
82fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return FALSE;
83fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
848ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer    if (formatters[pluralIndex] != NULL) {
858ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer        return TRUE;
868ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer    }
878de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubert    SimpleFormatter *newFmt = new SimpleFormatter(rawPattern, 0, 1, status);
88fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (newFmt == NULL) {
89fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        status = U_MEMORY_ALLOCATION_ERROR;
90fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return FALSE;
91fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
927d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer    if (U_FAILURE(status)) {
93fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        delete newFmt;
94fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return FALSE;
95fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
96fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    formatters[pluralIndex] = newFmt;
97fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    return TRUE;
98fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
99fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
100fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusUBool QuantityFormatter::isValid() const {
1010b3ec0516c035ea443fdc334025048597c740be1Markus Scherer    return formatters[StandardPlural::OTHER] != NULL;
102fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
103fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
1048de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubertconst SimpleFormatter *QuantityFormatter::getByVariant(
105f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        const char *variant) const {
1068ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer    U_ASSERT(isValid());
1070b3ec0516c035ea443fdc334025048597c740be1Markus Scherer    int32_t pluralIndex = StandardPlural::indexOrOtherIndexFromString(variant);
1088de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubert    const SimpleFormatter *pattern = formatters[pluralIndex];
109f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    if (pattern == NULL) {
1100b3ec0516c035ea443fdc334025048597c740be1Markus Scherer        pattern = formatters[StandardPlural::OTHER];
111f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    }
112f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    return pattern;
113f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius}
114f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius
115fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusUnicodeString &QuantityFormatter::format(
1167d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer            const Formattable &number,
117fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            const NumberFormat &fmt,
118fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            const PluralRules &rules,
119fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            UnicodeString &appendTo,
120fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            FieldPosition &pos,
121fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            UErrorCode &status) const {
1227d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer    UnicodeString formattedNumber;
1237d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer    StandardPlural::Form p = selectPlural(number, fmt, rules, formattedNumber, pos, status);
124fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
125fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return appendTo;
126fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
1278de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubert    const SimpleFormatter *pattern = formatters[p];
1287d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer    if (pattern == NULL) {
1297d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer        pattern = formatters[StandardPlural::OTHER];
1307d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer        if (pattern == NULL) {
1317d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer            status = U_INVALID_STATE_ERROR;
1327d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer            return appendTo;
1337d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer        }
1347d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer    }
1357d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer    return format(*pattern, formattedNumber, appendTo, pos, status);
1367d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer}
1377d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer
1387d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer// The following methods live here so that class PluralRules does not depend on number formatting,
1398de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubert// and the SimpleFormatter does not depend on FieldPosition.
1407d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer
1417d219b1ec89c9f70eedb20b1190fc678a1011519Markus SchererStandardPlural::Form QuantityFormatter::selectPlural(
1427d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer            const Formattable &number,
1437d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer            const NumberFormat &fmt,
1447d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer            const PluralRules &rules,
1457d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer            UnicodeString &formattedNumber,
1467d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer            FieldPosition &pos,
1477d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer            UErrorCode &status) {
1487d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer    if (U_FAILURE(status)) {
1497d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer        return StandardPlural::OTHER;
1507d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer    }
1517d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer    UnicodeString pluralKeyword;
152c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    VisibleDigitsWithExponent digits;
153fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    const DecimalFormat *decFmt = dynamic_cast<const DecimalFormat *>(&fmt);
154fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (decFmt != NULL) {
1557d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer        decFmt->initVisibleDigitsWithExponent(number, digits, status);
156fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if (U_FAILURE(status)) {
1577d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer            return StandardPlural::OTHER;
158fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
1597d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer        pluralKeyword = rules.select(digits);
1607d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer        decFmt->format(digits, formattedNumber, pos, status);
161fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    } else {
1627d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer        if (number.getType() == Formattable::kDouble) {
1637d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer            pluralKeyword = rules.select(number.getDouble());
1647d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer        } else if (number.getType() == Formattable::kLong) {
1657d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer            pluralKeyword = rules.select(number.getLong());
1667d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer        } else if (number.getType() == Formattable::kInt64) {
1677d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer            pluralKeyword = rules.select((double) number.getInt64());
168fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        } else {
169fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status = U_ILLEGAL_ARGUMENT_ERROR;
1707d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer            return StandardPlural::OTHER;
171fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
1727d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer        fmt.format(number, formattedNumber, pos, status);
173fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
1747d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer    return StandardPlural::orOtherFromString(pluralKeyword);
1757d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer}
1767d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer
1777d219b1ec89c9f70eedb20b1190fc678a1011519Markus SchererUnicodeString &QuantityFormatter::format(
1788de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubert            const SimpleFormatter &pattern,
1797d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer            const UnicodeString &value,
1807d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer            UnicodeString &appendTo,
1817d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer            FieldPosition &pos,
1827d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer            UErrorCode &status) {
183fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
184fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return appendTo;
185fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
1867d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer    const UnicodeString *param = &value;
1877d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer    int32_t offset;
1887d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer    pattern.formatAndAppend(&param, 1, appendTo, &offset, 1, status);
1897d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer    if (pos.getBeginIndex() != 0 || pos.getEndIndex() != 0) {
1907d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer        if (offset >= 0) {
1917d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer            pos.setBeginIndex(pos.getBeginIndex() + offset);
1927d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer            pos.setEndIndex(pos.getEndIndex() + offset);
1937d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer        } else {
1947d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer            pos.setBeginIndex(0);
1957d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer            pos.setEndIndex(0);
196fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
197fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
198fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    return appendTo;
199fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
200fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
201fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusU_NAMESPACE_END
202fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
203fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#endif /* #if !UCONFIG_NO_FORMATTING */
204