15d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath/*
25d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath *******************************************************************************
38d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath * Copyright (C) 2007-2014, International Business Machines Corporation and
45d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * others. All Rights Reserved.
55d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath *******************************************************************************
65d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath */
75d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
88d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamathpackage com.ibm.icu.simple;
95d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
105d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamathimport java.io.IOException;
115d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamathimport java.io.NotSerializableException;
125d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamathimport java.io.ObjectInputStream;
135d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamathimport java.io.ObjectOutputStream;
145d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamathimport java.io.Serializable;
155d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamathimport java.text.ParseException;
165d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamathimport java.util.ArrayList;
175d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamathimport java.util.Collection;
185d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamathimport java.util.Collections;
195d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamathimport java.util.HashSet;
205d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamathimport java.util.Iterator;
215d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamathimport java.util.LinkedHashSet;
225d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamathimport java.util.List;
235d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamathimport java.util.Locale;
245d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamathimport java.util.Set;
255d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamathimport java.util.TreeSet;
265d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamathimport java.util.regex.Pattern;
275d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
285d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamathimport com.ibm.icu.util.Output;
295d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
305d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath/**
315d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <p>
325d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * Defines rules for mapping non-negative numeric values onto a small set of keywords.
335d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * </p>
345d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <p>
355d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * Rules are constructed from a text description, consisting of a series of keywords and conditions. The {@link #select}
365d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * method examines each condition in order and returns the keyword for the first condition that matches the number. If
375d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * none match, {@link #KEYWORD_OTHER} is returned.
385d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * </p>
395d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <p>
405d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * A PluralRules object is immutable. It contains caches for sample values, but those are synchronized.
415d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <p>
425d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * PluralRules is Serializable so that it can be used in formatters, which are serializable.
435d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * </p>
445d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <p>
455d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * For more information, details, and tips for writing rules, see the <a
465d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * href="http://www.unicode.org/draft/reports/tr35/tr35.html#Language_Plural_Rules">LDML spec, C.11 Language Plural
475d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * Rules</a>
485d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * </p>
495d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <p>
505d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * Examples:
515d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * </p>
525d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath *
535d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <pre>
545d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * &quot;one: n is 1; few: n in 2..4&quot;
555d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * </pre>
565d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <p>
575d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * This defines two rules, for 'one' and 'few'. The condition for 'one' is "n is 1" which means that the number must be
585d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * equal to 1 for this condition to pass. The condition for 'few' is "n in 2..4" which means that the number must be
595d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * between 2 and 4 inclusive - and be an integer - for this condition to pass. All other numbers are assigned the
605d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * keyword "other" by the default rule.
615d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * </p>
625d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath *
635d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <pre>
645d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * &quot;zero: n is 0; one: n is 1; zero: n mod 100 in 1..19&quot;
655d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * </pre>
665d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <p>
675d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * This illustrates that the same keyword can be defined multiple times. Each rule is examined in order, and the first
685d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * keyword whose condition passes is the one returned. Also notes that a modulus is applied to n in the last rule. Thus
695d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * its condition holds for 119, 219, 319...
705d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * </p>
715d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath *
725d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <pre>
735d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * &quot;one: n is 1; few: n mod 10 in 2..4 and n mod 100 not in 12..14&quot;
745d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * </pre>
755d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <p>
765d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * This illustrates conjunction and negation. The condition for 'few' has two parts, both of which must be met:
775d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * "n mod 10 in 2..4" and "n mod 100 not in 12..14". The first part applies a modulus to n before the test as in the
785d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * previous example. The second part applies a different modulus and also uses negation, thus it matches all numbers
795d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * _not_ in 12, 13, 14, 112, 113, 114, 212, 213, 214...
805d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * </p>
815d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <p>
825d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * Syntax:
835d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * </p>
845d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <pre>
855d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * rules         = rule (';' rule)*
865d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * rule          = keyword ':' condition
875d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * keyword       = &lt;identifier&gt;
885d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * condition     = and_condition ('or' and_condition)*
895d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * and_condition = relation ('and' relation)*
905d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * relation      = not? expr not? rel not? range_list
915d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * expr          = ('n' | 'i' | 'f' | 'v' | 't') (mod value)?
925d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * not           = 'not' | '!'
935d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * rel           = 'in' | 'is' | '=' | '≠' | 'within'
945d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * mod           = 'mod' | '%'
955d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * range_list    = (range | value) (',' range_list)*
965d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * value         = digit+
975d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * digit         = 0|1|2|3|4|5|6|7|8|9
985d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * range         = value'..'value
995d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * </pre>
1005d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <p>Each <b>not</b> term inverts the meaning; however, there should not be more than one of them.</p>
1015d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <p>
1025d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * The i, f, t, and v values are defined as follows:
1035d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * </p>
1045d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <ul>
1055d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <li>i to be the integer digits.</li>
1065d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <li>f to be the visible decimal digits, as an integer.</li>
1075d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <li>t to be the visible decimal digits—without trailing zeros—as an integer.</li>
1085d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <li>v to be the number of visible fraction digits.</li>
1095d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <li>j is defined to only match integers. That is j is 3 fails if v != 0 (eg for 3.1 or 3.0).</li>
1105d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * </ul>
1115d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <p>
1125d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * Examples are in the following table:
1135d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * </p>
1145d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <table border='1' style="border-collapse:collapse">
1155d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <tbody>
1165d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <tr>
1175d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <th>n</th>
1185d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <th>i</th>
1195d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <th>f</th>
1205d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <th>v</th>
1215d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * </tr>
1225d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <tr>
1235d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <td>1.0</td>
1245d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <td>1</td>
1255d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <td align="right">0</td>
1265d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <td>1</td>
1275d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * </tr>
1285d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <tr>
1295d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <td>1.00</td>
1305d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <td>1</td>
1315d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <td align="right">0</td>
1325d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <td>2</td>
1335d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * </tr>
1345d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <tr>
1355d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <td>1.3</td>
1365d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <td>1</td>
1375d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <td align="right">3</td>
1385d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <td>1</td>
1395d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * </tr>
1405d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <tr>
1415d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <td>1.03</td>
1425d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <td>1</td>
1435d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <td align="right">3</td>
1445d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <td>2</td>
1455d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * </tr>
1465d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <tr>
1475d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <td>1.23</td>
1485d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <td>1</td>
1495d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <td align="right">23</td>
1505d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <td>2</td>
1515d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * </tr>
1525d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * </tbody>
1535d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * </table>
1545d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <p>
1555d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * An "identifier" is a sequence of characters that do not have the Unicode Pattern_Syntax or Pattern_White_Space
1565d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * properties.
1575d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * <p>
1585d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * The difference between 'in' and 'within' is that 'in' only includes integers in the specified range, while 'within'
1595d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * includes all values. Using 'within' with a range_list consisting entirely of values is the same as using 'in' (it's
1605d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * not an error).
1615d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * </p>
1625d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath *
1635d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath * @stable ICU 3.8
1645d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath */
1655d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamathpublic class PluralRules implements Serializable {
1665d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
1678d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    // static final UnicodeSet ALLOWED_ID = new UnicodeSet("[a-z]").freeze();
1685d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
1695d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    // TODO Remove RulesList by moving its API and fields into PluralRules.
1705d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
1715d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @internal
1725d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @deprecated This API is ICU internal only.
1735d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
1748d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    @Deprecated
1755d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public static final String CATEGORY_SEPARATOR = ";  ";
1765d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
1775d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @internal
1785d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @deprecated This API is ICU internal only.
1795d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
1808d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    @Deprecated
1815d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public static final String KEYWORD_RULE_SEPARATOR = ": ";
1825d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
1835d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    private static final long serialVersionUID = 1;
1845d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
1855d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    private final RuleList rules;
1865d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    private final transient Set<String> keywords;
1875d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
1885d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
1895d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Provides a factory for returning plural rules
1905d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *
1915d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @internal
1928d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath     * @deprecated This API is ICU internal only.
1935d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
1948d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    @Deprecated
1955d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public static abstract class Factory {
1965d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
1975d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * Provides access to the predefined <code>PluralRules</code> for a given locale and the plural type.
1985d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         *
1995d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * <p>
2005d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * ICU defines plural rules for many locales based on CLDR <i>Language Plural Rules</i>. For these predefined
2015d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * rules, see CLDR page at http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
2025d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         *
2035d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @param locale
2045d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         *            The locale for which a <code>PluralRules</code> object is returned.
2055d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @param type
2065d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         *            The plural type (e.g., cardinal or ordinal).
2075d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @return The predefined <code>PluralRules</code> object for this locale. If there's no predefined rules for
2085d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         *         this locale, the rules for the closest parent in the locale hierarchy that has one will be returned.
2095d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         *         The final fallback always returns the default rules.
2105d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
2118d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         * @deprecated This API is ICU internal only.
2125d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
2138d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
2148d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        public abstract PluralRules forLocale(Locale locale, PluralType type);
2155d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
2165d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
2175d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * Utility for getting CARDINAL rules.
2185d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @param locale the locale
2195d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @return plural rules.
2205d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
2218d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         * @deprecated This API is ICU internal only.
2225d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
2238d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
2248d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        public final PluralRules forLocale(Locale locale) {
2255d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return forLocale(locale, PluralType.CARDINAL);
2265d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
2275d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
2285d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
2295d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * Returns the locales for which there is plurals data.
2305d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         *
2315d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
2328d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         * @deprecated This API is ICU internal only.
2338d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
2345d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public abstract ULocale[] getAvailableULocales();
2358d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         */
2365d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
2375d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
2385d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * Returns the 'functionally equivalent' locale with respect to plural rules. Calling PluralRules.forLocale with
2395d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * the functionally equivalent locale, and with the provided locale, returns rules that behave the same. <br/>
2405d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * All locales with the same functionally equivalent locale have plural rules that behave the same. This is not
2415d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * exaustive; there may be other locales whose plural rules behave the same that do not have the same equivalent
2425d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * locale.
2435d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         *
2445d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @param locale
2455d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         *            the locale to check
2465d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @param isAvailable
2475d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         *            if not null and of length > 0, this will hold 'true' at index 0 if locale is directly defined
2485d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         *            (without fallback) as having plural rules
2495d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @return the functionally-equivalent locale
2505d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
2518d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         * @deprecated This API is ICU internal only.
2528d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
2535d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public abstract ULocale getFunctionalEquivalent(ULocale locale, boolean[] isAvailable);
2548d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         */
2555d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
2565d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
2575d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * Returns the default factory.
2585d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
2598d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         * @deprecated This API is ICU internal only.
2605d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
2618d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
2625d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public static PluralRulesLoader getDefaultFactory() {
2635d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return PluralRulesLoader.loader;
2645d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
2655d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
2665d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
2675d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * Returns whether or not there are overrides.
2685d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
2698d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         * @deprecated This API is ICU internal only.
2708d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
2715d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public abstract boolean hasOverride(ULocale locale);
2728d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         */
2735d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
2745d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    // Standard keywords.
2755d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
2765d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
2775d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Common name for the 'zero' plural form.
2785d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @stable ICU 3.8
2795d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
2805d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public static final String KEYWORD_ZERO = "zero";
2815d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
2825d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
2835d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Common name for the 'singular' plural form.
2845d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @stable ICU 3.8
2855d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
2865d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public static final String KEYWORD_ONE = "one";
2875d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
2885d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
2895d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Common name for the 'dual' plural form.
2905d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @stable ICU 3.8
2915d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
2925d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public static final String KEYWORD_TWO = "two";
2935d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
2945d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
2955d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Common name for the 'paucal' or other special plural form.
2965d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @stable ICU 3.8
2975d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
2985d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public static final String KEYWORD_FEW = "few";
2995d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
3005d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
3015d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Common name for the arabic (11 to 99) plural form.
3025d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @stable ICU 3.8
3035d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
3045d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public static final String KEYWORD_MANY = "many";
3055d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
3065d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
3075d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Common name for the default plural form.  This name is returned
3085d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * for values to which no other form in the rule applies.  It
3095d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * can additionally be assigned rules of its own.
3105d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @stable ICU 3.8
3115d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
3125d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public static final String KEYWORD_OTHER = "other";
3135d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
3145d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
3155d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Value returned by {@link #getUniqueKeywordValue} when there is no
3165d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * unique value to return.
3175d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @stable ICU 4.8
3185d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
3195d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public static final double NO_UNIQUE_VALUE = -0.00123456777;
3205d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
3215d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
3225d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Type of plurals and PluralRules.
3235d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @stable ICU 50
3245d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
3255d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public enum PluralType {
3265d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
3275d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * Plural rules for cardinal numbers: 1 file vs. 2 files.
3285d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @stable ICU 50
3295d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
3305d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        CARDINAL,
3315d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
3325d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * Plural rules for ordinal numbers: 1st file, 2nd file, 3rd file, 4th file, etc.
3335d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @stable ICU 50
3345d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
3355d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        ORDINAL
3365d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    };
3375d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
3385d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /*
3395d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * The default constraint that is always satisfied.
3405d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
3415d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    private static final Constraint NO_CONSTRAINT = new Constraint() {
3425d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        private static final long serialVersionUID = 9163464945387899416L;
3435d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
3445d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public boolean isFulfilled(FixedDecimal n) {
3455d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return true;
3465d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
3475d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
3485d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public boolean isLimited(SampleType sampleType) {
3495d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return false;
3505d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
3515d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
3525d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public String toString() {
3535d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return "";
3545d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
3555d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    };
3565d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
3575d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
3585d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *
3595d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
3605d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    private static final Rule DEFAULT_RULE = new Rule("other", NO_CONSTRAINT, null, null);
3615d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
3625d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
3635d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Parses a plural rules description and returns a PluralRules.
3645d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @param description the rule description.
3655d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @throws ParseException if the description cannot be parsed.
3665d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *    The exception index is typically not set, it will be -1.
3675d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @stable ICU 3.8
3685d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
3695d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public static PluralRules parseDescription(String description)
3705d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            throws ParseException {
3715d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
3725d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        description = description.trim();
3735d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return description.length() == 0 ? DEFAULT : new PluralRules(parseRuleChain(description));
3745d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
3755d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
3765d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
3775d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Creates a PluralRules from a description if it is parsable,
3785d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * otherwise returns null.
3795d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @param description the rule description.
3805d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @return the PluralRules
3815d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @stable ICU 3.8
3825d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
3835d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public static PluralRules createRules(String description) {
3845d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        try {
3855d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return parseDescription(description);
3865d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        } catch(Exception e) {
3875d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return null;
3885d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
3895d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
3905d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
3915d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
3925d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * The default rules that accept any number and return
3935d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * {@link #KEYWORD_OTHER}.
3945d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @stable ICU 3.8
3955d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
3965d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public static final PluralRules DEFAULT = new PluralRules(new RuleList().addRule(DEFAULT_RULE));
3975d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
3985d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    private enum Operand {
3995d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        n,
4005d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        i,
4015d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        f,
4025d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        t,
4035d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        v,
4045d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        w,
4058d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        /* deprecated */
4065d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        j;
4075d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
4085d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
4095d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
4105d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @internal
4115d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @deprecated This API is ICU internal only.
4125d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
4138d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    @Deprecated
4145d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public static class FixedDecimal extends Number implements Comparable<FixedDecimal> {
4155d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        private static final long serialVersionUID = -4756200506571685661L;
4165d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
4175d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
4185d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
4195d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
4208d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
4215d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public final double source;
4225d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
4235d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
4245d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
4255d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
4268d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
4275d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public final int visibleDecimalDigitCount;
4285d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
4295d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
4305d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
4315d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
4328d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
4335d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public final int visibleDecimalDigitCountWithoutTrailingZeros;
4345d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
4355d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
4365d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
4375d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
4388d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
4395d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public final long decimalDigits;
4405d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
4415d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
4425d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
4435d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
4448d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
4455d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public final long decimalDigitsWithoutTrailingZeros;
4465d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
4475d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
4485d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
4495d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
4508d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
4515d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public final long integerValue;
4525d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
4535d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
4545d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
4555d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
4568d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
4575d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public final boolean hasIntegerValue;
4585d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
4595d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
4605d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
4615d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
4628d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
4635d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public final boolean isNegative;
4645d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        private final int baseFactor;
4655d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
4665d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
4675d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
4685d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
4695d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
4708d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
4715d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public double getSource() {
4725d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return source;
4735d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
4745d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
4755d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
4765d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
4775d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
4785d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
4798d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
4805d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public int getVisibleDecimalDigitCount() {
4815d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return visibleDecimalDigitCount;
4825d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
4835d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
4845d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
4855d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
4865d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
4875d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
4888d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
4895d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public int getVisibleDecimalDigitCountWithoutTrailingZeros() {
4905d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return visibleDecimalDigitCountWithoutTrailingZeros;
4915d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
4925d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
4935d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
4945d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
4955d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
4965d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
4978d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
4985d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public long getDecimalDigits() {
4995d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return decimalDigits;
5005d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
5015d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
5025d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
5035d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
5045d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
5055d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
5068d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
5075d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public long getDecimalDigitsWithoutTrailingZeros() {
5085d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return decimalDigitsWithoutTrailingZeros;
5095d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
5105d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
5115d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
5125d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
5135d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
5145d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
5158d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
5165d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public long getIntegerValue() {
5175d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return integerValue;
5185d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
5195d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
5205d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
5215d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
5225d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
5235d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
5248d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
5255d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public boolean isHasIntegerValue() {
5265d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return hasIntegerValue;
5275d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
5285d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
5295d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
5305d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
5315d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
5325d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
5338d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
5345d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public boolean isNegative() {
5355d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return isNegative;
5365d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
5375d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
5385d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
5395d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
5405d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
5415d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
5428d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
5435d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public int getBaseFactor() {
5445d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return baseFactor;
5455d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
5465d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
5478d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        static final long MAX = (long)1E18;
5488d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath
5495d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
5505d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
5515d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
5525d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @param n is the original number
5535d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @param v number of digits to the right of the decimal place. e.g 1.00 = 2 25. = 0
5545d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @param f Corresponds to f in the plural rules grammar.
5555d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         *   The digits to the right of the decimal place as an integer. e.g 1.10 = 10
5565d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
5578d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
5585d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public FixedDecimal(double n, int v, long f) {
5595d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            isNegative = n < 0;
5605d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            source = isNegative ? -n : n;
5615d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            visibleDecimalDigitCount = v;
5625d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            decimalDigits = f;
5638d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath            integerValue = n > MAX
5648d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                    ? MAX
5658d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                            : (long)n;
5665d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            hasIntegerValue = source == integerValue;
5675d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            // check values. TODO make into unit test.
5685d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            //
5695d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            //            long visiblePower = (int) Math.pow(10, v);
5705d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            //            if (fractionalDigits > visiblePower) {
5715d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            //                throw new IllegalArgumentException();
5725d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            //            }
5735d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            //            double fraction = intValue + (fractionalDigits / (double) visiblePower);
5745d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            //            if (fraction != source) {
5755d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            //                double diff = Math.abs(fraction - source)/(Math.abs(fraction) + Math.abs(source));
5765d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            //                if (diff > 0.00000001d) {
5775d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            //                    throw new IllegalArgumentException();
5785d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            //                }
5795d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            //            }
5805d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            if (f == 0) {
5815d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                decimalDigitsWithoutTrailingZeros = 0;
5825d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                visibleDecimalDigitCountWithoutTrailingZeros = 0;
5835d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            } else {
5845d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                long fdwtz = f;
5855d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                int trimmedCount = v;
5865d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                while ((fdwtz%10) == 0) {
5875d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    fdwtz /= 10;
5885d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    --trimmedCount;
5895d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                }
5905d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                decimalDigitsWithoutTrailingZeros = fdwtz;
5915d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                visibleDecimalDigitCountWithoutTrailingZeros = trimmedCount;
5925d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
5935d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            baseFactor = (int) Math.pow(10, v);
5945d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
5955d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
5965d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
5975d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
5985d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
5995d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
6008d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
6015d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public FixedDecimal(double n, int v) {
6025d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            this(n,v,getFractionalDigits(n, v));
6035d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
6045d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
6055d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        private static int getFractionalDigits(double n, int v) {
6065d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            if (v == 0) {
6075d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                return 0;
6085d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            } else {
6098d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                if (n < 0) {
6108d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                    n = -n;
6118d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                }
6125d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                int baseFactor = (int) Math.pow(10, v);
6135d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                long scaled = Math.round(n * baseFactor);
6145d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                return (int) (scaled % baseFactor);
6155d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
6165d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
6175d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
6185d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
6195d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
6205d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
6215d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
6228d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
6235d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public FixedDecimal(double n) {
6245d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            this(n, decimals(n));
6255d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
6265d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
6275d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
6285d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
6295d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
6305d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
6318d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
6325d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public FixedDecimal(long n) {
6335d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            this(n,0);
6345d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
6355d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
6368d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        private static final long MAX_INTEGER_PART = 1000000000;
6375d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
6388d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         * Return a guess as to the number of decimals that would be displayed. This is only a guess; callers should
6398d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         * always supply the decimals explicitly if possible. Currently, it is up to 6 decimals (without trailing zeros).
6408d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         * Returns 0 for infinities and nans.
6415d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
6425d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
6438d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         *
6445d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
6458d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
6465d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public static int decimals(double n) {
6475d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            // Ugly...
6488d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath            if (Double.isInfinite(n) || Double.isNaN(n)) {
6498d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                return 0;
6508d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath            }
6518d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath            if (n < 0) {
6528d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                n = -n;
6538d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath            }
6548d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath            if (n < MAX_INTEGER_PART) {
6558d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                long temp = (long)(n * 1000000) % 1000000; // get 6 decimals
6568d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                for (int mask = 10, digits = 6; digits > 0; mask *= 10, --digits) {
6578d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                    if ((temp % mask) != 0) {
6588d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                        return digits;
6598d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                    }
6608d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                }
6618d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                return 0;
6628d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath            } else {
6638d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                String buf = String.format(Locale.ENGLISH, "%1.15e", n);
6648d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                int ePos = buf.lastIndexOf('e');
6658d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                int expNumPos = ePos + 1;
6668d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                if (buf.charAt(expNumPos) == '+') {
6678d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                    expNumPos++;
6688d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                }
6698d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                String exponentStr = buf.substring(expNumPos);
6708d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                int exponent = Integer.parseInt(exponentStr);
6718d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                int numFractionDigits = ePos - 2 - exponent;
6728d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                if (numFractionDigits < 0) {
6738d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                    return 0;
6748d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                }
6758d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                for (int i=ePos-1; numFractionDigits > 0; --i) {
6768d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                    if (buf.charAt(i) != '0') {
6778d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                        break;
6788d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                    }
6798d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                    --numFractionDigits;
6808d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                }
6818d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                return numFractionDigits;
6828d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath            }
6835d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
6845d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
6855d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
6865d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
6875d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
6885d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
6898d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
6905d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public FixedDecimal (String n) {
6915d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            // Ugly, but for samples we don't care.
6925d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            this(Double.parseDouble(n), getVisibleFractionCount(n));
6935d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
6945d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
6955d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        private static int getVisibleFractionCount(String value) {
6965d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            value = value.trim();
6975d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            int decimalPos = value.indexOf('.') + 1;
6985d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            if (decimalPos == 0) {
6995d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                return 0;
7005d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            } else {
7015d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                return value.length() - decimalPos;
7025d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
7035d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
7045d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
7055d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
7065d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
7075d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
7085d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
7098d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
7105d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public double get(Operand operand) {
7115d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            switch(operand) {
7125d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            default: return source;
7135d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            case i: return integerValue;
7145d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            case f: return decimalDigits;
7155d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            case t: return decimalDigitsWithoutTrailingZeros;
7165d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            case v: return visibleDecimalDigitCount;
7175d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            case w: return visibleDecimalDigitCountWithoutTrailingZeros;
7185d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
7195d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
7205d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
7215d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
7225d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
7235d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
7245d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
7258d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
7265d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public static Operand getOperand(String t) {
7275d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return Operand.valueOf(t);
7285d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
7295d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
7305d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
7315d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * We're not going to care about NaN.
7325d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
7335d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
7345d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
7358d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
7365d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public int compareTo(FixedDecimal other) {
7375d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            if (integerValue != other.integerValue) {
7385d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                return integerValue < other.integerValue ? -1 : 1;
7395d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
7405d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            if (source != other.source) {
7415d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                return source < other.source ? -1 : 1;
7425d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
7435d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            if (visibleDecimalDigitCount != other.visibleDecimalDigitCount) {
7445d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                return visibleDecimalDigitCount < other.visibleDecimalDigitCount ? -1 : 1;
7455d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
7465d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            long diff = decimalDigits - other.decimalDigits;
7475d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            if (diff != 0) {
7485d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                return diff < 0 ? -1 : 1;
7495d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
7505d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return 0;
7515d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
7525d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
7535d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
7545d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
7555d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
7565d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
7578d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
7585d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        @Override
7595d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public boolean equals(Object arg0) {
7605d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            if (arg0 == null) {
7615d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                return false;
7625d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
7635d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            if (arg0 == this) {
7645d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                return true;
7655d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
7665d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            if (!(arg0 instanceof FixedDecimal)) {
7675d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                return false;
7685d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
7695d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            FixedDecimal other = (FixedDecimal)arg0;
7705d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return source == other.source && visibleDecimalDigitCount == other.visibleDecimalDigitCount && decimalDigits == other.decimalDigits;
7715d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
7725d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
7735d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
7745d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
7755d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
7765d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
7778d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
7785d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        @Override
7795d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public int hashCode() {
7805d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            // TODO Auto-generated method stub
7815d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return (int)(decimalDigits + 37 * (visibleDecimalDigitCount + (int)(37 * source)));
7825d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
7835d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
7845d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
7855d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
7865d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
7875d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
7888d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
7895d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        @Override
7905d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public String toString() {
7915d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return String.format("%." + visibleDecimalDigitCount + "f", source);
7925d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
7935d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
7945d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
7955d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
7965d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
7975d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
7988d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
7995d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public boolean hasIntegerValue() {
8005d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return hasIntegerValue;
8015d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
8025d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
8035d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
8045d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
8055d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
8065d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
8078d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
8085d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        @Override
8095d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public int intValue() {
8105d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            // TODO Auto-generated method stub
8115d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return (int)integerValue;
8125d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
8135d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
8145d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
8155d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
8165d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
8175d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
8188d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
8195d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        @Override
8205d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public long longValue() {
8215d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return integerValue;
8225d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
8235d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
8245d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
8255d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
8265d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
8275d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
8288d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
8295d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        @Override
8305d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public float floatValue() {
8315d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return (float) source;
8325d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
8335d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
8345d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
8355d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
8365d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
8375d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
8388d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
8395d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        @Override
8405d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public double doubleValue() {
8418d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath            return isNegative ? -source : source;
8425d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
8435d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
8445d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
8455d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
8465d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
8475d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
8488d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
8495d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public long getShiftedValue() {
8505d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return integerValue * baseFactor + decimalDigits;
8515d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
8525d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
8535d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        private void writeObject(
8545d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                ObjectOutputStream out)
8555d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        throws IOException {
8565d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            throw new NotSerializableException();
8575d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
8585d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
8595d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        private void readObject(ObjectInputStream in
8605d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                ) throws IOException, ClassNotFoundException {
8615d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            throw new NotSerializableException();
8625d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
8635d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
8645d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
8655d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
8665d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Selection parameter for either integer-only or decimal-only.
8675d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @internal
8685d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @deprecated This API is ICU internal only.
8695d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
8708d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    @Deprecated
8718d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    public enum SampleType {
8728d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        /**
8738d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         * @internal
8748d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         * @deprecated This API is ICU internal only.
8758d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         */
8768d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
8778d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        INTEGER,
8788d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        /**
8798d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         * @internal
8808d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         * @deprecated This API is ICU internal only.
8818d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         */
8828d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
8838d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        DECIMAL
8848d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    }
8855d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
8865d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
8875d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * A range of NumberInfo that includes all values with the same visibleFractionDigitCount.
8885d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @internal
8895d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @deprecated This API is ICU internal only.
8905d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
8918d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    @Deprecated
8925d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public static class FixedDecimalRange {
8935d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
8945d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
8955d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
8965d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
8978d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
8985d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public final FixedDecimal start;
8995d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
9005d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
9015d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
9025d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
9038d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
9045d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public final FixedDecimal end;
9055d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
9065d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
9075d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
9085d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
9098d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
9105d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public FixedDecimalRange(FixedDecimal start, FixedDecimal end) {
9115d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            if (start.visibleDecimalDigitCount != end.visibleDecimalDigitCount) {
9125d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                throw new IllegalArgumentException("Ranges must have the same number of visible decimals: " + start + "~" + end);
9135d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
9145d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            this.start = start;
9155d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            this.end = end;
9165d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
9175d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
9185d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
9195d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
9205d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
9218d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
9225d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        @Override
9235d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public String toString() {
9245d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return start + (end == start ? "" : "~" + end);
9255d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
9265d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
9275d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
9285d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
9295d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * A list of NumberInfo that includes all values with the same visibleFractionDigitCount.
9305d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @internal
9315d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @deprecated This API is ICU internal only.
9325d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
9338d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    @Deprecated
9345d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public static class FixedDecimalSamples {
9355d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
9365d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
9375d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
9385d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
9398d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
9405d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public final SampleType sampleType;
9415d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
9425d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
9435d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
9445d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
9458d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
9465d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public final Set<FixedDecimalRange> samples;
9475d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
9485d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
9495d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
9505d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
9518d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
9525d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public final boolean bounded;
9535d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
9545d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * The samples must be immutable.
9555d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @param sampleType
9565d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @param samples
9575d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
9585d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        private FixedDecimalSamples(SampleType sampleType, Set<FixedDecimalRange> samples, boolean bounded) {
9595d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            super();
9605d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            this.sampleType = sampleType;
9615d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            this.samples = samples;
9625d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            this.bounded = bounded;
9635d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
9645d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /*
9655d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * Parse a list of the form described in CLDR. The source must be trimmed.
9665d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
9675d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        static FixedDecimalSamples parse(String source) {
9685d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            SampleType sampleType2;
9695d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            boolean bounded2 = true;
9705d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            boolean haveBound = false;
9715d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            Set<FixedDecimalRange> samples2 = new LinkedHashSet<FixedDecimalRange>();
9725d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
9735d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            if (source.startsWith("integer")) {
9745d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                sampleType2 = SampleType.INTEGER;
9755d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            } else if (source.startsWith("decimal")) {
9765d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                sampleType2 = SampleType.DECIMAL;
9775d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            } else {
9785d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                throw new IllegalArgumentException("Samples must start with 'integer' or 'decimal'");
9795d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
9805d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            source = source.substring(7).trim(); // remove both
9815d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
9825d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            for (String range : COMMA_SEPARATED.split(source)) {
9835d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                if (range.equals("…") || range.equals("...")) {
9845d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    bounded2 = false;
9855d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    haveBound = true;
9865d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    continue;
9875d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                }
9885d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                if (haveBound) {
9895d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    throw new IllegalArgumentException("Can only have … at the end of samples: " + range);
9905d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                }
9915d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                String[] rangeParts = TILDE_SEPARATED.split(range);
9925d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                switch (rangeParts.length) {
9935d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                case 1:
9945d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    FixedDecimal sample = new FixedDecimal(rangeParts[0]);
9955d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    checkDecimal(sampleType2, sample);
9965d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    samples2.add(new FixedDecimalRange(sample, sample));
9975d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    break;
9985d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                case 2:
9995d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    FixedDecimal start = new FixedDecimal(rangeParts[0]);
10005d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    FixedDecimal end = new FixedDecimal(rangeParts[1]);
10015d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    checkDecimal(sampleType2, start);
10025d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    checkDecimal(sampleType2, end);
10035d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    samples2.add(new FixedDecimalRange(start, end));
10045d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    break;
10055d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                default: throw new IllegalArgumentException("Ill-formed number range: " + range);
10065d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                }
10075d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
10085d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return new FixedDecimalSamples(sampleType2, Collections.unmodifiableSet(samples2), bounded2);
10095d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
10105d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
10115d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        private static void checkDecimal(SampleType sampleType2, FixedDecimal sample) {
10125d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            if ((sampleType2 == SampleType.INTEGER) != (sample.getVisibleDecimalDigitCount() == 0)) {
10135d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                throw new IllegalArgumentException("Ill-formed number range: " + sample);
10145d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
10155d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
10165d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
10175d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
10185d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
10195d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
10205d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
10218d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
10225d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public Set<Double> addSamples(Set<Double> result) {
10235d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            for (FixedDecimalRange item : samples) {
10245d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                // we have to convert to longs so we don't get strange double issues
10255d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                long startDouble = item.start.getShiftedValue();
10265d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                long endDouble = item.end.getShiftedValue();
10275d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
10285d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                for (long d = startDouble; d <= endDouble; d += 1) {
10295d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    result.add(d/(double)item.start.baseFactor);
10305d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                }
10315d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
10325d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return result;
10335d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
10345d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
10355d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
10365d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
10375d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
10385d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
10398d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
10405d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        @Override
10415d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public String toString() {
10425d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            StringBuilder b = new StringBuilder("@").append(sampleType.toString().toLowerCase(Locale.ENGLISH));
10435d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            boolean first = true;
10445d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            for (FixedDecimalRange item : samples) {
10455d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                if (first) {
10465d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    first = false;
10475d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                } else {
10485d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    b.append(",");
10495d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                }
10505d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                b.append(' ').append(item);
10515d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
10525d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            if (!bounded) {
10535d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                b.append(", …");
10545d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
10555d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return b.toString();
10565d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
10575d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
10585d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
10595d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
10605d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
10615d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
10628d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
10635d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public Set<FixedDecimalRange> getSamples() {
10645d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return samples;
10655d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
10665d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
10675d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
10685d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
10695d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
10705d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
10718d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
10725d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public void getStartEndSamples(Set<FixedDecimal> target) {
10735d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            for (FixedDecimalRange item : samples) {
10745d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                target.add(item.start);
10755d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                target.add(item.end);
10765d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
10775d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
10785d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
10795d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
10805d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /*
10815d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * A constraint on a number.
10825d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
10835d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    private interface Constraint extends Serializable {
10845d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /*
10855d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * Returns true if the number fulfills the constraint.
10865d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @param n the number to test, >= 0.
10875d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
10885d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        boolean isFulfilled(FixedDecimal n);
10895d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
10905d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /*
10915d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * Returns false if an unlimited number of values fulfills the
10925d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * constraint.
10935d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
10945d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        boolean isLimited(SampleType sampleType);
10955d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
10965d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
10978d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    private static final boolean isBreakAndIgnore(char c) {
10988d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        return c <= 0x20 && (c == 0x20 || c == 9 || c == 0xa || c == 0xc || c == 0xd);
10998d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    }
11008d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    private static final boolean isBreakAndKeep(char c) {
11018d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        return c <= '=' && c >= '!' && (c == '!' || c == '%' || c == ',' || c == '.' || c == '=');
11028d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    }
11035d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    static class SimpleTokenizer {
11048d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        // static final UnicodeSet BREAK_AND_IGNORE = new UnicodeSet(0x09, 0x0a, 0x0c, 0x0d, 0x20, 0x20).freeze();
11058d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        // static final UnicodeSet BREAK_AND_KEEP = new UnicodeSet('!', '!', '%', '%', ',', ',', '.', '.', '=', '=').freeze();
11065d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        static String[] split(String source) {
11075d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            int last = -1;
11085d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            List<String> result = new ArrayList<String>();
11095d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            for (int i = 0; i < source.length(); ++i) {
11105d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                char ch = source.charAt(i);
11118d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                if (isBreakAndIgnore(ch) /* BREAK_AND_IGNORE.contains(ch) */) {
11125d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    if (last >= 0) {
11135d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        result.add(source.substring(last,i));
11145d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        last = -1;
11155d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    }
11168d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                } else if (isBreakAndKeep(ch) /* BREAK_AND_KEEP.contains(ch) */) {
11175d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    if (last >= 0) {
11185d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        result.add(source.substring(last,i));
11195d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    }
11205d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    result.add(source.substring(i,i+1));
11215d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    last = -1;
11225d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                } else if (last < 0) {
11235d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    last = i;
11245d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                }
11255d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
11265d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            if (last >= 0) {
11275d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                result.add(source.substring(last));
11285d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
11295d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return result.toArray(new String[result.size()]);
11305d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
11315d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
11325d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
11335d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /*
11345d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * syntax:
11355d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * condition :       or_condition
11365d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *                   and_condition
11375d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * or_condition :    and_condition 'or' condition
11385d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * and_condition :   relation
11395d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *                   relation 'and' relation
11405d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * relation :        in_relation
11415d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *                   within_relation
11425d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * in_relation :     not? expr not? in not? range
11435d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * within_relation : not? expr not? 'within' not? range
11445d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * not :             'not'
11455d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *                   '!'
11465d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * expr :            'n'
11475d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *                   'n' mod value
11485d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * mod :             'mod'
11495d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *                   '%'
11505d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * in :              'in'
11515d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *                   'is'
11525d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *                   '='
11535d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *                   '≠'
11545d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * value :           digit+
11555d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * digit :           0|1|2|3|4|5|6|7|8|9
11565d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * range :           value'..'value
11575d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
11585d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    private static Constraint parseConstraint(String description)
11595d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            throws ParseException {
11605d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
11615d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        Constraint result = null;
11625d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        String[] or_together = OR_SEPARATED.split(description);
11635d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        for (int i = 0; i < or_together.length; ++i) {
11645d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            Constraint andConstraint = null;
11655d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            String[] and_together = AND_SEPARATED.split(or_together[i]);
11665d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            for (int j = 0; j < and_together.length; ++j) {
11675d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                Constraint newConstraint = NO_CONSTRAINT;
11685d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
11695d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                String condition = and_together[j].trim();
11705d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                String[] tokens = SimpleTokenizer.split(condition);
11715d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
11725d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                int mod = 0;
11735d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                boolean inRange = true;
11745d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                boolean integersOnly = true;
11755d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                double lowBound = Long.MAX_VALUE;
11765d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                double highBound = Long.MIN_VALUE;
11775d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                long[] vals = null;
11785d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
11795d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                int x = 0;
11805d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                String t = tokens[x++];
11815d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                boolean hackForCompatibility = false;
11825d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                Operand operand;
11835d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                try {
11845d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    operand = FixedDecimal.getOperand(t);
11855d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                } catch (Exception e) {
11865d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    throw unexpected(t, condition);
11875d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                }
11885d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                if (x < tokens.length) {
11895d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    t = tokens[x++];
11905d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    if ("mod".equals(t) || "%".equals(t)) {
11915d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        mod = Integer.parseInt(tokens[x++]);
11925d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        t = nextToken(tokens, x++, condition);
11935d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    }
11945d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    if ("not".equals(t)) {
11955d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        inRange = !inRange;
11965d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        t = nextToken(tokens, x++, condition);
11975d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        if ("=".equals(t)) {
11985d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                            throw unexpected(t, condition);
11995d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        }
12005d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    } else if ("!".equals(t)) {
12015d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        inRange = !inRange;
12025d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        t = nextToken(tokens, x++, condition);
12035d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        if (!"=".equals(t)) {
12045d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                            throw unexpected(t, condition);
12055d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        }
12065d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    }
12075d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    if ("is".equals(t) || "in".equals(t) || "=".equals(t)) {
12085d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        hackForCompatibility = "is".equals(t);
12095d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        if (hackForCompatibility && !inRange) {
12105d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                            throw unexpected(t, condition);
12115d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        }
12125d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        t = nextToken(tokens, x++, condition);
12135d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    } else if ("within".equals(t)) {
12145d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        integersOnly = false;
12155d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        t = nextToken(tokens, x++, condition);
12165d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    } else {
12175d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        throw unexpected(t, condition);
12185d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    }
12195d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    if ("not".equals(t)) {
12205d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        if (!hackForCompatibility && !inRange) {
12215d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                            throw unexpected(t, condition);
12225d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        }
12235d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        inRange = !inRange;
12245d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        t = nextToken(tokens, x++, condition);
12255d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    }
12265d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
12275d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    List<Long> valueList = new ArrayList<Long>();
12285d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
12295d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    // the token t is always one item ahead
12305d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    while (true) {
12315d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        long low = Long.parseLong(t);
12325d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        long high = low;
12335d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        if (x < tokens.length) {
12345d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                            t = nextToken(tokens, x++, condition);
12355d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                            if (t.equals(".")) {
12365d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                                t = nextToken(tokens, x++, condition);
12375d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                                if (!t.equals(".")) {
12385d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                                    throw unexpected(t, condition);
12395d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                                }
12405d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                                t = nextToken(tokens, x++, condition);
12415d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                                high = Long.parseLong(t);
12425d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                                if (x < tokens.length) {
12435d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                                    t = nextToken(tokens, x++, condition);
12445d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                                    if (!t.equals(",")) { // adjacent number: 1 2
12455d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                                        // no separator, fail
12465d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                                        throw unexpected(t, condition);
12475d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                                    }
12485d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                                }
12495d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                            } else if (!t.equals(",")) { // adjacent number: 1 2
12505d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                                // no separator, fail
12515d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                                throw unexpected(t, condition);
12525d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                            }
12535d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        }
12545d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        // at this point, either we are out of tokens, or t is ','
12555d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        if (low > high) {
12565d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                            throw unexpected(low + "~" + high, condition);
12575d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        } else if (mod != 0 && high >= mod) {
12585d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                            throw unexpected(high + ">mod=" + mod, condition);
12595d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        }
12605d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        valueList.add(low);
12615d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        valueList.add(high);
12625d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        lowBound = Math.min(lowBound, low);
12635d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        highBound = Math.max(highBound, high);
12645d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        if (x >= tokens.length) {
12655d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                            break;
12665d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        }
12675d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        t = nextToken(tokens, x++, condition);
12685d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    }
12695d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
12705d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    if (t.equals(",")) {
12715d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        throw unexpected(t, condition);
12725d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    }
12735d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
12745d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    if (valueList.size() == 2) {
12755d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        vals = null;
12765d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    } else {
12775d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        vals = new long[valueList.size()];
12785d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        for (int k = 0; k < vals.length; ++k) {
12795d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                            vals[k] = valueList.get(k);
12805d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        }
12815d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    }
12825d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
12835d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    // Hack to exclude "is not 1,2"
12845d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    if (lowBound != highBound && hackForCompatibility && !inRange) {
12855d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        throw unexpected("is not <range>", condition);
12865d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    }
12875d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
12885d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    newConstraint =
12895d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                            new RangeConstraint(mod, inRange, operand, integersOnly, lowBound, highBound, vals);
12905d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                }
12915d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
12925d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                if (andConstraint == null) {
12935d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    andConstraint = newConstraint;
12945d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                } else {
12955d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    andConstraint = new AndConstraint(andConstraint,
12965d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                            newConstraint);
12975d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                }
12985d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
12995d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
13005d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            if (result == null) {
13015d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                result = andConstraint;
13025d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            } else {
13035d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                result = new OrConstraint(result, andConstraint);
13045d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
13055d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
13065d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return result;
13075d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
13085d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
13095d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    static final Pattern AT_SEPARATED = Pattern.compile("\\s*\\Q\\E@\\s*");
13105d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    static final Pattern OR_SEPARATED = Pattern.compile("\\s*or\\s*");
13115d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    static final Pattern AND_SEPARATED = Pattern.compile("\\s*and\\s*");
13125d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    static final Pattern COMMA_SEPARATED = Pattern.compile("\\s*,\\s*");
13135d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    static final Pattern DOTDOT_SEPARATED = Pattern.compile("\\s*\\Q..\\E\\s*");
13145d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    static final Pattern TILDE_SEPARATED = Pattern.compile("\\s*~\\s*");
13155d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    static final Pattern SEMI_SEPARATED = Pattern.compile("\\s*;\\s*");
13165d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
13175d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
13185d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /* Returns a parse exception wrapping the token and context strings. */
13195d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    private static ParseException unexpected(String token, String context) {
13205d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return new ParseException("unexpected token '" + token +
13215d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                "' in '" + context + "'", -1);
13225d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
13235d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
13245d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /*
13255d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Returns the token at x if available, else throws a parse exception.
13265d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
13275d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    private static String nextToken(String[] tokens, int x, String context)
13285d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            throws ParseException {
13295d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        if (x < tokens.length) {
13305d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return tokens[x];
13315d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
13325d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        throw new ParseException("missing token at end of '" + context + "'", -1);
13335d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
13345d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
13355d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /*
13365d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Syntax:
13375d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * rule : keyword ':' condition
13385d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * keyword: <identifier>
13395d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
13405d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    private static Rule parseRule(String description) throws ParseException {
13415d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        if (description.length() == 0) {
13425d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return DEFAULT_RULE;
13435d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
13445d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
13455d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        description = description.toLowerCase(Locale.ENGLISH);
13465d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
13475d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        int x = description.indexOf(':');
13485d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        if (x == -1) {
13495d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            throw new ParseException("missing ':' in rule description '" +
13505d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    description + "'", 0);
13515d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
13525d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
13535d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        String keyword = description.substring(0, x).trim();
13545d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        if (!isValidKeyword(keyword)) {
13555d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            throw new ParseException("keyword '" + keyword +
13565d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    " is not valid", 0);
13575d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
13585d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
13595d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        description = description.substring(x+1).trim();
13605d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        String[] constraintOrSamples = AT_SEPARATED.split(description);
13615d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        boolean sampleFailure = false;
13625d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        FixedDecimalSamples integerSamples = null, decimalSamples = null;
13635d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        switch (constraintOrSamples.length) {
13645d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        case 1: break;
13655d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        case 2:
13665d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            integerSamples = FixedDecimalSamples.parse(constraintOrSamples[1]);
13675d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            if (integerSamples.sampleType == SampleType.DECIMAL) {
13685d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                decimalSamples = integerSamples;
13695d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                integerSamples = null;
13705d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
13715d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            break;
13725d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        case 3:
13735d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            integerSamples = FixedDecimalSamples.parse(constraintOrSamples[1]);
13745d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            decimalSamples = FixedDecimalSamples.parse(constraintOrSamples[2]);
13755d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            if (integerSamples.sampleType != SampleType.INTEGER || decimalSamples.sampleType != SampleType.DECIMAL) {
13765d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                throw new IllegalArgumentException("Must have @integer then @decimal in " + description);
13775d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
13785d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            break;
13795d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        default:
13805d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            throw new IllegalArgumentException("Too many samples in " + description);
13815d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
13825d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        if (sampleFailure) {
13835d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            throw new IllegalArgumentException("Ill-formed samples—'@' characters.");
13845d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
13855d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
13865d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        // 'other' is special, and must have no rules; all other keywords must have rules.
13875d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        boolean isOther = keyword.equals("other");
13885d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        if (isOther != (constraintOrSamples[0].length() == 0)) {
13895d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            throw new IllegalArgumentException("The keyword 'other' must have no constraints, just samples.");
13905d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
13915d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
13925d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        Constraint constraint;
13935d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        if (isOther) {
13945d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            constraint = NO_CONSTRAINT;
13955d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        } else {
13965d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            constraint = parseConstraint(constraintOrSamples[0]);
13975d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
13985d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return new Rule(keyword, constraint, integerSamples, decimalSamples);
13995d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
14005d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
14015d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
14025d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /*
14035d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Syntax:
14045d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * rules : rule
14055d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *         rule ';' rules
14065d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
14075d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    private static RuleList parseRuleChain(String description)
14085d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            throws ParseException {
14095d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        RuleList result = new RuleList();
14105d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        // remove trailing ;
14115d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        if (description.endsWith(";")) {
14125d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            description = description.substring(0,description.length()-1);
14135d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
14145d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        String[] rules = SEMI_SEPARATED.split(description);
14155d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        for (int i = 0; i < rules.length; ++i) {
14165d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            Rule rule = parseRule(rules[i].trim());
14175d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            result.hasExplicitBoundingInfo |= rule.integerSamples != null || rule.decimalSamples != null;
14185d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            result.addRule(rule);
14195d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
14205d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return result.finish();
14215d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
14225d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
14235d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /*
14245d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * An implementation of Constraint representing a modulus,
14255d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * a range of values, and include/exclude. Provides lots of
14265d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * convenience factory methods.
14275d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
14285d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    private static class RangeConstraint implements Constraint, Serializable {
14295d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        private static final long serialVersionUID = 1;
14305d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
14315d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        private final int mod;
14325d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        private final boolean inRange;
14335d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        private final boolean integersOnly;
14345d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        private final double lowerBound;
14355d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        private final double upperBound;
14365d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        private final long[] range_list;
14375d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        private final Operand operand;
14385d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
14395d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        RangeConstraint(int mod, boolean inRange, Operand operand, boolean integersOnly,
14405d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                double lowBound, double highBound, long[] vals) {
14415d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            this.mod = mod;
14425d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            this.inRange = inRange;
14435d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            this.integersOnly = integersOnly;
14445d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            this.lowerBound = lowBound;
14455d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            this.upperBound = highBound;
14465d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            this.range_list = vals;
14475d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            this.operand = operand;
14485d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
14495d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
14505d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public boolean isFulfilled(FixedDecimal number) {
14515d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            double n = number.get(operand);
14525d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            if ((integersOnly && (n - (long)n) != 0.0
14535d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    || operand == Operand.j && number.visibleDecimalDigitCount != 0)) {
14545d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                return !inRange;
14555d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
14565d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            if (mod != 0) {
14575d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                n = n % mod;    // java % handles double numerator the way we want
14585d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
14595d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            boolean test = n >= lowerBound && n <= upperBound;
14605d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            if (test && range_list != null) {
14615d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                test = false;
14625d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                for (int i = 0; !test && i < range_list.length; i += 2) {
14635d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    test = n >= range_list[i] && n <= range_list[i+1];
14645d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                }
14655d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
14665d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return inRange == test;
14675d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
14685d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
14695d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public boolean isLimited(SampleType sampleType) {
14705d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            boolean valueIsZero = lowerBound == upperBound && lowerBound == 0d;
14715d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            boolean hasDecimals =
14725d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    (operand == Operand.v || operand == Operand.w || operand == Operand.f || operand == Operand.t)
14735d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    && inRange != valueIsZero; // either NOT f = zero or f = non-zero
14745d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            switch (sampleType) {
14755d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            case INTEGER:
14765d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                return hasDecimals // will be empty
14775d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        || (operand == Operand.n || operand == Operand.i || operand == Operand.j)
14785d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        && mod == 0
14795d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        && inRange;
14805d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
14815d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            case DECIMAL:
14825d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                return  (!hasDecimals || operand == Operand.n || operand == Operand.j)
14835d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        && (integersOnly || lowerBound == upperBound)
14845d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        && mod == 0
14855d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        && inRange;
14865d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
14875d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return false;
14885d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
14895d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
14905d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public String toString() {
14915d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            StringBuilder result = new StringBuilder();
14925d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            result.append(operand);
14935d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            if (mod != 0) {
14945d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                result.append(" % ").append(mod);
14955d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
14965d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            boolean isList = lowerBound != upperBound;
14975d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            result.append(
14985d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    !isList ? (inRange ? " = " : " != ")
14995d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                            : integersOnly ? (inRange ? " = " : " != ")
15005d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                                    : (inRange ? " within " : " not within ")
15015d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    );
15025d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            if (range_list != null) {
15035d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                for (int i = 0; i < range_list.length; i += 2) {
15045d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    addRange(result, range_list[i], range_list[i+1], i != 0);
15055d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                }
15065d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            } else {
15075d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                addRange(result, lowerBound, upperBound, false);
15085d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
15095d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return result.toString();
15105d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
15115d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
15125d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
15135d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    private static void addRange(StringBuilder result, double lb, double ub, boolean addSeparator) {
15145d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        if (addSeparator) {
15155d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            result.append(",");
15165d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
15175d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        if (lb == ub) {
15185d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            result.append(format(lb));
15195d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        } else {
15205d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            result.append(format(lb) + ".." + format(ub));
15215d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
15225d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
15235d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
15245d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    private static String format(double lb) {
15255d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        long lbi = (long) lb;
15265d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return lb == lbi ? String.valueOf(lbi) : String.valueOf(lb);
15275d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
15285d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
15295d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /* Convenience base class for and/or constraints. */
15305d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    private static abstract class BinaryConstraint implements Constraint,
15315d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    Serializable {
15325d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        private static final long serialVersionUID = 1;
15335d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        protected final Constraint a;
15345d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        protected final Constraint b;
15355d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
15365d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        protected BinaryConstraint(Constraint a, Constraint b) {
15375d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            this.a = a;
15385d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            this.b = b;
15395d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
15405d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
15415d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
15425d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /* A constraint representing the logical and of two constraints. */
15435d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    private static class AndConstraint extends BinaryConstraint {
15445d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        private static final long serialVersionUID = 7766999779862263523L;
15455d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
15465d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        AndConstraint(Constraint a, Constraint b) {
15475d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            super(a, b);
15485d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
15495d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
15505d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public boolean isFulfilled(FixedDecimal n) {
15515d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return a.isFulfilled(n)
15525d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    && b.isFulfilled(n);
15535d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
15545d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
15555d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public boolean isLimited(SampleType sampleType) {
15565d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            // we ignore the case where both a and b are unlimited but no values
15575d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            // satisfy both-- we still consider this 'unlimited'
15585d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return a.isLimited(sampleType)
15595d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    || b.isLimited(sampleType);
15605d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
15615d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
15625d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public String toString() {
15635d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return a.toString() + " and " + b.toString();
15645d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
15655d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
15665d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
15675d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /* A constraint representing the logical or of two constraints. */
15685d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    private static class OrConstraint extends BinaryConstraint {
15695d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        private static final long serialVersionUID = 1405488568664762222L;
15705d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
15715d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        OrConstraint(Constraint a, Constraint b) {
15725d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            super(a, b);
15735d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
15745d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
15755d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public boolean isFulfilled(FixedDecimal n) {
15765d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return a.isFulfilled(n)
15775d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    || b.isFulfilled(n);
15785d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
15795d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
15805d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public boolean isLimited(SampleType sampleType) {
15815d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return a.isLimited(sampleType)
15825d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    && b.isLimited(sampleType);
15835d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
15845d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
15855d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public String toString() {
15865d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return a.toString() + " or " + b.toString();
15875d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
15885d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
15895d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
15905d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /*
15915d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Implementation of Rule that uses a constraint.
15925d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Provides 'and' and 'or' to combine constraints.  Immutable.
15935d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
15945d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    private static class Rule implements Serializable {
15955d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        private static final long serialVersionUID = 1;
15965d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        private final String keyword;
15975d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        private final Constraint constraint;
15985d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        private final FixedDecimalSamples integerSamples;
15995d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        private final FixedDecimalSamples decimalSamples;
16005d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
16015d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public Rule(String keyword, Constraint constraint, FixedDecimalSamples integerSamples, FixedDecimalSamples decimalSamples) {
16025d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            this.keyword = keyword;
16035d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            this.constraint = constraint;
16045d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            this.integerSamples = integerSamples;
16055d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            this.decimalSamples = decimalSamples;
16065d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
16075d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
16085d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        @SuppressWarnings("unused")
16095d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public Rule and(Constraint c) {
16105d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return new Rule(keyword, new AndConstraint(constraint, c), integerSamples, decimalSamples);
16115d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
16125d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
16135d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        @SuppressWarnings("unused")
16145d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public Rule or(Constraint c) {
16155d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return new Rule(keyword, new OrConstraint(constraint, c), integerSamples, decimalSamples);
16165d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
16175d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
16185d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public String getKeyword() {
16195d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return keyword;
16205d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
16215d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
16225d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public boolean appliesTo(FixedDecimal n) {
16235d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return constraint.isFulfilled(n);
16245d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
16255d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
16265d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public boolean isLimited(SampleType sampleType) {
16275d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return constraint.isLimited(sampleType);
16285d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
16295d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
16305d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public String toString() {
16315d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return keyword + ": " + constraint.toString()
16325d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    + (integerSamples == null ? "" : " " + integerSamples.toString())
16335d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    + (decimalSamples == null ? "" : " " + decimalSamples.toString());
16345d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
16355d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
16365d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
16375d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @internal
16385d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @deprecated This API is ICU internal only.
16395d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
16408d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
16415d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        @Override
16425d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public int hashCode() {
16435d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return keyword.hashCode() ^ constraint.hashCode();
16445d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
16455d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
16465d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public String getConstraint() {
16475d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return constraint.toString();
16485d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
16495d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
16505d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
16515d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    private static class RuleList implements Serializable {
16525d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        private boolean hasExplicitBoundingInfo = false;
16535d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        private static final long serialVersionUID = 1;
16545d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        private final List<Rule> rules = new ArrayList<Rule>();
16555d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
16565d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public RuleList addRule(Rule nextRule) {
16575d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            String keyword = nextRule.getKeyword();
16585d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            for (Rule rule : rules) {
16595d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                if (keyword.equals(rule.getKeyword())) {
16605d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    throw new IllegalArgumentException("Duplicate keyword: " + keyword);
16615d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                }
16625d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
16635d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            rules.add(nextRule);
16645d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return this;
16655d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
16665d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
16675d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public RuleList finish() throws ParseException {
16685d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            // make sure that 'other' is present, and at the end.
16695d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            Rule otherRule = null;
16705d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            for (Iterator<Rule> it = rules.iterator(); it.hasNext();) {
16715d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                Rule rule = it.next();
16725d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                if ("other".equals(rule.getKeyword())) {
16735d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    otherRule = rule;
16745d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    it.remove();
16755d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                }
16765d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
16775d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            if (otherRule == null) {
16785d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                otherRule = parseRule("other:"); // make sure we have always have an 'other' a rule
16795d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
16805d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            rules.add(otherRule);
16815d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return this;
16825d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
16835d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
16845d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        private Rule selectRule(FixedDecimal n) {
16855d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            for (Rule rule : rules) {
16865d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                if (rule.appliesTo(n)) {
16875d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    return rule;
16885d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                }
16895d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
16905d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return null;
16915d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
16925d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
16935d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public String select(FixedDecimal n) {
16948d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath            if (Double.isInfinite(n.source) || Double.isNaN(n.source)) {
16958d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                return KEYWORD_OTHER;
16968d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath            }
16975d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            Rule r = selectRule(n);
16985d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return r.getKeyword();
16995d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
17005d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
17015d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public Set<String> getKeywords() {
17025d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            Set<String> result = new LinkedHashSet<String>();
17035d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            for (Rule rule : rules) {
17045d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                result.add(rule.getKeyword());
17055d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
17065d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            // since we have explict 'other', we don't need this.
17075d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            //result.add(KEYWORD_OTHER);
17085d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return result;
17095d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
17105d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
17115d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public boolean isLimited(String keyword, SampleType sampleType) {
17125d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            if (hasExplicitBoundingInfo) {
17135d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                FixedDecimalSamples mySamples = getDecimalSamples(keyword, sampleType);
17145d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                return mySamples == null ? true : mySamples.bounded;
17155d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
17165d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
17175d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return computeLimited(keyword, sampleType);
17185d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
17195d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
17205d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public boolean computeLimited(String keyword, SampleType sampleType) {
17215d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            // if all rules with this keyword are limited, it's limited,
17225d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            // and if there's no rule with this keyword, it's unlimited
17235d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            boolean result = false;
17245d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            for (Rule rule : rules) {
17255d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                if (keyword.equals(rule.getKeyword())) {
17265d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    if (!rule.isLimited(sampleType)) {
17275d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                        return false;
17285d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    }
17295d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    result = true;
17305d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                }
17315d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
17325d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return result;
17335d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
17345d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
17355d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public String toString() {
17365d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            StringBuilder builder = new StringBuilder();
17375d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            for (Rule rule : rules) {
17385d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                if (builder.length() != 0) {
17395d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    builder.append(CATEGORY_SEPARATOR);
17405d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                }
17415d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                builder.append(rule);
17425d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
17435d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return builder.toString();
17445d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
17455d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
17465d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public String getRules(String keyword) {
17475d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            for (Rule rule : rules) {
17485d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                if (rule.getKeyword().equals(keyword)) {
17495d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    return rule.getConstraint();
17505d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                }
17515d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
17525d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return null;
17535d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
17545d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
17555d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public boolean select(FixedDecimal sample, String keyword) {
17565d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            for (Rule rule : rules) {
17575d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                if (rule.getKeyword().equals(keyword) && rule.appliesTo(sample)) {
17585d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    return true;
17595d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                }
17605d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
17615d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return false;
17625d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
17635d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
17645d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        public FixedDecimalSamples getDecimalSamples(String keyword, SampleType sampleType) {
17655d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            for (Rule rule : rules) {
17665d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                if (rule.getKeyword().equals(keyword)) {
17675d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    return sampleType == SampleType.INTEGER ? rule.integerSamples : rule.decimalSamples;
17685d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                }
17695d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
17705d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return null;
17715d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
17725d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
17735d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
17745d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
17755d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @deprecated This API is ICU internal only.
17765d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @internal
17775d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
17788d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    @Deprecated
17795d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public enum StandardPluralCategories {
17808d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        /**
17818d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         * @internal
17828d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         * @deprecated This API is ICU internal only.
17838d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         */
17848d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
17855d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        zero,
17868d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        /**
17878d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         * @internal
17888d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         * @deprecated This API is ICU internal only.
17898d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         */
17908d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
17915d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        one,
17928d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        /**
17938d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         * @internal
17948d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         * @deprecated This API is ICU internal only.
17958d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         */
17968d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
17975d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        two,
17988d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        /**
17998d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         * @internal
18008d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         * @deprecated This API is ICU internal only.
18018d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         */
18028d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
18035d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        few,
18048d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        /**
18058d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         * @internal
18068d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         * @deprecated This API is ICU internal only.
18078d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         */
18088d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
18095d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        many,
18108d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        /**
18118d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         * @internal
18128d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         * @deprecated This API is ICU internal only.
18138d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath         */
18148d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        @Deprecated
18155d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        other;
18165d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        static StandardPluralCategories forString(String s) {
18175d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            StandardPluralCategories a;
18185d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            try {
18195d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                a = valueOf(s);
18205d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            } catch (Exception e) {
18215d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                return null;
18225d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
18235d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return a;
18245d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
18255d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
18265d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
18275d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    @SuppressWarnings("unused")
18285d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    private boolean addConditional(Set<FixedDecimal> toAddTo, Set<FixedDecimal> others, double trial) {
18295d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        boolean added;
18305d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        FixedDecimal toAdd = new FixedDecimal(trial);
18315d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        if (!toAddTo.contains(toAdd) && !others.contains(toAdd)) {
18325d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            others.add(toAdd);
18335d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            added = true;
18345d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        } else {
18355d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            added = false;
18365d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
18375d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return added;
18385d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
18395d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
18405d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
18415d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
18425d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    // -------------------------------------------------------------------------
18435d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    // Static class methods.
18445d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    // -------------------------------------------------------------------------
18455d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
18465d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
18475d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Provides access to the predefined cardinal-number <code>PluralRules</code> for a given
18485d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * locale.
18495d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Same as forLocale(locale, PluralType.CARDINAL).
18505d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *
18515d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * <p>ICU defines plural rules for many locales based on CLDR <i>Language Plural Rules</i>.
18525d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * For these predefined rules, see CLDR page at
18535d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
18545d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *
18555d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @param locale The locale for which a <code>PluralRules</code> object is
18565d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *   returned.
18575d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @return The predefined <code>PluralRules</code> object for this locale.
18585d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *   If there's no predefined rules for this locale, the rules
18595d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *   for the closest parent in the locale hierarchy that has one will
18605d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *   be returned.  The final fallback always returns the default
18615d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *   rules.
18625d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @stable ICU 3.8
18635d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
18648d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    public static PluralRules forLocale(Locale locale) {
18658d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        return forLocale(locale, PluralType.CARDINAL);
18665d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
18675d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
18685d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
18695d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Provides access to the predefined <code>PluralRules</code> for a given
18705d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * locale and the plural type.
18715d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *
18725d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * <p>ICU defines plural rules for many locales based on CLDR <i>Language Plural Rules</i>.
18735d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * For these predefined rules, see CLDR page at
18745d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
18755d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *
18765d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @param locale The locale for which a <code>PluralRules</code> object is
18775d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *   returned.
18785d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @param type The plural type (e.g., cardinal or ordinal).
18795d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @return The predefined <code>PluralRules</code> object for this locale.
18805d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *   If there's no predefined rules for this locale, the rules
18815d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *   for the closest parent in the locale hierarchy that has one will
18825d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *   be returned.  The final fallback always returns the default
18835d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *   rules.
18845d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @stable ICU 50
18855d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
18868d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    public static PluralRules forLocale(Locale locale, PluralType type) {
18875d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return Factory.getDefaultFactory().forLocale(locale, type);
18885d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
18895d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
18905d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /*
18915d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Checks whether a token is a valid keyword.
18925d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *
18935d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @param token the token to be checked
18945d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @return true if the token is a valid keyword.
18955d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
18965d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    private static boolean isValidKeyword(String token) {
18978d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        // return ALLOWED_ID.containsAll(token);
18988d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        for (int i = 0; i < token.length(); ++i) {
18998d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath            char c = token.charAt(i);
19008d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath            if (!('a' <= c && c <= 'z')) {
19018d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath                return false;
19028d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath            }
19038d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        }
19048d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath        return true;
19055d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
19065d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
19075d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /*
19085d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Creates a new <code>PluralRules</code> object.  Immutable.
19095d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
19105d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    private PluralRules(RuleList rules) {
19115d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        this.rules = rules;
19125d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        this.keywords = Collections.unmodifiableSet(rules.getKeywords());
19135d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
19145d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
19155d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
19165d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @internal
19175d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @deprecated This API is ICU internal only.
19185d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
19198d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    @Deprecated
19205d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    @Override
19215d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public int hashCode() {
19225d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return rules.hashCode();
19235d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
19245d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
19255d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Given a number, returns the keyword of the first rule that applies to
19265d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * the number.
19275d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *
19285d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @param number The number for which the rule has to be determined.
19295d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @return The keyword of the selected rule.
19305d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @stable ICU 4.0
19315d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
19325d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public String select(double number) {
19335d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return rules.select(new FixedDecimal(number));
19345d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
19355d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
19365d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
19375d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Given a number, returns the keyword of the first rule that applies to
19385d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * the number.
19395d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *
19405d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @param number The number for which the rule has to be determined.
19415d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @return The keyword of the selected rule.
19425d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @internal
19435d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @deprecated This API is ICU internal only.
19445d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
19458d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    @Deprecated
19465d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public String select(double number, int countVisibleFractionDigits, long fractionaldigits) {
19475d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return rules.select(new FixedDecimal(number, countVisibleFractionDigits, fractionaldigits));
19485d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
19495d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
19505d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
19515d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Given a number information, returns the keyword of the first rule that applies to
19525d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * the number.
19535d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *
19545d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @param sample The number information for which the rule has to be determined.
19555d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @return The keyword of the selected rule.
19565d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @internal
19575d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @deprecated This API is ICU internal only.
19585d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
19598d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    @Deprecated
19605d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public String select(FixedDecimal sample) {
19615d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return rules.select(sample);
19625d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
19635d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
19645d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
19655d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
19665d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Given a number information, and keyword, return whether the keyword would match the number.
19675d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *
19685d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @param sample The number information for which the rule has to be determined.
19695d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @param keyword The keyword to filter on
19705d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @internal
19715d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @deprecated This API is ICU internal only.
19725d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
19738d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    @Deprecated
19745d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public boolean matches(FixedDecimal sample, String keyword) {
19755d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return rules.select(sample, keyword);
19765d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
19775d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
19785d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
19795d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Returns a set of all rule keywords used in this <code>PluralRules</code>
19805d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * object.  The rule "other" is always present by default.
19815d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *
19825d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @return The set of keywords.
19835d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @stable ICU 3.8
19845d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
19855d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public Set<String> getKeywords() {
19865d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return keywords;
19875d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
19885d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
19895d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
19905d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Returns the unique value that this keyword matches, or {@link #NO_UNIQUE_VALUE}
19915d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * if the keyword matches multiple values or is not defined for this PluralRules.
19925d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *
19935d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @param keyword the keyword to check for a unique value
19945d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @return The unique value for the keyword, or NO_UNIQUE_VALUE.
19955d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @stable ICU 4.8
19965d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
19975d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public double getUniqueKeywordValue(String keyword) {
19985d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        Collection<Double> values = getAllKeywordValues(keyword);
19995d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        if (values != null && values.size() == 1) {
20005d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return values.iterator().next();
20015d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
20025d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return NO_UNIQUE_VALUE;
20035d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
20045d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
20055d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
20065d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Returns all the values that trigger this keyword, or null if the number of such
20075d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * values is unlimited.
20085d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *
20095d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @param keyword the keyword
20105d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @return the values that trigger this keyword, or null.  The returned collection
20115d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * is immutable. It will be empty if the keyword is not defined.
20125d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @stable ICU 4.8
20135d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
20145d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public Collection<Double> getAllKeywordValues(String keyword) {
20155d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return getAllKeywordValues(keyword, SampleType.INTEGER);
20165d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
20175d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
20185d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
20195d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Returns all the values that trigger this keyword, or null if the number of such
20205d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * values is unlimited.
20215d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *
20225d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @param keyword the keyword
20238d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath     * @param type the type of samples requested, INTEGER or DECIMAL
20245d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @return the values that trigger this keyword, or null.  The returned collection
20255d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * is immutable. It will be empty if the keyword is not defined.
20265d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *
20275d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @internal
20285d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @deprecated This API is ICU internal only.
20295d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
20308d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    @Deprecated
20315d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public Collection<Double> getAllKeywordValues(String keyword, SampleType type) {
20325d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        if (!isLimited(keyword, type)) {
20335d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return null;
20345d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
20355d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        Collection<Double> samples = getSamples(keyword, type);
20365d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return samples == null ? null : Collections.unmodifiableCollection(samples);
20375d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
20385d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
20395d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
20408d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath     * Returns a list of integer values for which select() would return that keyword,
20415d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * or null if the keyword is not defined. The returned collection is unmodifiable.
20425d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * The returned list is not complete, and there might be additional values that
20435d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * would return the keyword.
20445d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *
20455d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @param keyword the keyword to test
20465d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @return a list of values matching the keyword.
20475d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @stable ICU 4.8
20485d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
20495d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public Collection<Double> getSamples(String keyword) {
20505d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return getSamples(keyword, SampleType.INTEGER);
20515d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
20525d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
20535d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
20545d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Returns a list of values for which select() would return that keyword,
20555d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * or null if the keyword is not defined.
20565d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * The returned collection is unmodifiable.
20575d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * The returned list is not complete, and there might be additional values that
20585d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * would return the keyword. The keyword might be defined, and yet have an empty set of samples,
20595d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * IF there are samples for the other sampleType.
20605d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *
20615d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @param keyword the keyword to test
20628d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath     * @param sampleType the type of samples requested, INTEGER or DECIMAL
20635d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @return a list of values matching the keyword.
20648d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath     * @internal
20655d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @deprecated ICU internal only
20665d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
20678d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    @Deprecated
20685d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public Collection<Double> getSamples(String keyword, SampleType sampleType) {
20695d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        if (!keywords.contains(keyword)) {
20705d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return null;
20715d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
20725d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        Set<Double> result = new TreeSet<Double>();
20735d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
20745d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        if (rules.hasExplicitBoundingInfo) {
20755d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            FixedDecimalSamples samples = rules.getDecimalSamples(keyword, sampleType);
20765d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return samples == null ? Collections.unmodifiableSet(result)
20775d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    : Collections.unmodifiableSet(samples.addSamples(result));
20785d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
20795d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
20805d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        // hack in case the rule is created without explicit samples
20815d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        int maxCount = isLimited(keyword, sampleType) ? Integer.MAX_VALUE : 20;
20825d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
20835d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        switch (sampleType) {
20845d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        case INTEGER:
20855d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            for (int i = 0; i < 200; ++i) {
20865d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                if (!addSample(keyword, i, maxCount, result)) {
20875d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    break;
20885d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                }
20895d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
20905d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            addSample(keyword, 1000000, maxCount, result); // hack for Welsh
20915d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            break;
20925d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        case DECIMAL:
20935d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            for (int i = 0; i < 2000; ++i) {
20945d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                if (!addSample(keyword, new FixedDecimal(i/10d, 1), maxCount, result)) {
20955d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    break;
20965d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                }
20975d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
20985d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            addSample(keyword, new FixedDecimal(1000000d, 1), maxCount, result); // hack for Welsh
20995d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            break;
21005d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
21015d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return result.size() == 0 ? null : Collections.unmodifiableSet(result);
21025d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
21035d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
21045d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
21055d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @internal
21065d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @deprecated This API is ICU internal only.
21075d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
21088d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    @Deprecated
21095d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public boolean addSample(String keyword, Number sample, int maxCount, Set<Double> result) {
21105d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        String selectedKeyword = sample instanceof FixedDecimal ? select((FixedDecimal)sample) : select(sample.doubleValue());
21115d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        if (selectedKeyword.equals(keyword)) {
21125d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            result.add(sample.doubleValue());
21135d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            if (--maxCount < 0) {
21145d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                return false;
21155d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
21165d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
21175d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return true;
21185d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
21195d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
21205d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
21215d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Returns a list of values for which select() would return that keyword,
21225d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * or null if the keyword is not defined or no samples are available.
21235d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * The returned collection is unmodifiable.
21245d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * The returned list is not complete, and there might be additional values that
21255d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * would return the keyword.
21265d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *
21275d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @param keyword the keyword to test
21288d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath     * @param sampleType the type of samples requested, INTEGER or DECIMAL
21295d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @return a list of values matching the keyword.
21305d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @internal
21315d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @deprecated This API is ICU internal only.
21325d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
21338d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    @Deprecated
21345d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public FixedDecimalSamples getDecimalSamples(String keyword, SampleType sampleType) {
21355d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return rules.getDecimalSamples(keyword, sampleType);
21365d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
21375d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
21385d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
21395d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Returns the set of locales for which PluralRules are known.
21405d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @return the set of locales for which PluralRules are known, as a list
21415d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @draft ICU 4.2
21425d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @provisional This API might change or be removed in a future release.
21435d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public static ULocale[] getAvailableULocales() {
21445d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return Factory.getDefaultFactory().getAvailableULocales();
21455d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
21468d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath     */
21475d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
21485d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
21495d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Returns the 'functionally equivalent' locale with respect to
21505d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * plural rules.  Calling PluralRules.forLocale with the functionally equivalent
21515d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * locale, and with the provided locale, returns rules that behave the same.
21525d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * <br/>
21535d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * All locales with the same functionally equivalent locale have
21545d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * plural rules that behave the same.  This is not exaustive;
21555d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * there may be other locales whose plural rules behave the same
21565d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * that do not have the same equivalent locale.
21575d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *
21585d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @param locale the locale to check
21595d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @param isAvailable if not null and of length > 0, this will hold 'true' at
21605d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * index 0 if locale is directly defined (without fallback) as having plural rules
21615d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @return the functionally-equivalent locale
21625d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @draft ICU 4.2
21635d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @provisional This API might change or be removed in a future release.
21645d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public static ULocale getFunctionalEquivalent(ULocale locale, boolean[] isAvailable) {
21655d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return Factory.getDefaultFactory().getFunctionalEquivalent(locale, isAvailable);
21665d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
21678d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath     */
21685d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
21695d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
21705d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * {@inheritDoc}
21715d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @stable ICU 3.8
21725d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
21735d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public String toString() {
21745d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return rules.toString();
21755d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
21765d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
21775d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
21785d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * {@inheritDoc}
21795d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @stable ICU 3.8
21805d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
21815d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public boolean equals(Object rhs) {
21825d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return rhs instanceof PluralRules && equals((PluralRules)rhs);
21835d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
21845d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
21855d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
21865d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Returns true if rhs is equal to this.
21875d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @param rhs the PluralRules to compare to.
21885d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @return true if this and rhs are equal.
21895d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @stable ICU 3.8
21905d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
21915d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    // TODO Optimize this
21925d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public boolean equals(PluralRules rhs) {
21935d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return rhs != null && toString().equals(rhs.toString());
21945d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
21955d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
21965d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
21975d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Status of the keyword for the rules, given a set of explicit values.
21985d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *
21995d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @draft ICU 50
22005d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @provisional This API might change or be removed in a future release.
22015d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
22025d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public enum KeywordStatus {
22035d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
22045d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * The keyword is not valid for the rules.
22055d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         *
22065d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @draft ICU 50
22075d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @provisional This API might change or be removed in a future release.
22085d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
22095d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        INVALID,
22105d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
22115d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * The keyword is valid, but unused (it is covered by the explicit values, OR has no values for the given {@link SampleType}).
22125d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         *
22135d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @draft ICU 50
22145d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @provisional This API might change or be removed in a future release.
22155d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
22165d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        SUPPRESSED,
22175d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
22185d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * The keyword is valid, used, and has a single possible value (before considering explicit values).
22195d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         *
22205d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @draft ICU 50
22215d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @provisional This API might change or be removed in a future release.
22225d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
22235d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        UNIQUE,
22245d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
22255d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * The keyword is valid, used, not unique, and has a finite set of values.
22265d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         *
22275d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @draft ICU 50
22285d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @provisional This API might change or be removed in a future release.
22295d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
22305d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        BOUNDED,
22315d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        /**
22325d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * The keyword is valid but not bounded; there indefinitely many matching values.
22335d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         *
22345d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @draft ICU 50
22355d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         * @provisional This API might change or be removed in a future release.
22365d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath         */
22375d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        UNBOUNDED
22385d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
22395d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
22405d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
22415d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Find the status for the keyword, given a certain set of explicit values.
22425d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *
22435d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @param keyword
22445d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *            the particular keyword (call rules.getKeywords() to get the valid ones)
22455d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @param offset
22465d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *            the offset used, or 0.0d if not. Internally, the offset is subtracted from each explicit value before
22475d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *            checking against the keyword values.
22485d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @param explicits
22495d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *            a set of Doubles that are used explicitly (eg [=0], "[=1]"). May be empty or null.
22505d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @param uniqueValue
22515d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *            If non null, set to the unique value.
22525d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @return the KeywordStatus
22535d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @draft ICU 50
22545d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @provisional This API might change or be removed in a future release.
22555d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
22565d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public KeywordStatus getKeywordStatus(String keyword, int offset, Set<Double> explicits,
22575d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            Output<Double> uniqueValue) {
22585d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return getKeywordStatus(keyword, offset, explicits, uniqueValue, SampleType.INTEGER);
22595d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
22605d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
22615d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * Find the status for the keyword, given a certain set of explicit values.
22625d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *
22635d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @param keyword
22645d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *            the particular keyword (call rules.getKeywords() to get the valid ones)
22655d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @param offset
22665d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *            the offset used, or 0.0d if not. Internally, the offset is subtracted from each explicit value before
22675d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *            checking against the keyword values.
22685d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @param explicits
22695d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *            a set of Doubles that are used explicitly (eg [=0], "[=1]"). May be empty or null.
22708d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath     * @param sampleType
22718d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath     *            request KeywordStatus relative to INTEGER or DECIMAL values
22725d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @param uniqueValue
22735d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     *            If non null, set to the unique value.
22745d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @return the KeywordStatus
22755d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @internal
22765d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @provisional This API might change or be removed in a future release.
22775d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
22785d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public KeywordStatus getKeywordStatus(String keyword, int offset, Set<Double> explicits,
22795d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            Output<Double> uniqueValue, SampleType sampleType) {
22805d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        if (uniqueValue != null) {
22815d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            uniqueValue.value = null;
22825d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
22835d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
22845d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        if (!keywords.contains(keyword)) {
22855d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return KeywordStatus.INVALID;
22865d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
22875d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
22885d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        if (!isLimited(keyword, sampleType)) {
22895d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return KeywordStatus.UNBOUNDED;
22905d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
22915d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
22925d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        Collection<Double> values = getSamples(keyword, sampleType);
22935d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
22945d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        int originalSize = values.size();
22955d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
22965d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        if (explicits == null) {
22975d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            explicits = Collections.emptySet();
22985d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
22995d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
23005d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        // Quick check on whether there are multiple elements
23015d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
23025d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        if (originalSize > explicits.size()) {
23035d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            if (originalSize == 1) {
23045d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                if (uniqueValue != null) {
23055d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    uniqueValue.value = values.iterator().next();
23065d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                }
23075d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                return KeywordStatus.UNIQUE;
23085d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            }
23095d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return KeywordStatus.BOUNDED;
23105d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
23115d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
23125d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        // Compute if the quick test is insufficient.
23135d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
23145d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        HashSet<Double> subtractedSet = new HashSet<Double>(values);
23155d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        for (Double explicit : explicits) {
23165d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            subtractedSet.remove(explicit - offset);
23175d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
23185d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        if (subtractedSet.size() == 0) {
23195d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            return KeywordStatus.SUPPRESSED;
23205d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
23215d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
23225d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        if (uniqueValue != null && subtractedSet.size() == 1) {
23235d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            uniqueValue.value = subtractedSet.iterator().next();
23245d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        }
23255d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
23265d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return originalSize == 1 ? KeywordStatus.UNIQUE : KeywordStatus.BOUNDED;
23275d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
23285d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
23295d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
23305d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @internal
23315d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @deprecated This API is ICU internal only.
23325d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
23338d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    @Deprecated
23345d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public String getRules(String keyword) {
23355d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return rules.getRules(keyword);
23365d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
23378d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    /*
23385d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    private void writeObject(
23395d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            ObjectOutputStream out)
23405d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath                    throws IOException {
23415d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        throw new NotSerializableException();
23425d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
23435d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
23445d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    private void readObject(ObjectInputStream in
23455d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath            ) throws IOException, ClassNotFoundException {
23465d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        throw new NotSerializableException();
23475d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
23485d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
23495d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    private Object writeReplace() throws ObjectStreamException {
23505d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return new PluralRulesSerialProxy(toString());
23515d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
23528d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    */
23535d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
23545d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @internal
23555d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @deprecated internal
23565d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
23578d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    @Deprecated
23585d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public int compareTo(PluralRules other) {
23595d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return toString().compareTo(other.toString());
23605d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
23615d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
23625d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
23635d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @internal
23645d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @deprecated internal
23655d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
23668d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    @Deprecated
23675d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public Boolean isLimited(String keyword) {
23685d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return rules.isLimited(keyword, SampleType.INTEGER);
23695d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
23705d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
23715d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
23725d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @internal
23735d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @deprecated internal
23745d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
23758d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    @Deprecated
23765d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public boolean isLimited(String keyword, SampleType sampleType) {
23775d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return rules.isLimited(keyword, sampleType);
23785d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
23795d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath
23805d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    /**
23815d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @internal
23825d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     * @deprecated internal
23835d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath     */
23848d05787d6a4b5762d790ccd2a9ed9dc8885986efNarayan Kamath    @Deprecated
23855d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    public boolean computeLimited(String keyword, SampleType sampleType) {
23865d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath        return rules.computeLimited(keyword, sampleType);
23875d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath    }
23885d1b0c9f348c25f01c6f2f5be04d2409409c08feNarayan Kamath}
2389