1/*
2*******************************************************************************
3* Copyright (C) 2010, International Business Machines Corporation and
4* others. All Rights Reserved.
5*******************************************************************************
6*
7*
8* File NUMSYS.CPP
9*
10* Modification History:*
11*   Date        Name        Description
12*
13********************************************************************************
14*/
15
16#include "unicode/utypes.h"
17#include "unicode/localpointer.h"
18#include "unicode/uchar.h"
19#include "unicode/unistr.h"
20#include "unicode/ures.h"
21#include "unicode/ustring.h"
22#include "unicode/uloc.h"
23#include "unicode/schriter.h"
24#include "unicode/numsys.h"
25
26#include "uresimp.h"
27
28#if !UCONFIG_NO_FORMATTING
29
30U_NAMESPACE_BEGIN
31
32// Useful constants
33
34#define DEFAULT_DIGITS UNICODE_STRING_SIMPLE("0123456789");
35static const char gNumberingSystems[] = "numberingSystems";
36static const char gDefaultNumberingSystem[] = "defaultNumberingSystem";
37static const char gDesc[] = "desc";
38static const char gRadix[] = "radix";
39static const char gAlgorithmic[] = "algorithmic";
40
41
42UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NumberingSystem)
43
44    /**
45     * Default Constructor.
46     *
47     * @draft ICU 4.2
48     */
49
50NumberingSystem::NumberingSystem() {
51     radix = 10;
52     algorithmic = FALSE;
53     UnicodeString defaultDigits = DEFAULT_DIGITS;
54     desc.setTo(defaultDigits);
55}
56
57    /**
58     * Copy constructor.
59     * @draft ICU 4.2
60     */
61
62NumberingSystem::NumberingSystem(const NumberingSystem& other)
63:  UObject(other) {
64    *this=other;
65}
66
67NumberingSystem* U_EXPORT2
68NumberingSystem::createInstance(int32_t radix_in, UBool isAlgorithmic_in, const UnicodeString & desc_in, UErrorCode &status) {
69
70    if ( radix_in < 2 ) {
71        status = U_ILLEGAL_ARGUMENT_ERROR;
72        return NULL;
73    }
74
75    if ( !isAlgorithmic_in ) {
76       if ( desc_in.countChar32() != radix_in || !isValidDigitString(desc_in)) {
77           status = U_ILLEGAL_ARGUMENT_ERROR;
78           return NULL;
79       }
80    }
81
82    NumberingSystem *ns = new NumberingSystem();
83
84    ns->setRadix(radix_in);
85    ns->setDesc(desc_in);
86    ns->setAlgorithmic(isAlgorithmic_in);
87    return ns;
88
89}
90
91
92NumberingSystem* U_EXPORT2
93NumberingSystem::createInstance(const Locale & inLocale, UErrorCode& status) {
94
95    char buffer[ULOC_KEYWORDS_CAPACITY];
96    int32_t count = inLocale.getKeywordValue("numbers",buffer, sizeof(buffer),status);
97    if ( count > 0 ) { // @numbers keyword was specified in the locale
98        buffer[count] = '\0'; // Make sure it is null terminated.
99        return NumberingSystem::createInstanceByName(buffer,status);
100    } else { // Find the default numbering system for this locale.
101        LocalUResourceBundlePointer resource(ures_open(NULL, inLocale.getName(), &status));
102        if (U_FAILURE(status)) {
103            status = U_USING_FALLBACK_WARNING;
104            NumberingSystem *ns = new NumberingSystem();
105            return ns;
106        }
107        const UChar *defaultNSName =
108            ures_getStringByKeyWithFallback(resource.getAlias(), gDefaultNumberingSystem, &count, &status);
109        if (U_FAILURE(status)) {
110               return NULL;
111        }
112        if ( count > 0 && count < ULOC_KEYWORDS_CAPACITY ) { // Default numbering system found
113           u_UCharsToChars(defaultNSName,buffer,count);
114           buffer[count] = '\0'; // Make sure it is null terminated.
115           return NumberingSystem::createInstanceByName(buffer,status);
116        } else {
117            status = U_USING_FALLBACK_WARNING;
118            NumberingSystem *ns = new NumberingSystem();
119            return ns;
120        }
121
122    }
123}
124
125NumberingSystem* U_EXPORT2
126NumberingSystem::createInstance(UErrorCode& status) {
127    return NumberingSystem::createInstance(Locale::getDefault(), status);
128}
129
130NumberingSystem* U_EXPORT2
131NumberingSystem::createInstanceByName(const char *name, UErrorCode& status) {
132
133     UResourceBundle *numberingSystemsInfo = NULL;
134     UResourceBundle *nsTop, *nsCurrent;
135     const UChar* description = NULL;
136     int32_t radix = 10;
137     int32_t algorithmic = 0;
138     int32_t len;
139
140     numberingSystemsInfo = ures_openDirect(NULL,gNumberingSystems, &status);
141     nsCurrent = ures_getByKey(numberingSystemsInfo,gNumberingSystems,NULL,&status);
142     nsTop = ures_getByKey(nsCurrent,name,NULL,&status);
143     description = ures_getStringByKey(nsTop,gDesc,&len,&status);
144
145	 ures_getByKey(nsTop,gRadix,nsCurrent,&status);
146     radix = ures_getInt(nsCurrent,&status);
147
148     ures_getByKey(nsTop,gAlgorithmic,nsCurrent,&status);
149     algorithmic = ures_getInt(nsCurrent,&status);
150
151     UBool isAlgorithmic = ( algorithmic == 1 );
152     UnicodeString nsd;
153     nsd.setTo(description);
154
155	 ures_close(nsCurrent);
156	 ures_close(nsTop);
157     ures_close(numberingSystemsInfo);
158
159     if (U_FAILURE(status)) {
160         status = U_UNSUPPORTED_ERROR;
161         return NULL;
162     }
163
164     return NumberingSystem::createInstance(radix,isAlgorithmic,nsd,status);
165
166}
167
168    /**
169     * Destructor.
170     * @draft ICU 4.2
171     */
172NumberingSystem::~NumberingSystem() {
173}
174
175int32_t NumberingSystem::getRadix() {
176    return radix;
177}
178
179UnicodeString NumberingSystem::getDescription() {
180    return desc;
181}
182
183void NumberingSystem::setRadix(int32_t r) {
184    radix = r;
185}
186
187void NumberingSystem::setAlgorithmic(UBool c) {
188    algorithmic = c;
189}
190
191void NumberingSystem::setDesc(UnicodeString d) {
192    desc.setTo(d);
193}
194
195UBool NumberingSystem::isAlgorithmic() const {
196    return ( algorithmic );
197}
198
199
200UBool NumberingSystem::isValidDigitString(const UnicodeString& str) {
201
202    StringCharacterIterator it(str);
203    UChar32 c;
204    UChar32 prev = 0;
205    int32_t i = 0;
206
207    for ( it.setToStart(); it.hasNext(); ) {
208       c = it.next32PostInc();
209       if ( u_charDigitValue(c) != i ) {  // Digits outside the Unicode decimal digit class are not currently supported
210           return FALSE;
211       }
212       if ( prev != 0 && c != prev + 1 ) { // Non-contiguous digits are not currently supported
213          return FALSE;
214       }
215       if ( c > 0xFFFF ) { // Digits outside the BMP are not currently supported
216          return FALSE;
217       }
218       i++;
219       prev = c;
220    }
221    return TRUE;
222}
223U_NAMESPACE_END
224
225#endif /* #if !UCONFIG_NO_FORMATTING */
226
227//eof
228