1/*
2*******************************************************************************
3* Copyright (C) 2007-2010, International Business Machines Corporation and    *
4* others. All Rights Reserved.                                                *
5*******************************************************************************
6*/
7#ifndef ZSTRFMT_H
8#define ZSTRFMT_H
9
10#include "unicode/utypes.h"
11
12#if !UCONFIG_NO_FORMATTING
13
14#include "unicode/unistr.h"
15#include "unicode/calendar.h"
16#include "uhash.h"
17#include "uvector.h"
18
19U_NAMESPACE_BEGIN
20
21/*
22 * Character node used by TextTrieMap
23 */
24struct CharacterNode {
25    // No constructor or destructor.
26    // We malloc and free an uninitalized array of CharacterNode objects
27    // and clear and delete them ourselves.
28
29    void clear();
30    void deleteValues();
31
32    void addValue(void *value, UErrorCode &status);
33    inline UBool hasValues() const;
34    inline int32_t countValues() const;
35    inline const void *getValue(int32_t index) const;
36
37    void     *fValues;      // Union of one single value vs. UVector of values.
38    UChar    fCharacter;    // UTF-16 code unit.
39    uint16_t fFirstChild;   // 0 if no children.
40    uint16_t fNextSibling;  // 0 terminates the list.
41    UBool    fHasValuesVector;
42    UBool    fPadding;
43
44    // No value:   fValues == NULL               and  fHasValuesVector == FALSE
45    // One value:  fValues == value              and  fHasValuesVector == FALSE
46    // >=2 values: fValues == UVector of values  and  fHasValuesVector == TRUE
47};
48
49inline UBool CharacterNode::hasValues() const {
50    return (UBool)(fValues != NULL);
51}
52
53inline int32_t CharacterNode::countValues() const {
54    return
55        fValues == NULL ? 0 :
56        !fHasValuesVector ? 1 :
57        ((const UVector *)fValues)->size();
58}
59
60inline const void *CharacterNode::getValue(int32_t index) const {
61    if (!fHasValuesVector) {
62        return fValues;  // Assume index == 0.
63    } else {
64        return ((const UVector *)fValues)->elementAt(index);
65    }
66}
67
68/*
69 * Search result handler callback interface used by TextTrieMap search.
70 */
71class TextTrieMapSearchResultHandler : public UMemory {
72public:
73    virtual UBool handleMatch(int32_t matchLength,
74                              const CharacterNode *node, UErrorCode& status) = 0;
75    virtual ~TextTrieMapSearchResultHandler(); //added to avoid warning
76};
77
78
79/*
80 * ZSFStringPool   Pool of (UChar *) strings.  Provides for sharing of repeated
81 *                 strings within ZoneStringFormats.
82 */
83struct ZSFStringPoolChunk;
84class ZSFStringPool: public UMemory {
85  public:
86    ZSFStringPool(UErrorCode &status);
87    ~ZSFStringPool();
88
89    /* Get the pooled string that is equal to the supplied string s.
90     * Copy the string into the pool if it is not already present.
91     *
92     * Life time of the returned string is that of the pool.
93     */
94    const UChar *get(const UChar *s, UErrorCode &status);
95
96    /* Get the pooled string that is equal to the supplied string s.
97     * Copy the string into the pool if it is not already present.
98     */
99    const UChar *get(const UnicodeString &s, UErrorCode &status);
100
101    /* Adopt a string into the pool, without copying it.
102     * Used for strings from resource bundles, which will persist without copying.
103     */
104    const UChar *adopt(const UChar *s, UErrorCode &status);
105
106    /* Freeze the string pool.  Discards the hash table that is used
107     * for looking up a string.  All pointers to pooled strings remain valid.
108     */
109    void freeze();
110
111  private:
112    ZSFStringPoolChunk   *fChunks;
113    UHashtable           *fHash;
114};
115
116
117/**
118 * TextTrieMap is a trie implementation for supporting
119 * fast prefix match for the string key.
120 */
121class TextTrieMap : public UMemory {
122public:
123    TextTrieMap(UBool ignoreCase);
124    virtual ~TextTrieMap();
125
126    void put(const UnicodeString &key, void *value, ZSFStringPool &sp, UErrorCode &status);
127    void search(const UnicodeString &text, int32_t start,
128        TextTrieMapSearchResultHandler *handler, UErrorCode& status) const;
129    int32_t isEmpty() const;
130
131private:
132    UBool           fIgnoreCase;
133    CharacterNode   *fNodes;
134    int32_t         fNodesCapacity;
135    int32_t         fNodesCount;
136
137    UVector         *fLazyContents;
138    UBool           fIsEmpty;
139
140    UBool growNodes();
141    CharacterNode* addChildNode(CharacterNode *parent, UChar c, UErrorCode &status);
142    CharacterNode* getChildNode(CharacterNode *parent, UChar c) const;
143
144    void putImpl(const UnicodeString &key, void *value, UErrorCode &status);
145    void buildTrie(UErrorCode &status);
146    void search(CharacterNode *node, const UnicodeString &text, int32_t start,
147        int32_t index, TextTrieMapSearchResultHandler *handler, UErrorCode &status) const;
148};
149
150
151// Name types, these bit flag are used for zone string lookup
152enum TimeZoneTranslationType {
153    LOCATION        = 0x0001,
154    GENERIC_LONG    = 0x0002,
155    GENERIC_SHORT   = 0x0004,
156    STANDARD_LONG   = 0x0008,
157    STANDARD_SHORT  = 0x0010,
158    DAYLIGHT_LONG   = 0x0020,
159    DAYLIGHT_SHORT  = 0x0040
160};
161
162// Name type index, these constants are used for index in the zone strings array.
163enum TimeZoneTranslationTypeIndex {
164    ZSIDX_LOCATION = 0,
165    ZSIDX_LONG_STANDARD,
166    ZSIDX_SHORT_STANDARD,
167    ZSIDX_LONG_DAYLIGHT,
168    ZSIDX_SHORT_DAYLIGHT,
169    ZSIDX_LONG_GENERIC,
170    ZSIDX_SHORT_GENERIC,
171
172    ZSIDX_COUNT
173};
174
175class MessageFormat;
176
177
178/*
179 * ZoneStringInfo is a class holding a localized zone string
180 * information.
181 */
182class ZoneStringInfo : public UMemory {
183public:
184    virtual ~ZoneStringInfo();
185
186    inline UnicodeString& getID(UnicodeString &result) const;
187    inline UnicodeString& getString(UnicodeString &result) const;
188    inline UBool isStandard(void) const;
189    inline UBool isDaylight(void) const;
190    inline UBool isGeneric(void) const;
191
192private:
193    friend class ZoneStringFormat;
194    friend class ZoneStringSearchResultHandler;
195
196    ZoneStringInfo(const UnicodeString &id, const UnicodeString &str,
197                   TimeZoneTranslationType type, ZSFStringPool &sp, UErrorCode &status);
198
199    const UChar   *fId;
200    const UChar   *fStr;
201    TimeZoneTranslationType fType;
202};
203
204inline UnicodeString& ZoneStringInfo::getID(UnicodeString &result) const {
205    return result.setTo(fId, -1);
206}
207
208inline UnicodeString& ZoneStringInfo::getString(UnicodeString &result) const {
209    return result.setTo(fStr, -1);
210}
211
212inline UBool ZoneStringInfo::isStandard(void) const {
213    return (fType == STANDARD_LONG || fType == STANDARD_SHORT);
214}
215
216inline UBool ZoneStringInfo::isDaylight(void) const {
217    return (fType == DAYLIGHT_LONG || fType == DAYLIGHT_SHORT);
218}
219
220inline UBool ZoneStringInfo::isGeneric(void) const {
221    return (fType == LOCATION || fType == GENERIC_LONG || fType == GENERIC_SHORT);
222}
223
224class SafeZoneStringFormatPtr;
225
226class ZoneStringFormat : public UMemory {
227public:
228    ZoneStringFormat(const UnicodeString* const* strings, int32_t rowCount, int32_t columnCount, UErrorCode &status);
229    ZoneStringFormat(const Locale& locale, UErrorCode &status);
230    virtual ~ZoneStringFormat();
231
232    /* Gets zone string format from cache if available, create it if not cached. */
233    static SafeZoneStringFormatPtr* getZoneStringFormat(const Locale& locale, UErrorCode &status);
234
235    /*
236     * Create a snapshot of old zone strings array for the given date
237     */
238    UnicodeString** createZoneStringsArray(UDate date, int32_t &rowCount, int32_t &colCount, UErrorCode &status) const;
239
240    /* TODO:  There is no implementation for this function.  Delete declaration? */
241    const UnicodeString** getZoneStrings(int32_t &rowCount, int32_t &columnCount) const;
242
243    UnicodeString& getSpecificLongString(const Calendar &cal,
244        UnicodeString &result, UErrorCode &status) const;
245
246    UnicodeString& getSpecificShortString(const Calendar &cal,
247        UBool commonlyUsedOnly, UnicodeString &result, UErrorCode &status) const;
248
249    UnicodeString& getGenericLongString(const Calendar &cal,
250        UnicodeString &result, UErrorCode &status) const;
251
252    UnicodeString& getGenericShortString(const Calendar &cal,
253        UBool commonlyUsedOnly, UnicodeString &result, UErrorCode &status) const;
254
255    UnicodeString& getGenericLocationString(const Calendar &cal,
256        UnicodeString &result, UErrorCode &status) const;
257
258    const ZoneStringInfo* findSpecificLong(const UnicodeString &text, int32_t start,
259        int32_t &matchLength, UErrorCode &status) const;
260    const ZoneStringInfo* findSpecificShort(const UnicodeString &text, int32_t start,
261        int32_t &matchLength, UErrorCode &status) const;
262    const ZoneStringInfo* findGenericLong(const UnicodeString &text, int32_t start,
263        int32_t &matchLength, UErrorCode &status) const;
264    const ZoneStringInfo* findGenericShort(const UnicodeString &text, int32_t start,
265        int32_t &matchLength, UErrorCode &status) const;
266    const ZoneStringInfo* findGenericLocation(const UnicodeString &text, int32_t start,
267        int32_t &matchLength, UErrorCode &status) const;
268
269    // Following APIs are not used by SimpleDateFormat, but public for testing purpose
270    inline UnicodeString& getLongStandard(const UnicodeString &tzid, UDate date,
271        UnicodeString &result) const;
272    inline UnicodeString& getLongDaylight(const UnicodeString &tzid, UDate date,
273        UnicodeString &result) const;
274    inline UnicodeString& getLongGenericNonLocation(const UnicodeString &tzid, UDate date,
275        UnicodeString &result) const;
276    inline UnicodeString& getLongGenericPartialLocation(const UnicodeString &tzid, UDate date,
277        UnicodeString &result) const;
278    inline UnicodeString& getShortStandard(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
279        UnicodeString &result) const;
280    inline UnicodeString& getShortDaylight(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
281        UnicodeString &result) const;
282    inline UnicodeString& getShortGenericNonLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
283        UnicodeString &result) const;
284    inline UnicodeString& getShortGenericPartialLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
285        UnicodeString &result) const;
286    inline UnicodeString& getGenericLocation(const UnicodeString &tzid, UnicodeString &result) const;
287
288private:
289    Locale           fLocale;
290    UHashtable      *fTzidToStrings;
291    UHashtable      *fMzidToStrings;
292
293    TextTrieMap      fZoneStringsTrie;
294    ZSFStringPool    fStringPool;
295
296    UResourceBundle *fZoneStringsArray;
297    UResourceBundle *fMetazoneItem;
298    UResourceBundle *fZoneItem;
299
300	UBool			 fIsFullyLoaded;
301
302	void loadZone(const UnicodeString &utzid, UErrorCode &status);
303	void addSingleZone(UnicodeString &utzid, UErrorCode &status);
304	void loadFull(UErrorCode &status);
305
306
307    /*
308     * Private method to get a zone string except generic partial location types.
309     */
310    UnicodeString& getString(const UnicodeString &tzid, TimeZoneTranslationTypeIndex typeIdx, UDate date,
311        UBool commonlyUsedOnly, UnicodeString& result) const;
312
313    /*
314     * Private method to get a generic string, with fallback logic involved,
315     * that is,
316     *
317     * 1. If a generic non-location string is avaiable for the zone, return it.
318     * 2. If a generic non-location string is associated with a metazone and
319     *    the zone never use daylight time around the given date, use the standard
320     *    string (if available).
321     *
322     *    Note: In CLDR1.5.1, the same localization is used for generic and standard.
323     *    In this case, we do not use the standard string and do the rest.
324     *
325     * 3. If a generic non-location string is associated with a metazone and
326     *    the offset at the given time is different from the preferred zone for the
327     *    current locale, then return the generic partial location string (if avaiable)
328     * 4. If a generic non-location string is not available, use generic location
329     *    string.
330     */
331    UnicodeString& getGenericString(const Calendar &cal, UBool isShort, UBool commonlyUsedOnly,
332        UnicodeString &result, UErrorCode &status) const;
333
334    /*
335     * Private method to get a generic partial location string
336     */
337    UnicodeString& getGenericPartialLocationString(const UnicodeString &tzid, UBool isShort,
338        UDate date, UBool commonlyUsedOnly, UnicodeString &result) const;
339
340    /*
341     * Find a prefix matching time zone for the given zone string types.
342     * @param text The text contains a time zone string
343     * @param start The start index within the text
344     * @param types The bit mask representing a set of requested types
345     * @param matchLength Receives the match length
346     * @param status
347     * @return If any zone string matched for the requested types, returns a
348     * ZoneStringInfo for the longest match.  If no matches are found for
349     * the requested types, returns a ZoneStringInfo for the longest match
350     * for any other types.  If nothing matches at all, returns null.
351     */
352    const ZoneStringInfo* find(const UnicodeString &text, int32_t start, int32_t types,
353        int32_t &matchLength, UErrorCode &status) const;
354	const ZoneStringInfo* subFind(const UnicodeString &text, int32_t start, int32_t types,
355                       int32_t &matchLength, UErrorCode &status) const;
356
357    UnicodeString& getRegion(UnicodeString &region) const;
358
359    static MessageFormat* getFallbackFormat(const Locale &locale, UErrorCode &status);
360    static MessageFormat* getRegionFormat(const Locale &locale, UErrorCode &status);
361    const UChar* getZoneStringFromBundle(const UResourceBundle *zoneitem, const char *key);
362    static UBool isCommonlyUsed(const UResourceBundle *zoneitem);
363    static UnicodeString& getLocalizedCountry(const UnicodeString &countryCode, const Locale &locale,
364        UnicodeString &displayCountry);
365};
366
367inline UnicodeString&
368ZoneStringFormat::getLongStandard(const UnicodeString &tzid, UDate date,
369                                  UnicodeString &result) const {
370    return getString(tzid, ZSIDX_LONG_STANDARD, date, FALSE /* not used */, result);
371}
372
373inline UnicodeString&
374ZoneStringFormat::getLongDaylight(const UnicodeString &tzid, UDate date,
375                                  UnicodeString &result) const {
376    return getString(tzid, ZSIDX_LONG_DAYLIGHT, date, FALSE /* not used */, result);
377}
378
379inline UnicodeString&
380ZoneStringFormat::getLongGenericNonLocation(const UnicodeString &tzid, UDate date,
381                                            UnicodeString &result) const {
382    return getString(tzid, ZSIDX_LONG_GENERIC, date, FALSE /* not used */, result);
383}
384
385inline UnicodeString&
386ZoneStringFormat::getLongGenericPartialLocation(const UnicodeString &tzid, UDate date,
387                                                UnicodeString &result) const {
388    return getGenericPartialLocationString(tzid, FALSE, date, FALSE /* not used */, result);
389}
390
391inline UnicodeString&
392ZoneStringFormat::getShortStandard(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
393                                   UnicodeString &result) const {
394    return getString(tzid, ZSIDX_SHORT_STANDARD, date, commonlyUsedOnly, result);
395}
396
397inline UnicodeString&
398ZoneStringFormat::getShortDaylight(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
399                                   UnicodeString &result) const {
400    return getString(tzid, ZSIDX_SHORT_DAYLIGHT, date, commonlyUsedOnly, result);
401}
402
403inline UnicodeString&
404ZoneStringFormat::getShortGenericNonLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
405                                             UnicodeString &result) const {
406    return getString(tzid, ZSIDX_SHORT_GENERIC, date, commonlyUsedOnly, result);
407}
408
409inline UnicodeString&
410ZoneStringFormat::getShortGenericPartialLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
411                                                 UnicodeString &result) const {
412    return getGenericPartialLocationString(tzid, TRUE, date, commonlyUsedOnly, result);
413}
414
415inline UnicodeString&
416ZoneStringFormat::getGenericLocation(const UnicodeString &tzid, UnicodeString &result) const {
417    return getString(tzid, ZSIDX_LOCATION, 0 /*not used*/, FALSE /*not used*/, result);
418}
419
420
421/*
422 * ZoneStrings is a container of localized zone strings used by ZoneStringFormat
423 */
424class ZoneStrings : public UMemory {
425public:
426    ZoneStrings(UnicodeString *strings,
427                int32_t        stringsCount,
428                UBool          commonlyUsed,
429                UnicodeString **genericPartialLocationStrings,
430                int32_t        genericRowCount,
431                int32_t        genericColCount,
432                ZSFStringPool &sp,
433                UErrorCode    &status);
434    virtual         ~ZoneStrings();
435
436    UnicodeString&   getString(int32_t typeIdx, UnicodeString &result) const;
437    inline UBool     isShortFormatCommonlyUsed(void) const;
438    UnicodeString&   getGenericPartialLocationString(const UnicodeString &mzid, UBool isShort,
439                                        UBool commonlyUsedOnly, UnicodeString &result) const;
440
441private:
442    const UChar   **fStrings;
443    int32_t         fStringsCount;
444    UBool           fIsCommonlyUsed;
445    const UChar * **fGenericPartialLocationStrings;
446    int32_t         fGenericPartialLocationRowCount;
447    int32_t         fGenericPartialLocationColCount;
448};
449
450inline UBool
451ZoneStrings::isShortFormatCommonlyUsed(void) const {
452    return fIsCommonlyUsed;
453}
454
455/*
456 * ZoneStringSearchResultHandler is an implementation of
457 * TextTrieMapSearchHandler.  This class is used by ZoneStringFormat
458 * for collecting search results for localized zone strings.
459 */
460class ZoneStringSearchResultHandler : public TextTrieMapSearchResultHandler {
461public:
462    ZoneStringSearchResultHandler(UErrorCode &status);
463    virtual ~ZoneStringSearchResultHandler();
464
465    virtual UBool handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status);
466    int32_t countMatches(void);
467    const ZoneStringInfo* getMatch(int32_t index, int32_t &matchLength);
468    void clear(void);
469
470private:
471    UVector fResults;
472    int32_t fMatchLen[ZSIDX_COUNT];
473};
474
475
476/*
477 * ZoneStringFormat cache implementation
478 */
479class ZSFCacheEntry : public UMemory {
480public:
481    ~ZSFCacheEntry();
482
483    void delRef(void);
484    const ZoneStringFormat* getZoneStringFormat(void);
485
486private:
487    friend class ZSFCache;
488
489    ZSFCacheEntry(const Locale &locale, ZoneStringFormat *zsf, ZSFCacheEntry *next);
490
491    Locale              fLocale;
492    ZoneStringFormat    *fZoneStringFormat;
493    ZSFCacheEntry       *fNext;
494    int32_t             fRefCount;
495};
496
497class SafeZoneStringFormatPtr : public UMemory {
498public:
499    ~SafeZoneStringFormatPtr();
500    const ZoneStringFormat* get() const;
501
502private:
503    friend class ZSFCache;
504
505    SafeZoneStringFormatPtr(ZSFCacheEntry *cacheEntry);
506
507    ZSFCacheEntry   *fCacheEntry;
508};
509
510class ZSFCache : public UMemory {
511public:
512    ZSFCache(int32_t capacity);
513    ~ZSFCache();
514
515    SafeZoneStringFormatPtr* get(const Locale &locale, UErrorCode &status);
516
517private:
518    int32_t         fCapacity;
519    ZSFCacheEntry   *fFirst;
520};
521
522U_NAMESPACE_END
523
524#endif /* #if !UCONFIG_NO_FORMATTING */
525
526#endif // ZSTRFMT_H
527