1/********************************************************************
2 * COPYRIGHT:
3 * Copyright (c) 1997-2012, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 * Copyright (C) 2010 , Yahoo! Inc.
6 ********************************************************************
7 *
8 * File SELFMT.CPP
9 *
10 * Modification History:
11 *
12 *   Date        Name        Description
13 *   11/11/09    kirtig      Finished first cut of implementation.
14 *   11/16/09    kirtig      Improved version
15 ********************************************************************/
16
17#include "utypeinfo.h"  // for 'typeid' to work
18
19#include "unicode/messagepattern.h"
20#include "unicode/rbnf.h"
21#include "unicode/selfmt.h"
22#include "unicode/uchar.h"
23#include "unicode/ucnv_err.h"
24#include "unicode/umsg.h"
25#include "unicode/ustring.h"
26#include "unicode/utypes.h"
27#include "cmemory.h"
28#include "messageimpl.h"
29#include "patternprops.h"
30#include "selfmtimpl.h"
31#include "uassert.h"
32#include "ustrfmt.h"
33#include "util.h"
34#include "uvector.h"
35
36#if !UCONFIG_NO_FORMATTING
37
38U_NAMESPACE_BEGIN
39
40UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SelectFormat)
41
42static const UChar SELECT_KEYWORD_OTHER[] = {LOW_O, LOW_T, LOW_H, LOW_E, LOW_R, 0};
43
44SelectFormat::SelectFormat(const UnicodeString& pat,
45                           UErrorCode& status) : msgPattern(status) {
46   applyPattern(pat, status);
47}
48
49SelectFormat::SelectFormat(const SelectFormat& other) : Format(other),
50                                                        msgPattern(other.msgPattern) {
51}
52
53SelectFormat::~SelectFormat() {
54}
55
56void
57SelectFormat::applyPattern(const UnicodeString& newPattern, UErrorCode& status) {
58    if (U_FAILURE(status)) {
59      return;
60    }
61
62    msgPattern.parseSelectStyle(newPattern, NULL, status);
63    if (U_FAILURE(status)) {
64        msgPattern.clear();
65    }
66}
67
68UnicodeString&
69SelectFormat::format(const Formattable& obj,
70                   UnicodeString& appendTo,
71                   FieldPosition& pos,
72                   UErrorCode& status) const
73{
74    if (U_FAILURE(status)) {
75        return appendTo;
76    }
77    if (obj.getType() == Formattable::kString) {
78        return format(obj.getString(status), appendTo, pos, status);
79    } else {
80        status = U_ILLEGAL_ARGUMENT_ERROR;
81        return appendTo;
82    }
83}
84
85UnicodeString&
86SelectFormat::format(const UnicodeString& keyword,
87                     UnicodeString& appendTo,
88                     FieldPosition& /*pos */,
89                     UErrorCode& status) const {
90    if (U_FAILURE(status)) {
91        return appendTo;
92    }
93    // Check for the validity of the keyword
94    if (!PatternProps::isIdentifier(keyword.getBuffer(), keyword.length())) {
95        status = U_ILLEGAL_ARGUMENT_ERROR;  // Invalid formatting argument.
96    }
97    if (msgPattern.countParts() == 0) {
98        status = U_INVALID_STATE_ERROR;
99        return appendTo;
100    }
101    int32_t msgStart = findSubMessage(msgPattern, 0, keyword, status);
102    if (!MessageImpl::jdkAposMode(msgPattern)) {
103        int32_t patternStart = msgPattern.getPart(msgStart).getLimit();
104        int32_t msgLimit = msgPattern.getLimitPartIndex(msgStart);
105        appendTo.append(msgPattern.getPatternString(),
106                        patternStart,
107                        msgPattern.getPatternIndex(msgLimit) - patternStart);
108        return appendTo;
109    }
110    // JDK compatibility mode: Remove SKIP_SYNTAX.
111    return MessageImpl::appendSubMessageWithoutSkipSyntax(msgPattern, msgStart, appendTo);
112}
113
114UnicodeString&
115SelectFormat::toPattern(UnicodeString& appendTo) {
116    if (0 == msgPattern.countParts()) {
117        appendTo.setToBogus();
118    } else {
119        appendTo.append(msgPattern.getPatternString());
120    }
121    return appendTo;
122}
123
124
125int32_t SelectFormat::findSubMessage(const MessagePattern& pattern, int32_t partIndex,
126                                     const UnicodeString& keyword, UErrorCode& ec) {
127    if (U_FAILURE(ec)) {
128        return 0;
129    }
130    UnicodeString other(FALSE, SELECT_KEYWORD_OTHER, 5);
131    int32_t count = pattern.countParts();
132    int32_t msgStart=0;
133    // Iterate over (ARG_SELECTOR, message) pairs until ARG_LIMIT or end of select-only pattern.
134    do {
135        const MessagePattern::Part& part=pattern.getPart(partIndex++);
136        const UMessagePatternPartType type=part.getType();
137        if(type==UMSGPAT_PART_TYPE_ARG_LIMIT) {
138            break;
139        }
140        // part is an ARG_SELECTOR followed by a message
141        if(pattern.partSubstringMatches(part, keyword)) {
142            // keyword matches
143            return partIndex;
144        } else if(msgStart==0 && pattern.partSubstringMatches(part, other)) {
145            msgStart=partIndex;
146        }
147        partIndex=pattern.getLimitPartIndex(partIndex);
148    } while(++partIndex<count);
149    return msgStart;
150}
151
152Format* SelectFormat::clone() const
153{
154    return new SelectFormat(*this);
155}
156
157SelectFormat&
158SelectFormat::operator=(const SelectFormat& other) {
159    if (this != &other) {
160        msgPattern = other.msgPattern;
161    }
162    return *this;
163}
164
165UBool
166SelectFormat::operator==(const Format& other) const {
167    if (this == &other) {
168        return TRUE;
169    }
170    if (!Format::operator==(other)) {
171        return FALSE;
172    }
173    const SelectFormat& o = (const SelectFormat&)other;
174    return msgPattern == o.msgPattern;
175}
176
177UBool
178SelectFormat::operator!=(const Format& other) const {
179    return  !operator==(other);
180}
181
182void
183SelectFormat::parseObject(const UnicodeString& /*source*/,
184                        Formattable& /*result*/,
185                        ParsePosition& pos) const
186{
187    // Parsing not supported.
188    pos.setErrorIndex(pos.getIndex());
189}
190
191U_NAMESPACE_END
192
193#endif /* #if !UCONFIG_NO_FORMATTING */
194
195//eof
196