12ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/* GENERATED SOURCE. DO NOT MODIFY. */
2f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert// © 2016 and later: Unicode, Inc. and others.
3f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html#License
42ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/*
52ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *******************************************************************************
6bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin * Copyright (C) 2004-2016, International Business Machines Corporation and    *
72ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * others. All Rights Reserved.                                                *
82ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Copyright (C) 2009 , Yahoo! Inc.                                            *
92ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *******************************************************************************
102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */
112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerpackage android.icu.text;
122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.io.IOException;
142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.io.ObjectInputStream;
152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.text.FieldPosition;
162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.text.Format;
172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.text.ParsePosition;
182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.impl.PatternProps;
202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/**
222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p><code>SelectFormat</code> supports the creation of  internationalized
232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * messages by selecting phrases based on keywords. The pattern  specifies
242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * how to map keywords to phrases and provides a default phrase. The
252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * object provided to the format method is a string that's matched
262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * against the keywords. If there is a match, the corresponding phrase
27bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin * is selected; otherwise, the default phrase is used.
282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
29bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin * <h3>Using <code>SelectFormat</code> for Gender Agreement</h3>
302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>Note: Typically, select formatting is done via <code>MessageFormat</code>
322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * with a <code>select</code> argument type,
33bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin * rather than using a stand-alone <code>SelectFormat</code>.
342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>The main use case for the select format is gender based  inflection.
362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * When names or nouns are inserted into sentences, their gender can  affect pronouns,
372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * verb forms, articles, and adjectives. Special care needs to be
382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * taken for the case where the gender cannot be determined.
39bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin * The impact varies between languages:
402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <ul>
422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>English has three genders, and unknown gender is handled as a  special
432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * case. Names use the gender of the named person (if known), nouns  referring
442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * to people use natural gender, and inanimate objects are usually  neutral.
452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * The gender only affects pronouns: "he", "she", "it", "they".
462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>German differs from English in that the gender of nouns is  rather
48bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin * arbitrary, even for nouns referring to people ("M&#xE4;dchen", girl, is  neutral).
492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * The gender affects pronouns ("er", "sie", "es"), articles ("der",  "die",
50bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin * "das"), and adjective forms ("guter Mann", "gute Frau", "gutes  M&#xE4;dchen").
512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>French has only two genders; as in German the gender of nouns
532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * is rather arbitrary - for sun and moon, the genders
542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * are the opposite of those in German. The gender affects
552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * pronouns ("il", "elle"), articles ("le", "la"),
562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * adjective forms ("bon", "bonne"), and sometimes
57bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin * verb forms ("all&#xE9;", "all&#xE9;e").
582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>Polish distinguishes five genders (or noun classes),
602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * human masculine, animate non-human masculine, inanimate masculine,
612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * feminine, and neuter.
622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * </ul>
632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>Some other languages have noun classes that are not related to  gender,
652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * but similar in grammatical use.
66bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin * Some African languages have around 20 noun classes.
672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p><b>Note:</b>For the gender of a <i>person</i> in a given sentence,
69bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin * we usually need to distinguish only between female, male and other/unknown.
702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>To enable localizers to create sentence patterns that take their
722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * language's gender dependencies into consideration, software has to  provide
732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * information about the gender associated with a noun or name to
742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <code>MessageFormat</code>.
75bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin * Two main cases can be distinguished:
762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <ul>
782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>For people, natural gender information should be maintained  for each person.
792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Keywords like "male", "female", "mixed" (for groups of people)
802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * and "unknown" could be used.
812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>For nouns, grammatical gender information should be maintained  for
832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * each noun and per language, e.g., in resource bundles.
842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * The keywords "masculine", "feminine", and "neuter" are commonly  used,
852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * but some languages may require other keywords.
862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * </ul>
872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>The resulting keyword is provided to <code>MessageFormat</code>  as a
892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * parameter separate from the name or noun it's associated with. For  example,
902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * to generate a message such as "Jean went to Paris", three separate  arguments
912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * would be provided: The name of the person as argument 0, the  gender of
922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the person as argument 1, and the name of the city as argument 2.
932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * The sentence pattern for English, where the gender of the person has
94bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin * no impact on this simple sentence, would not refer to argument 1  at all:
952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <pre>{0} went to {2}.</pre>
972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p><b>Note:</b> The entire sentence should be included (and partially repeated)
992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * inside each phrase. Otherwise translators would have to be trained on how to
1002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * move bits of the sentence in and out of the select argument of a message.
101bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin * (The examples below do not follow this recommendation!)
1022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>The sentence pattern for French, where the gender of the person affects
104bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin * the form of the participle, uses a select format based on argument 1:
1052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
106bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin * <pre>{0} est {1, select, female {all&#xE9;e} other {all&#xE9;}} &#xE0; {2}.</pre>
1072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>Patterns can be nested, so that it's possible to handle  interactions of
1092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * number and gender where necessary. For example, if the above  sentence should
1102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * allow for the names of several people to be inserted, the  following sentence
1112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * pattern can be used (with argument 0 the list of people's names,
1122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * argument 1 the number of people, argument 2 their combined gender, and
113bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin * argument 3 the city name):
1142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <pre>{0} {1, plural,
116bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin * one {est {2, select, female {all&#xE9;e} other  {all&#xE9;}}}
117bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin * other {sont {2, select, female {all&#xE9;es} other {all&#xE9;s}}}
118bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin * }&#xE0; {3}.</pre>
1192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <h4>Patterns and Their Interpretation</h4>
1212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>The <code>SelectFormat</code> pattern string defines the phrase  output
1232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * for each user-defined keyword.
1242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * The pattern is a sequence of (keyword, message) pairs.
125bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin * A keyword is a "pattern identifier": [^[[:Pattern_Syntax:][:Pattern_White_Space:]]]+
1262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
127bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin * <p>Each message is a MessageFormat pattern string enclosed in {curly braces}.
1282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>You always have to define a phrase for the default keyword
1302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <code>other</code>; this phrase is returned when the keyword
1312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * provided to
1322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the <code>format</code> method matches no other keyword.
1332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * If a pattern does not provide a phrase for <code>other</code>, the  method
1342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * it's provided to returns the error  <code>U_DEFAULT_KEYWORD_MISSING</code>.
135bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin * <br>
1362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Pattern_White_Space between keywords and messages is ignored.
137bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin * Pattern_White_Space within a message is preserved and output.
1382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
139bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin * <pre>Example:
1402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * MessageFormat msgFmt = new MessageFormat("{0} est " +
141bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin *     "{1, select, female {all&#xE9;e} other {all&#xE9;}} &#xE0; Paris.",
1422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     new ULocale("fr"));
1432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Object args[] = {"Kirti","female"};
1442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * System.out.println(msgFmt.format(args));
1452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * </pre>
1462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>
147bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin * Produces the output:<br>
148bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin * <code>Kirti est all&#xE9;e &#xE0; Paris.</code>
1492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */
1502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerpublic class SelectFormat extends Format{
1522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // Generated by serialver from JDK 1.5
1532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final long serialVersionUID = 2993154333257524984L;
1542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
1562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The applied pattern string.
1572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
1582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private String pattern = null;
1592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
1612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The MessagePattern which contains the parsed structure of the pattern string.
1622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
1632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    transient private MessagePattern msgPattern;
1642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
1662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Creates a new <code>SelectFormat</code> for a given pattern string.
1672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param  pattern the pattern for this <code>SelectFormat</code>.
1682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
1692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public SelectFormat(String pattern) {
1702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        applyPattern(pattern);
1712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
1722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
1742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Resets the <code>SelectFormat</code> object.
1752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
1762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void reset() {
1772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        pattern = null;
1782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if(msgPattern != null) {
1792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            msgPattern.clear();
1802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
1812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
1822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
1842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Sets the pattern used by this select format.
1852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Patterns and their interpretation are specified in the class description.
1862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
1872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param pattern the pattern for this select format.
1882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalArgumentException when the pattern is not a valid select format pattern.
1892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
1902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public void applyPattern(String pattern) {
1912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.pattern = pattern;
1922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (msgPattern == null) {
1932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            msgPattern = new MessagePattern();
1942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
1952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        try {
1962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            msgPattern.parseSelectStyle(pattern);
1972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } catch(RuntimeException e) {
1982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            reset();
1992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw e;
2002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
2022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
2042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Returns the pattern for this <code>SelectFormat</code>
2052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
2062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return the pattern string
2072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
2082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public String toPattern() {
2092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return pattern;
2102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
2112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
2132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Finds the SelectFormat sub-message for the given keyword, or the "other" sub-message.
2142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param pattern A MessagePattern.
2152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param partIndex the index of the first SelectFormat argument style part.
2162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param keyword a keyword to be matched to one of the SelectFormat argument's keywords.
2172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return the sub-message start part index.
2182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
2192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*package*/ static int findSubMessage(MessagePattern pattern, int partIndex, String keyword) {
2202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int count=pattern.countParts();
2212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int msgStart=0;
2222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Iterate over (ARG_SELECTOR, message) pairs until ARG_LIMIT or end of select-only pattern.
2232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        do {
2242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            MessagePattern.Part part=pattern.getPart(partIndex++);
2252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            MessagePattern.Part.Type type=part.getType();
2262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if(type==MessagePattern.Part.Type.ARG_LIMIT) {
2272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
2282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
2292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            assert type==MessagePattern.Part.Type.ARG_SELECTOR;
2302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // part is an ARG_SELECTOR followed by a message
2312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if(pattern.partSubstringMatches(part, keyword)) {
2322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // keyword matches
2332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return partIndex;
2342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if(msgStart==0 && pattern.partSubstringMatches(part, "other")) {
2352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                msgStart=partIndex;
2362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
2372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            partIndex=pattern.getLimitPartIndex(partIndex);
2382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } while(++partIndex<count);
2392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return msgStart;
2402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
2412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
2432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Selects the phrase for the given keyword.
2442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
2452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param keyword a phrase selection keyword.
2462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return the string containing the formatted select message.
2472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalArgumentException when the given keyword is not a "pattern identifier"
2482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
2492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public final String format(String keyword) {
2502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        //Check for the validity of the keyword
2512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (!PatternProps.isIdentifier(keyword)) {
2522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException("Invalid formatting argument.");
2532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // If no pattern was applied, throw an exception
2552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (msgPattern == null || msgPattern.countParts() == 0) {
2562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalStateException("Invalid format error.");
2572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Get the appropriate sub-message.
2602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int msgStart = findSubMessage(msgPattern, 0, keyword);
2612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (!msgPattern.jdkAposMode()) {
2622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int msgLimit = msgPattern.getLimitPartIndex(msgStart);
2632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return msgPattern.getPatternString().substring(msgPattern.getPart(msgStart).getLimit(),
2642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                           msgPattern.getPatternIndex(msgLimit));
2652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // JDK compatibility mode: Remove SKIP_SYNTAX.
2672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        StringBuilder result = null;
2682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int prevIndex = msgPattern.getPart(msgStart).getLimit();
2692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (int i = msgStart;;) {
2702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            MessagePattern.Part part = msgPattern.getPart(++i);
2712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            MessagePattern.Part.Type type = part.getType();
2722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int index = part.getIndex();
2732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (type == MessagePattern.Part.Type.MSG_LIMIT) {
2742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (result == null) {
2752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return pattern.substring(prevIndex, index);
2762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
2772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return result.append(pattern, prevIndex, index).toString();
2782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
2792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (type == MessagePattern.Part.Type.SKIP_SYNTAX) {
2802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (result == null) {
2812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    result = new StringBuilder();
2822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
2832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result.append(pattern, prevIndex, index);
2842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                prevIndex = part.getLimit();
2852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (type == MessagePattern.Part.Type.ARG_START) {
2862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (result == null) {
2872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    result = new StringBuilder();
2882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
2892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result.append(pattern, prevIndex, index);
2902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                prevIndex = index;
2912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                i = msgPattern.getLimitPartIndex(i);
2922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                index = msgPattern.getPart(i).getLimit();
2932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                MessagePattern.appendReducedApostrophes(pattern, prevIndex, index, result);
2942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                prevIndex = index;
2952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
2962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
2982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
3002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Selects the phrase for the given keyword.
3012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * and appends the formatted message to the given <code>StringBuffer</code>.
3022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param keyword a phrase selection keyword.
3032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param toAppendTo the selected phrase will be appended to this
3042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        <code>StringBuffer</code>.
3052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param pos will be ignored by this method.
3062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalArgumentException when the given keyword is not a String
3072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         or not a "pattern identifier"
3082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return the string buffer passed in as toAppendTo, with formatted text
3092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         appended.
3102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public StringBuffer format(Object keyword, StringBuffer toAppendTo,
3122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            FieldPosition pos) {
3132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (keyword instanceof String) {
3142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            toAppendTo.append(format( (String)keyword));
3152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }else{
3162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException("'" + keyword + "' is not a String");
3172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return toAppendTo;
3192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
3202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
3222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This method is not supported by <code>SelectFormat</code>.
3232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param source the string to be parsed.
3242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param pos defines the position where parsing is to begin,
3252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * and upon return, the position where parsing left off.  If the position
3262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * has not changed upon return, then parsing failed.
3272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return nothing because this method is not supported.
3282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws UnsupportedOperationException thrown always.
3292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public Object parseObject(String source, ParsePosition pos) {
3312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        throw new UnsupportedOperationException();
3322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
3332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
3352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * {@inheritDoc}
3362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Override
3382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public boolean equals(Object obj) {
3392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if(this == obj) {
3402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return true;
3412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if(obj == null || getClass() != obj.getClass()) {
3432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return false;
3442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        SelectFormat sf = (SelectFormat) obj;
3462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return msgPattern == null ? sf.msgPattern == null : msgPattern.equals(sf.msgPattern);
3472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
3482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
3502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * {@inheritDoc}
3512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Override
3532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int hashCode() {
3542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (pattern != null) {
3552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return pattern.hashCode();
3562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return 0;
3582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
3592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
3612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * {@inheritDoc}
3622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Override
3642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public String toString() {
3652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return "pattern='" + pattern + "'";
3662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
3672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void readObject(ObjectInputStream in)
3692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        throws IOException, ClassNotFoundException {
3702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        in.defaultReadObject();
3712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (pattern != null) {
3722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            applyPattern(pattern);
3732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
3752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller}
376