1b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho/*
2b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho*******************************************************************************
38393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius* Copyright (C) 2011-2013, International Business Machines Corporation and
4103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius* others. All Rights Reserved.
5b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho*******************************************************************************
6b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho*/
7b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
8b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "unicode/utypes.h"
9b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
10b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#if !UCONFIG_NO_FORMATTING
11b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
12b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "tzgnames.h"
13b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
14b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "unicode/basictz.h"
15b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "unicode/locdspnm.h"
16b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "unicode/msgfmt.h"
17b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "unicode/rbtz.h"
18b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "unicode/simpletz.h"
19b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "unicode/vtzone.h"
20b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
21b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "cmemory.h"
22b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "cstring.h"
23b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "uhash.h"
24b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "uassert.h"
25b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "umutex.h"
26b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "uresimp.h"
27b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "ureslocs.h"
28b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "zonemeta.h"
29b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "tznames_impl.h"
30b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "olsontz.h"
31103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius#include "ucln_in.h"
32b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
33b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoU_NAMESPACE_BEGIN
34b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
35b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#define ZID_KEY_MAX  128
36b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
37b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic const char gZoneStrings[]                = "zoneStrings";
38b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
39b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic const char gRegionFormatTag[]            = "regionFormat";
40b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic const char gFallbackRegionFormatTag[]    = "fallbackRegionFormat";
41b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic const char gFallbackFormatTag[]          = "fallbackFormat";
42b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
43b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic const UChar gEmpty[]                     = {0x00};
44b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
45b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic const UChar gDefRegionPattern[]          = {0x7B, 0x30, 0x7D, 0x00}; // "{0}"
46b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic const UChar gDefFallbackRegionPattern[]  = {0x7B, 0x31, 0x7D, 0x20, 0x28, 0x7B, 0x30, 0x7D, 0x29, 0x00}; // "{1} ({0})"
47b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic const UChar gDefFallbackPattern[]        = {0x7B, 0x31, 0x7D, 0x20, 0x28, 0x7B, 0x30, 0x7D, 0x29, 0x00}; // "{1} ({0})"
48b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
49b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic const double kDstCheckRange      = (double)184*U_MILLIS_PER_DAY;
50b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
51b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
52b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
53b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoU_CDECL_BEGIN
54b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
55b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehotypedef struct PartialLocationKey {
56b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    const UChar* tzID;
57b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    const UChar* mzID;
58b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UBool isLong;
59b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho} PartialLocationKey;
60b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
61b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho/**
62b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho * Hash function for partial location name hash key
63b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho */
64b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic int32_t U_CALLCONV
65b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehohashPartialLocationKey(const UHashTok key) {
66b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // <tzID>&<mzID>#[L|S]
67b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    PartialLocationKey *p = (PartialLocationKey *)key.pointer;
68b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UnicodeString str(p->tzID);
69b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    str.append((UChar)0x26)
70103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        .append(p->mzID, -1)
71b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        .append((UChar)0x23)
72b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        .append((UChar)(p->isLong ? 0x4C : 0x53));
73103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    return str.hashCode();
74b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
75b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
76b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho/**
77b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho * Comparer for partial location name hash key
78b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho */
79b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic UBool U_CALLCONV
80b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehocomparePartialLocationKey(const UHashTok key1, const UHashTok key2) {
81b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    PartialLocationKey *p1 = (PartialLocationKey *)key1.pointer;
82b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    PartialLocationKey *p2 = (PartialLocationKey *)key2.pointer;
83b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
84b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (p1 == p2) {
85b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return TRUE;
86b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
87b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (p1 == NULL || p2 == NULL) {
88b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return FALSE;
89b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
90b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // We just check identity of tzID/mzID
91b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return (p1->tzID == p2->tzID && p1->mzID == p2->mzID && p1->isLong == p2->isLong);
92b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
93b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
94b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho/**
95b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho * Deleter for GNameInfo
96b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho */
97b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic void U_CALLCONV
98b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehodeleteGNameInfo(void *obj) {
99b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    uprv_free(obj);
100b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
101b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
102b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho/**
103b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho * GNameInfo stores zone name information in the local trie
104b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho */
105b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehotypedef struct GNameInfo {
106b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UTimeZoneGenericNameType    type;
107b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    const UChar*                tzID;
108b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho} ZNameInfo;
109b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
110b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho/**
111b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho * GMatchInfo stores zone name match information used by find method
112b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho */
113b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehotypedef struct GMatchInfo {
114b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    const GNameInfo*    gnameInfo;
115b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    int32_t             matchLength;
116103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    UTimeZoneFormatTimeType   timeType;
117b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho} ZMatchInfo;
118b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
119b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoU_CDECL_END
120b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
121b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho// ---------------------------------------------------
122b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho// The class stores time zone generic name match information
123b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho// ---------------------------------------------------
124103e9ffba2cba345d0078eb8b8db33249f81840aCraig Corneliusclass TimeZoneGenericNameMatchInfo : public UMemory {
125103e9ffba2cba345d0078eb8b8db33249f81840aCraig Corneliuspublic:
126103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    TimeZoneGenericNameMatchInfo(UVector* matches);
127103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    ~TimeZoneGenericNameMatchInfo();
128103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
129103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    int32_t size() const;
130103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    UTimeZoneGenericNameType getGenericNameType(int32_t index) const;
131103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    int32_t getMatchLength(int32_t index) const;
132103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    UnicodeString& getTimeZoneID(int32_t index, UnicodeString& tzID) const;
133103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
134103e9ffba2cba345d0078eb8b8db33249f81840aCraig Corneliusprivate:
135103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    UVector* fMatches;  // vector of MatchEntry
136103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius};
137103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
138b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoTimeZoneGenericNameMatchInfo::TimeZoneGenericNameMatchInfo(UVector* matches)
139b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho: fMatches(matches) {
140b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
141b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
142b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoTimeZoneGenericNameMatchInfo::~TimeZoneGenericNameMatchInfo() {
143b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (fMatches != NULL) {
144b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        delete fMatches;
145b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
146b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
147b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
148b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoint32_t
149b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoTimeZoneGenericNameMatchInfo::size() const {
150b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (fMatches == NULL) {
151b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return 0;
152b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
153b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return fMatches->size();
154b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
155b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
156b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoUTimeZoneGenericNameType
157b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoTimeZoneGenericNameMatchInfo::getGenericNameType(int32_t index) const {
158b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    GMatchInfo *minfo = (GMatchInfo *)fMatches->elementAt(index);
159b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (minfo != NULL) {
160b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return static_cast<UTimeZoneGenericNameType>(minfo->gnameInfo->type);
161b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
162b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return UTZGNM_UNKNOWN;
163b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
164b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
165b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoint32_t
166b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoTimeZoneGenericNameMatchInfo::getMatchLength(int32_t index) const {
167b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    ZMatchInfo *minfo = (ZMatchInfo *)fMatches->elementAt(index);
168b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (minfo != NULL) {
169b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return minfo->matchLength;
170b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
171b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return -1;
172b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
173b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
174b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoUnicodeString&
175b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoTimeZoneGenericNameMatchInfo::getTimeZoneID(int32_t index, UnicodeString& tzID) const {
176b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    GMatchInfo *minfo = (GMatchInfo *)fMatches->elementAt(index);
177b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (minfo != NULL && minfo->gnameInfo->tzID != NULL) {
178b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        tzID.setTo(TRUE, minfo->gnameInfo->tzID, -1);
179b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    } else {
180b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        tzID.setToBogus();
181b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
182b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return tzID;
183b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
184b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
185b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho// ---------------------------------------------------
186b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho// GNameSearchHandler
187b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho// ---------------------------------------------------
188b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoclass GNameSearchHandler : public TextTrieMapSearchResultHandler {
189b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehopublic:
190b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    GNameSearchHandler(uint32_t types);
191b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    virtual ~GNameSearchHandler();
192b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
193b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UBool handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status);
194b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UVector* getMatches(int32_t& maxMatchLen);
195b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
196b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoprivate:
197b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    uint32_t fTypes;
198b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UVector* fResults;
199b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    int32_t fMaxMatchLen;
200b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho};
201b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
202b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoGNameSearchHandler::GNameSearchHandler(uint32_t types)
203b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho: fTypes(types), fResults(NULL), fMaxMatchLen(0) {
204b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
205b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
206b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoGNameSearchHandler::~GNameSearchHandler() {
207b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (fResults != NULL) {
208b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        delete fResults;
209b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
210b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
211b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
212b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoUBool
213b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoGNameSearchHandler::handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status) {
214b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (U_FAILURE(status)) {
215b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return FALSE;
216b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
217b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (node->hasValues()) {
218b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        int32_t valuesCount = node->countValues();
219b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        for (int32_t i = 0; i < valuesCount; i++) {
220b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            GNameInfo *nameinfo = (ZNameInfo *)node->getValue(i);
221b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (nameinfo == NULL) {
222b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                break;
223b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
224b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if ((nameinfo->type & fTypes) != 0) {
225b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                // matches a requested type
226b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                if (fResults == NULL) {
227103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                    fResults = new UVector(uprv_free, NULL, status);
228b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    if (fResults == NULL) {
229b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        status = U_MEMORY_ALLOCATION_ERROR;
230b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    }
231b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
232b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                if (U_SUCCESS(status)) {
233103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                    U_ASSERT(fResults != NULL);
234b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    GMatchInfo *gmatch = (GMatchInfo *)uprv_malloc(sizeof(GMatchInfo));
235b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    if (gmatch == NULL) {
236b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        status = U_MEMORY_ALLOCATION_ERROR;
237b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    } else {
238b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        // add the match to the vector
239b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        gmatch->gnameInfo = nameinfo;
240b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        gmatch->matchLength = matchLength;
241b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        gmatch->timeType = UTZFMT_TIME_TYPE_UNKNOWN;
242b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        fResults->addElement(gmatch, status);
243b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        if (U_FAILURE(status)) {
244b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            uprv_free(gmatch);
245b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        } else {
246b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            if (matchLength > fMaxMatchLen) {
247b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                                fMaxMatchLen = matchLength;
248b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            }
249b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        }
250b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    }
251b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
252b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
253b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
254b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
255b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return TRUE;
256b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
257b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
258b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoUVector*
259b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoGNameSearchHandler::getMatches(int32_t& maxMatchLen) {
260b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // give the ownership to the caller
261b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UVector *results = fResults;
262b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    maxMatchLen = fMaxMatchLen;
263b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
264b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // reset
265b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    fResults = NULL;
266b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    fMaxMatchLen = 0;
267b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return results;
268b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
269b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
27054dcd9b6a06071f647dac967e9e267abb9410720Craig Corneliusstatic UMutex gLock = U_MUTEX_INITIALIZER;
27154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
272103e9ffba2cba345d0078eb8b8db33249f81840aCraig Corneliusclass TZGNCore : public UMemory {
273103e9ffba2cba345d0078eb8b8db33249f81840aCraig Corneliuspublic:
274103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    TZGNCore(const Locale& locale, UErrorCode& status);
275103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    virtual ~TZGNCore();
276103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
277103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    UnicodeString& getDisplayName(const TimeZone& tz, UTimeZoneGenericNameType type,
278103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                        UDate date, UnicodeString& name) const;
279103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
280103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    UnicodeString& getGenericLocationName(const UnicodeString& tzCanonicalID, UnicodeString& name) const;
281103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
282103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    int32_t findBestMatch(const UnicodeString& text, int32_t start, uint32_t types,
283103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        UnicodeString& tzID, UTimeZoneFormatTimeType& timeType, UErrorCode& status) const;
284103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
285103e9ffba2cba345d0078eb8b8db33249f81840aCraig Corneliusprivate:
286103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    Locale fLocale;
287103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    const TimeZoneNames* fTimeZoneNames;
288103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    UHashtable* fLocationNamesMap;
289103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    UHashtable* fPartialLocationNamesMap;
290103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
291103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    MessageFormat* fRegionFormat;
292103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    MessageFormat* fFallbackFormat;
293103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
294103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    LocaleDisplayNames* fLocaleDisplayNames;
295103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    ZNStringPool fStringPool;
296103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
297103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    TextTrieMap fGNamesTrie;
298103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    UBool fGNamesTrieFullyLoaded;
299103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
300103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    char fTargetRegion[ULOC_COUNTRY_CAPACITY];
301103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
302103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    void initialize(const Locale& locale, UErrorCode& status);
303103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    void cleanup();
304103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
305103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    void loadStrings(const UnicodeString& tzCanonicalID);
306103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
307103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    const UChar* getGenericLocationName(const UnicodeString& tzCanonicalID);
308103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
309103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    UnicodeString& formatGenericNonLocationName(const TimeZone& tz, UTimeZoneGenericNameType type,
310103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                        UDate date, UnicodeString& name) const;
311103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
312103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    UnicodeString& getPartialLocationName(const UnicodeString& tzCanonicalID,
313103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                        const UnicodeString& mzID, UBool isLong, const UnicodeString& mzDisplayName,
314103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                        UnicodeString& name) const;
315103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
316103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    const UChar* getPartialLocationName(const UnicodeString& tzCanonicalID,
317103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                        const UnicodeString& mzID, UBool isLong, const UnicodeString& mzDisplayName);
318103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
319103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    TimeZoneGenericNameMatchInfo* findLocal(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const;
320103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
321103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    TimeZoneNames::MatchInfoCollection* findTimeZoneNames(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const;
322103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius};
323103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
324103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
325b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho// ---------------------------------------------------
326103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius// TZGNCore - core implmentation of TimeZoneGenericNames
327b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho//
328b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho// TimeZoneGenericNames is parallel to TimeZoneNames,
329b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho// but handles run-time generated time zone names.
330b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho// This is the main part of this module.
331b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho// ---------------------------------------------------
332103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusTZGNCore::TZGNCore(const Locale& locale, UErrorCode& status)
333b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho: fLocale(locale),
334b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho  fTimeZoneNames(NULL),
335b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho  fLocationNamesMap(NULL),
336b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho  fPartialLocationNamesMap(NULL),
337b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho  fRegionFormat(NULL),
338b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho  fFallbackFormat(NULL),
339b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho  fLocaleDisplayNames(NULL),
340b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho  fStringPool(status),
341b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho  fGNamesTrie(TRUE, deleteGNameInfo),
342b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho  fGNamesTrieFullyLoaded(FALSE) {
343b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    initialize(locale, status);
344b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
345b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
346103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusTZGNCore::~TZGNCore() {
347b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    cleanup();
348b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
349b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
350b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehovoid
351103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusTZGNCore::initialize(const Locale& locale, UErrorCode& status) {
352b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (U_FAILURE(status)) {
353b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return;
354b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
355b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
356b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // TimeZoneNames
357b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    fTimeZoneNames = TimeZoneNames::createInstance(locale, status);
358b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (U_FAILURE(status)) {
359b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return;
360b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
361b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
362b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // Initialize format patterns
363b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UnicodeString rpat(TRUE, gDefRegionPattern, -1);
364b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UnicodeString frpat(TRUE, gDefFallbackRegionPattern, -1);
365b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UnicodeString fpat(TRUE, gDefFallbackPattern, -1);
366b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
367b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UErrorCode tmpsts = U_ZERO_ERROR;   // OK with fallback warning..
368b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UResourceBundle *zoneStrings = ures_open(U_ICUDATA_ZONE, locale.getName(), &tmpsts);
369b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    zoneStrings = ures_getByKeyWithFallback(zoneStrings, gZoneStrings, zoneStrings, &tmpsts);
370b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
371b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (U_SUCCESS(tmpsts)) {
372b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        const UChar *regionPattern = ures_getStringByKeyWithFallback(zoneStrings, gRegionFormatTag, NULL, &tmpsts);
373b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (U_SUCCESS(tmpsts) && u_strlen(regionPattern) > 0) {
374103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            rpat.setTo(regionPattern, -1);
375b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
376b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        tmpsts = U_ZERO_ERROR;
377b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        const UChar *fallbackRegionPattern = ures_getStringByKeyWithFallback(zoneStrings, gFallbackRegionFormatTag, NULL, &tmpsts);
378b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (U_SUCCESS(tmpsts) && u_strlen(fallbackRegionPattern) > 0) {
379103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            frpat.setTo(fallbackRegionPattern, -1);
380b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
381b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        tmpsts = U_ZERO_ERROR;
382b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        const UChar *fallbackPattern = ures_getStringByKeyWithFallback(zoneStrings, gFallbackFormatTag, NULL, &tmpsts);
383b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (U_SUCCESS(tmpsts) && u_strlen(fallbackPattern) > 0) {
384103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            fpat.setTo(fallbackPattern, -1);
385b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
386b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
387b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    ures_close(zoneStrings);
388b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
389b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    fRegionFormat = new MessageFormat(rpat, status);
390b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (fRegionFormat == NULL) {
391b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        status = U_MEMORY_ALLOCATION_ERROR;
392b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
393b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    fFallbackFormat = new MessageFormat(fpat, status);
394b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (fFallbackFormat == NULL) {
395b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        status = U_MEMORY_ALLOCATION_ERROR;
396b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
397b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (U_FAILURE(status)) {
398b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        cleanup();
399b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return;
400b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
401b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
402b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // locale display names
403b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    fLocaleDisplayNames = LocaleDisplayNames::createInstance(locale);
404b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
405b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // hash table for names - no key/value deleters
406b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    fLocationNamesMap = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
407b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (U_FAILURE(status)) {
408b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        cleanup();
409b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return;
410b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
411b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
412b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    fPartialLocationNamesMap = uhash_open(hashPartialLocationKey, comparePartialLocationKey, NULL, &status);
413b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (U_FAILURE(status)) {
414b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        cleanup();
415b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return;
416b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
417103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    uhash_setKeyDeleter(fPartialLocationNamesMap, uprv_free);
418b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // no value deleter
419b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
420b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // target region
421b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    const char* region = fLocale.getCountry();
422b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    int32_t regionLen = uprv_strlen(region);
423b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (regionLen == 0) {
424b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        char loc[ULOC_FULLNAME_CAPACITY];
425b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        uloc_addLikelySubtags(fLocale.getName(), loc, sizeof(loc), &status);
426b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
427b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        regionLen = uloc_getCountry(loc, fTargetRegion, sizeof(fTargetRegion), &status);
428b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (U_SUCCESS(status)) {
429b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            fTargetRegion[regionLen] = 0;
430b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        } else {
431b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            cleanup();
432b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            return;
433b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
434b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    } else if (regionLen < (int32_t)sizeof(fTargetRegion)) {
435b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        uprv_strcpy(fTargetRegion, region);
436b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    } else {
437b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        fTargetRegion[0] = 0;
438b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
439b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
440b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // preload generic names for the default zone
441b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    TimeZone *tz = TimeZone::createDefault();
442b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    const UChar *tzID = ZoneMeta::getCanonicalCLDRID(*tz);
443b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (tzID != NULL) {
444b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        loadStrings(UnicodeString(tzID));
445b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
446b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    delete tz;
447b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
448b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
449b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehovoid
450103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusTZGNCore::cleanup() {
451b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (fRegionFormat != NULL) {
452b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        delete fRegionFormat;
453b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
454b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (fFallbackFormat != NULL) {
455b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        delete fFallbackFormat;
456b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
457b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (fLocaleDisplayNames != NULL) {
458b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        delete fLocaleDisplayNames;
459b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
460b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (fTimeZoneNames != NULL) {
461b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        delete fTimeZoneNames;
462b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
463b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
464b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    uhash_close(fLocationNamesMap);
465b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    uhash_close(fPartialLocationNamesMap);
466b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
467b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
468103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
469b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoUnicodeString&
470103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusTZGNCore::getDisplayName(const TimeZone& tz, UTimeZoneGenericNameType type, UDate date, UnicodeString& name) const {
471b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    name.setToBogus();
472b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    switch (type) {
473b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    case UTZGNM_LOCATION:
474b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        {
475b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            const UChar* tzCanonicalID = ZoneMeta::getCanonicalCLDRID(tz);
476b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (tzCanonicalID != NULL) {
477b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                getGenericLocationName(UnicodeString(tzCanonicalID), name);
478b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
479b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
480b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        break;
481b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    case UTZGNM_LONG:
482b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    case UTZGNM_SHORT:
483b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        formatGenericNonLocationName(tz, type, date, name);
484b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (name.isEmpty()) {
485b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            const UChar* tzCanonicalID = ZoneMeta::getCanonicalCLDRID(tz);
486b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (tzCanonicalID != NULL) {
487b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                getGenericLocationName(UnicodeString(tzCanonicalID), name);
488b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
489b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
490b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        break;
491b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    default:
492b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        break;
493b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
494b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return name;
495b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
496b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
497b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoUnicodeString&
498103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusTZGNCore::getGenericLocationName(const UnicodeString& tzCanonicalID, UnicodeString& name) const {
499b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (tzCanonicalID.isEmpty()) {
500b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        name.setToBogus();
501b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return name;
502b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
503b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
504b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    const UChar *locname = NULL;
505103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    TZGNCore *nonConstThis = const_cast<TZGNCore *>(this);
50654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    umtx_lock(&gLock);
507b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    {
508b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        locname = nonConstThis->getGenericLocationName(tzCanonicalID);
509b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
51054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    umtx_unlock(&gLock);
511b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
512b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (locname == NULL) {
513b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        name.setToBogus();
514b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    } else {
515103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        name.setTo(locname, u_strlen(locname));
516b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
517b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
518b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return name;
519b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
520b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
521b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho/*
522b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho * This method updates the cache and must be called with a lock
523b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho */
524b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoconst UChar*
525103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusTZGNCore::getGenericLocationName(const UnicodeString& tzCanonicalID) {
526b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    U_ASSERT(!tzCanonicalID.isEmpty());
527b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (tzCanonicalID.length() > ZID_KEY_MAX) {
528b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return NULL;
529b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
530b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
531b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UErrorCode status = U_ZERO_ERROR;
532b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UChar tzIDKey[ZID_KEY_MAX + 1];
533b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    int32_t tzIDKeyLen = tzCanonicalID.extract(tzIDKey, ZID_KEY_MAX + 1, status);
534b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    U_ASSERT(status == U_ZERO_ERROR);   // already checked length above
535b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    tzIDKey[tzIDKeyLen] = 0;
536b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
537b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    const UChar *locname = (const UChar *)uhash_get(fLocationNamesMap, tzIDKey);
538b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
539b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (locname != NULL) {
540b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        // gEmpty indicate the name is not available
541b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (locname == gEmpty) {
542b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            return NULL;
543b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
544b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return locname;
545b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
546b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
547b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // Construct location name
548b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UnicodeString name;
549b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UnicodeString usCountryCode;
5508393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    UBool isPrimary = FALSE;
5518393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
5528393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    ZoneMeta::getCanonicalCountry(tzCanonicalID, usCountryCode, &isPrimary);
553b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
554b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (!usCountryCode.isEmpty()) {
5558393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        FieldPosition fpos;
556b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
5578393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        if (isPrimary) {
5588393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            // If this is the primary zone in the country, use the country name.
5598393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            char countryCode[ULOC_COUNTRY_CAPACITY];
5608393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            U_ASSERT(usCountryCode.length() < ULOC_COUNTRY_CAPACITY);
5618393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            int32_t ccLen = usCountryCode.extract(0, usCountryCode.length(), countryCode, sizeof(countryCode), US_INV);
5628393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            countryCode[ccLen] = 0;
5638393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
5648393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            UnicodeString country;
5658393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            fLocaleDisplayNames->regionDisplayName(countryCode, country);
566b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
567b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            Formattable param[] = {
568b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                Formattable(country)
569b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            };
5708393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
571b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            fRegionFormat->format(param, 1, name, fpos, status);
572b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        } else {
5738393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            // If this is not the primary zone in the country,
5748393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            // use the exemplar city name.
57554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
576b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            // getExemplarLocationName should retur non-empty string
577b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            // if the time zone is associated with a region
57854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
579b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            UnicodeString city;
580b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            fTimeZoneNames->getExemplarLocationName(tzCanonicalID, city);
581b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
58254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            Formattable param[] = {
583b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                Formattable(city),
584b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            };
5858393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
58654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            fRegionFormat->format(param, 1, name, fpos, status);
587b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
588b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (U_FAILURE(status)) {
589b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            return NULL;
590b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
591b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
592b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
593b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    locname = name.isEmpty() ? NULL : fStringPool.get(name, status);
594b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (U_SUCCESS(status)) {
595b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        // Cache the result
596b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        const UChar* cacheID = ZoneMeta::findTimeZoneID(tzCanonicalID);
597b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        U_ASSERT(cacheID != NULL);
598b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (locname == NULL) {
599b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            // gEmpty to indicate - no location name available
600b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            uhash_put(fLocationNamesMap, (void *)cacheID, (void *)gEmpty, &status);
601b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        } else {
602b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            uhash_put(fLocationNamesMap, (void *)cacheID, (void *)locname, &status);
603b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (U_FAILURE(status)) {
604b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                locname = NULL;
605b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            } else {
606b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                // put the name info into the trie
607b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                GNameInfo *nameinfo = (ZNameInfo *)uprv_malloc(sizeof(GNameInfo));
608b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                if (nameinfo != NULL) {
609b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    nameinfo->type = UTZGNM_LOCATION;
610b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    nameinfo->tzID = cacheID;
611b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    fGNamesTrie.put(locname, nameinfo, status);
612b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
613b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
614b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
615b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
616b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
617b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return locname;
618b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
619b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
620b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoUnicodeString&
621103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusTZGNCore::formatGenericNonLocationName(const TimeZone& tz, UTimeZoneGenericNameType type, UDate date, UnicodeString& name) const {
622b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    U_ASSERT(type == UTZGNM_LONG || type == UTZGNM_SHORT);
623b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    name.setToBogus();
624b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
625b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    const UChar* uID = ZoneMeta::getCanonicalCLDRID(tz);
626b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (uID == NULL) {
627b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return name;
628b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
629b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
630b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UnicodeString tzID(uID);
631b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
632b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // Try to get a name from time zone first
633b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UTimeZoneNameType nameType = (type == UTZGNM_LONG) ? UTZNM_LONG_GENERIC : UTZNM_SHORT_GENERIC;
634b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    fTimeZoneNames->getTimeZoneDisplayName(tzID, nameType, name);
635b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
636b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (!name.isEmpty()) {
637b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return name;
638b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
639b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
640b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // Try meta zone
641b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UnicodeString mzID;
642b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    fTimeZoneNames->getMetaZoneID(tzID, date, mzID);
643b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (!mzID.isEmpty()) {
644b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        UErrorCode status = U_ZERO_ERROR;
645b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        UBool useStandard = FALSE;
646b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        int32_t raw, sav;
647b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
648b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        tz.getOffset(date, FALSE, raw, sav, status);
649b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (U_FAILURE(status)) {
650b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            return name;
651b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
652b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
653b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (sav == 0) {
654b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            useStandard = TRUE;
655b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
656b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            TimeZone *tmptz = tz.clone();
657b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            // Check if the zone actually uses daylight saving time around the time
658b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            BasicTimeZone *btz = NULL;
659b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (dynamic_cast<OlsonTimeZone *>(tmptz) != NULL
660b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                || dynamic_cast<SimpleTimeZone *>(tmptz) != NULL
661b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                || dynamic_cast<RuleBasedTimeZone *>(tmptz) != NULL
662b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                || dynamic_cast<VTimeZone *>(tmptz) != NULL) {
663b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                btz = (BasicTimeZone*)tmptz;
664b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
665b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
666b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (btz != NULL) {
667b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                TimeZoneTransition before;
668b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                UBool beforTrs = btz->getPreviousTransition(date, TRUE, before);
669b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                if (beforTrs
670b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        && (date - before.getTime() < kDstCheckRange)
671b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        && before.getFrom()->getDSTSavings() != 0) {
672b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    useStandard = FALSE;
673b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                } else {
674b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    TimeZoneTransition after;
675b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    UBool afterTrs = btz->getNextTransition(date, FALSE, after);
676b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    if (afterTrs
677b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            && (after.getTime() - date < kDstCheckRange)
678b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            && after.getTo()->getDSTSavings() != 0) {
679b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        useStandard = FALSE;
680b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    }
681b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
682b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            } else {
683b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                // If not BasicTimeZone... only if the instance is not an ICU's implementation.
684b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                // We may get a wrong answer in edge case, but it should practically work OK.
685b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                tmptz->getOffset(date - kDstCheckRange, FALSE, raw, sav, status);
686b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                if (sav != 0) {
687b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    useStandard = FALSE;
688b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                } else {
689b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    tmptz->getOffset(date + kDstCheckRange, FALSE, raw, sav, status);
690b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    if (sav != 0){
691b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        useStandard = FALSE;
692b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    }
693b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
694b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                if (U_FAILURE(status)) {
695b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    delete tmptz;
696b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    return name;
697b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
698b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
699b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            delete tmptz;
700b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
701b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (useStandard) {
702b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            UTimeZoneNameType stdNameType = (nameType == UTZNM_LONG_GENERIC)
703103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                ? UTZNM_LONG_STANDARD : UTZNM_SHORT_STANDARD;
704b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            UnicodeString stdName;
705b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            fTimeZoneNames->getDisplayName(tzID, stdNameType, date, stdName);
706b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (!stdName.isEmpty()) {
707b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                name.setTo(stdName);
708b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
709b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                // TODO: revisit this issue later
710b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                // In CLDR, a same display name is used for both generic and standard
711b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                // for some meta zones in some locales.  This looks like a data bugs.
712b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                // For now, we check if the standard name is different from its generic
713b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                // name below.
714b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                UnicodeString mzGenericName;
715b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                fTimeZoneNames->getMetaZoneDisplayName(mzID, nameType, mzGenericName);
716b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                if (stdName.caseCompare(mzGenericName, 0) == 0) {
717b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    name.setToBogus();
718b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
719b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
720b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
721b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (name.isEmpty()) {
722b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            // Get a name from meta zone
723b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            UnicodeString mzName;
724b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            fTimeZoneNames->getMetaZoneDisplayName(mzID, nameType, mzName);
725b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (!mzName.isEmpty()) {
726b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                // Check if we need to use a partial location format.
727b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                // This check is done by comparing offset with the meta zone's
728b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                // golden zone at the given date.
729b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                UnicodeString goldenID;
730b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                fTimeZoneNames->getReferenceZoneID(mzID, fTargetRegion, goldenID);
731b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                if (!goldenID.isEmpty() && goldenID != tzID) {
732b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    TimeZone *goldenZone = TimeZone::createTimeZone(goldenID);
733b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    int32_t raw1, sav1;
734b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
735b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    // Check offset in the golden zone with wall time.
736b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    // With getOffset(date, false, offsets1),
737b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    // you may get incorrect results because of time overlap at DST->STD
738b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    // transition.
739b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    goldenZone->getOffset(date + raw + sav, TRUE, raw1, sav1, status);
740b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    delete goldenZone;
741b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    if (U_SUCCESS(status)) {
742b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        if (raw != raw1 || sav != sav1) {
743b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            // Now we need to use a partial location format
744b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            getPartialLocationName(tzID, mzID, (nameType == UTZNM_LONG_GENERIC), mzName, name);
745b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        } else {
746b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            name.setTo(mzName);
747b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        }
748b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    }
749b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                } else {
750b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    name.setTo(mzName);
751b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
752b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
753b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
754b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
755b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return name;
756b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
757b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
758b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoUnicodeString&
759103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusTZGNCore::getPartialLocationName(const UnicodeString& tzCanonicalID,
760b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        const UnicodeString& mzID, UBool isLong, const UnicodeString& mzDisplayName,
761b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        UnicodeString& name) const {
762b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    name.setToBogus();
763b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (tzCanonicalID.isEmpty() || mzID.isEmpty() || mzDisplayName.isEmpty()) {
764b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return name;
765b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
766b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
767b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    const UChar *uplname = NULL;
768103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    TZGNCore *nonConstThis = const_cast<TZGNCore *>(this);
76954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    umtx_lock(&gLock);
770b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    {
771b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        uplname = nonConstThis->getPartialLocationName(tzCanonicalID, mzID, isLong, mzDisplayName);
772b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
77354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    umtx_unlock(&gLock);
774b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
775b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (uplname == NULL) {
776b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        name.setToBogus();
777b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    } else {
778b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        name.setTo(TRUE, uplname, -1);
779b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
780b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return name;
781b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
782b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
783b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho/*
784b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho * This method updates the cache and must be called with a lock
785b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho */
786b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoconst UChar*
787103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusTZGNCore::getPartialLocationName(const UnicodeString& tzCanonicalID,
788b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        const UnicodeString& mzID, UBool isLong, const UnicodeString& mzDisplayName) {
789b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    U_ASSERT(!tzCanonicalID.isEmpty());
790b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    U_ASSERT(!mzID.isEmpty());
791b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    U_ASSERT(!mzDisplayName.isEmpty());
792b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
793b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    PartialLocationKey key;
794b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    key.tzID = ZoneMeta::findTimeZoneID(tzCanonicalID);
795b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    key.mzID = ZoneMeta::findMetaZoneID(mzID);
796b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    key.isLong = isLong;
797b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    U_ASSERT(key.tzID != NULL && key.mzID != NULL);
798b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
799b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    const UChar* uplname = (const UChar*)uhash_get(fPartialLocationNamesMap, (void *)&key);
800b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (uplname != NULL) {
801b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return uplname;
802b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
803b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
804b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UnicodeString location;
805b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UnicodeString usCountryCode;
806b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    ZoneMeta::getCanonicalCountry(tzCanonicalID, usCountryCode);
807b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (!usCountryCode.isEmpty()) {
808b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        char countryCode[ULOC_COUNTRY_CAPACITY];
809b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        U_ASSERT(usCountryCode.length() < ULOC_COUNTRY_CAPACITY);
810b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        int32_t ccLen = usCountryCode.extract(0, usCountryCode.length(), countryCode, sizeof(countryCode), US_INV);
811b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        countryCode[ccLen] = 0;
812b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
813b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        UnicodeString regionalGolden;
814b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        fTimeZoneNames->getReferenceZoneID(mzID, countryCode, regionalGolden);
815b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (tzCanonicalID == regionalGolden) {
816b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            // Use country name
817b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            fLocaleDisplayNames->regionDisplayName(countryCode, location);
818b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        } else {
819b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            // Otherwise, use exemplar city name
820b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            fTimeZoneNames->getExemplarLocationName(tzCanonicalID, location);
821b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
822b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    } else {
823b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        fTimeZoneNames->getExemplarLocationName(tzCanonicalID, location);
824b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (location.isEmpty()) {
825b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            // This could happen when the time zone is not associated with a country,
826b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            // and its ID is not hierarchical, for example, CST6CDT.
827b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            // We use the canonical ID itself as the location for this case.
828b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            location.setTo(tzCanonicalID);
829b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
830b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
831b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
832b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UErrorCode status = U_ZERO_ERROR;
833b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UnicodeString name;
834b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
835b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    FieldPosition fpos;
836b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    Formattable param[] = {
837b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        Formattable(location),
838b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        Formattable(mzDisplayName)
839b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    };
840b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    fFallbackFormat->format(param, 2, name, fpos, status);
841b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (U_FAILURE(status)) {
842b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return NULL;
843b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
844b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
845b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    uplname = fStringPool.get(name, status);
846b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (U_SUCCESS(status)) {
847b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        // Add the name to cache
848b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        PartialLocationKey* cacheKey = (PartialLocationKey *)uprv_malloc(sizeof(PartialLocationKey));
849b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (cacheKey != NULL) {
850b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            cacheKey->tzID = key.tzID;
851b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            cacheKey->mzID = key.mzID;
852b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            cacheKey->isLong = key.isLong;
853b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            uhash_put(fPartialLocationNamesMap, (void *)cacheKey, (void *)uplname, &status);
854b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (U_FAILURE(status)) {
855b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                uprv_free(cacheKey);
856b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            } else {
857b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                // put the name to the local trie as well
858b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                GNameInfo *nameinfo = (ZNameInfo *)uprv_malloc(sizeof(GNameInfo));
859b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                if (nameinfo != NULL) {
860b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    nameinfo->type = isLong ? UTZGNM_LONG : UTZGNM_SHORT;
861b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    nameinfo->tzID = key.tzID;
862b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    fGNamesTrie.put(uplname, nameinfo, status);
863b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
864b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
865b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
866b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
867b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return uplname;
868b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
869b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
870b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho/*
871b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho * This method updates the cache and must be called with a lock,
872b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho * except initializer.
873b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho */
874b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehovoid
875103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusTZGNCore::loadStrings(const UnicodeString& tzCanonicalID) {
876b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // load the generic location name
877b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    getGenericLocationName(tzCanonicalID);
878b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
879b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // partial location names
880b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UErrorCode status = U_ZERO_ERROR;
881b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
882b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    const UnicodeString *mzID;
883b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UnicodeString goldenID;
884b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UnicodeString mzGenName;
885b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UTimeZoneNameType genNonLocTypes[] = {
886b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        UTZNM_LONG_GENERIC, UTZNM_SHORT_GENERIC,
887b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        UTZNM_UNKNOWN /*terminator*/
888b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    };
889b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
890b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    StringEnumeration *mzIDs = fTimeZoneNames->getAvailableMetaZoneIDs(tzCanonicalID, status);
891b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    while ((mzID = mzIDs->snext(status))) {
892b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (U_FAILURE(status)) {
893b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            break;
894b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
895b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        // if this time zone is not the golden zone of the meta zone,
896b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        // partial location name (such as "PT (Los Angeles)") might be
897b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        // available.
898b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        fTimeZoneNames->getReferenceZoneID(*mzID, fTargetRegion, goldenID);
899b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (tzCanonicalID != goldenID) {
900b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            for (int32_t i = 0; genNonLocTypes[i] != UTZNM_UNKNOWN; i++) {
901b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                fTimeZoneNames->getMetaZoneDisplayName(*mzID, genNonLocTypes[i], mzGenName);
902b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                if (!mzGenName.isEmpty()) {
903b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    // getPartialLocationName formats a name and put it into the trie
904b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    getPartialLocationName(tzCanonicalID, *mzID,
905b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        (genNonLocTypes[i] == UTZNM_LONG_GENERIC), mzGenName);
906b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
907b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
908b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
909b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
910b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (mzIDs != NULL) {
911b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        delete mzIDs;
912b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
913b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
914b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
915b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoint32_t
916103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusTZGNCore::findBestMatch(const UnicodeString& text, int32_t start, uint32_t types,
917103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        UnicodeString& tzID, UTimeZoneFormatTimeType& timeType, UErrorCode& status) const {
918b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    timeType = UTZFMT_TIME_TYPE_UNKNOWN;
919b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    tzID.setToBogus();
920b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
921b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (U_FAILURE(status)) {
922b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return 0;
923b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
924b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
925b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // Find matches in the TimeZoneNames first
926103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    TimeZoneNames::MatchInfoCollection *tznamesMatches = findTimeZoneNames(text, start, types, status);
927b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (U_FAILURE(status)) {
928b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return 0;
929b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
930b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
931b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    int32_t bestMatchLen = 0;
932103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    UTimeZoneFormatTimeType bestMatchTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
933b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UnicodeString bestMatchTzID;
934103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    // UBool isLongStandard = FALSE;   // workaround - see the comments below
935103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    UBool isStandard = FALSE;       // TODO: Temporary hack (on hack) for short standard name/location name conflict (found in zh_Hant), should be removed after CLDR 21m1 integration
936b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
937b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (tznamesMatches != NULL) {
938b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        UnicodeString mzID;
939b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        for (int32_t i = 0; i < tznamesMatches->size(); i++) {
940103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            int32_t len = tznamesMatches->getMatchLengthAt(i);
941b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (len > bestMatchLen) {
942b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                bestMatchLen = len;
943103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                if (!tznamesMatches->getTimeZoneIDAt(i, bestMatchTzID)) {
944b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    // name for a meta zone
945103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                    if (tznamesMatches->getMetaZoneIDAt(i, mzID)) {
946103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                        fTimeZoneNames->getReferenceZoneID(mzID, fTargetRegion, bestMatchTzID);
947103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                    }
948103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                }
949103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                UTimeZoneNameType nameType = tznamesMatches->getNameTypeAt(i);
950103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                if (U_FAILURE(status)) {
951103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                    break;
952b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
953b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                switch (nameType) {
954b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                case UTZNM_LONG_STANDARD:
955103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                    // isLongStandard = TRUE;
956103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                case UTZNM_SHORT_STANDARD:  // this one is never used for generic, but just in case
957103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                    isStandard = TRUE;      // TODO: Remove this later, see the comments above.
958b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    bestMatchTimeType = UTZFMT_TIME_TYPE_STANDARD;
959b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    break;
960b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                case UTZNM_LONG_DAYLIGHT:
961b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                case UTZNM_SHORT_DAYLIGHT: // this one is never used for generic, but just in case
962b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    bestMatchTimeType = UTZFMT_TIME_TYPE_DAYLIGHT;
963b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    break;
964b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                default:
965b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    bestMatchTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
966b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
967b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
968b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
969b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        delete tznamesMatches;
970103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        if (U_FAILURE(status)) {
971103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            return 0;
972103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        }
973b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
974b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (bestMatchLen == (text.length() - start)) {
975b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            // Full match
976b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
977b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            //tzID.setTo(bestMatchTzID);
978b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            //timeType = bestMatchTimeType;
979b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            //return bestMatchLen;
980b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
981b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            // TODO Some time zone uses a same name for the long standard name
982b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            // and the location name. When the match is a long standard name,
983b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            // then we need to check if the name is same with the location name.
984b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            // This is probably a data error or a design bug.
985103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius/*
986b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (!isLongStandard) {
987b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                tzID.setTo(bestMatchTzID);
988b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                timeType = bestMatchTimeType;
989b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                return bestMatchLen;
990b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
991103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius*/
992103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            // TODO The deprecation of commonlyUsed flag introduced the name
993103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            // conflict not only for long standard names, but short standard names too.
994103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            // These short names (found in zh_Hant) should be gone once we clean
995103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            // up CLDR time zone display name data. Once the short name conflict
996103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            // problem (with location name) is resolved, we should change the condition
997103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            // below back to the original one above. -Yoshito (2011-09-14)
998103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            if (!isStandard) {
999103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                tzID.setTo(bestMatchTzID);
1000103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                timeType = bestMatchTimeType;
1001103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                return bestMatchLen;
1002103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            }
1003b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
1004b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
1005b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1006b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // Find matches in the local trie
1007b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    TimeZoneGenericNameMatchInfo *localMatches = findLocal(text, start, types, status);
1008b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (U_FAILURE(status)) {
1009b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return 0;
1010b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
1011b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (localMatches != NULL) {
1012b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        for (int32_t i = 0; i < localMatches->size(); i++) {
1013b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            int32_t len = localMatches->getMatchLength(i);
1014b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1015b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            // TODO See the above TODO. We use len >= bestMatchLen
1016b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            // because of the long standard/location name collision
1017b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            // problem. If it is also a location name, carrying
1018b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            // timeType = UTZFMT_TIME_TYPE_STANDARD will cause a
1019b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            // problem in SimpleDateFormat
1020b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (len >= bestMatchLen) {
1021b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                bestMatchLen = localMatches->getMatchLength(i);
1022b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                bestMatchTimeType = UTZFMT_TIME_TYPE_UNKNOWN;   // because generic
1023b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                localMatches->getTimeZoneID(i, bestMatchTzID);
1024b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
1025b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
1026b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        delete localMatches;
1027b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
1028b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1029b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (bestMatchLen > 0) {
1030b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        timeType = bestMatchTimeType;
1031b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        tzID.setTo(bestMatchTzID);
1032b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
1033b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return bestMatchLen;
1034b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
1035b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1036b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoTimeZoneGenericNameMatchInfo*
1037103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusTZGNCore::findLocal(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const {
1038b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    GNameSearchHandler handler(types);
1039b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1040103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    TZGNCore *nonConstThis = const_cast<TZGNCore *>(this);
1041b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
104254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    umtx_lock(&gLock);
1043b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    {
1044b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        fGNamesTrie.search(text, start, (TextTrieMapSearchResultHandler *)&handler, status);
1045b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
104654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    umtx_unlock(&gLock);
1047b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1048b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (U_FAILURE(status)) {
1049b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return NULL;
1050b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
1051b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1052b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    TimeZoneGenericNameMatchInfo *gmatchInfo = NULL;
1053b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1054b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    int32_t maxLen = 0;
1055b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UVector *results = handler.getMatches(maxLen);
1056b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (results != NULL && ((maxLen == (text.length() - start)) || fGNamesTrieFullyLoaded)) {
1057b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        // perfect match
1058b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        gmatchInfo = new TimeZoneGenericNameMatchInfo(results);
1059b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (gmatchInfo == NULL) {
1060b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            status = U_MEMORY_ALLOCATION_ERROR;
1061b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            delete results;
1062b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            return NULL;
1063b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
1064b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return gmatchInfo;
1065b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
1066b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1067b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (results != NULL) {
1068b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        delete results;
1069b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
1070b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1071b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // All names are not yet loaded into the local trie.
1072b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // Load all available names into the trie. This could be very heavy.
107354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    umtx_lock(&gLock);
1074b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    {
1075b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (!fGNamesTrieFullyLoaded) {
1076b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            StringEnumeration *tzIDs = TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_CANONICAL, NULL, NULL, status);
1077b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (U_SUCCESS(status)) {
1078b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                const UnicodeString *tzID;
1079b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                while ((tzID = tzIDs->snext(status))) {
1080b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    if (U_FAILURE(status)) {
1081b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        break;
1082b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    }
1083b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    nonConstThis->loadStrings(*tzID);
1084b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
1085b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
1086b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (tzIDs != NULL) {
1087b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                delete tzIDs;
1088b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
1089b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1090b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (U_SUCCESS(status)) {
1091b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                nonConstThis->fGNamesTrieFullyLoaded = TRUE;
1092b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
1093b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
1094b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
109554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    umtx_unlock(&gLock);
1096b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1097b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (U_FAILURE(status)) {
1098b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return NULL;
1099b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
1100b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
110154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    umtx_lock(&gLock);
1102b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    {
1103b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        // now try it again
1104b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        fGNamesTrie.search(text, start, (TextTrieMapSearchResultHandler *)&handler, status);
1105b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
110654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    umtx_unlock(&gLock);
1107b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1108b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    results = handler.getMatches(maxLen);
1109b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (results != NULL && maxLen > 0) {
1110b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        gmatchInfo = new TimeZoneGenericNameMatchInfo(results);
1111b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (gmatchInfo == NULL) {
1112b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            status = U_MEMORY_ALLOCATION_ERROR;
1113b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            delete results;
1114b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            return NULL;
1115b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
1116b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
1117b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1118b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return gmatchInfo;
1119b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
1120b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1121103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusTimeZoneNames::MatchInfoCollection*
1122103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusTZGNCore::findTimeZoneNames(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const {
1123b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // Check if the target name typs is really in the TimeZoneNames
1124b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    uint32_t nameTypes = 0;
1125b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (types & UTZGNM_LONG) {
1126b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        nameTypes |= (UTZNM_LONG_GENERIC | UTZNM_LONG_STANDARD);
1127b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
1128b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (types & UTZGNM_SHORT) {
1129103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        nameTypes |= (UTZNM_SHORT_GENERIC | UTZNM_SHORT_STANDARD);
1130b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
1131b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1132b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (types) {
1133b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        // Find matches in the TimeZoneNames
1134103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        return fTimeZoneNames->find(text, start, nameTypes, status);
1135103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    }
1136103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
1137103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    return NULL;
1138103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius}
1139103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
1140103e9ffba2cba345d0078eb8b8db33249f81840aCraig Corneliustypedef struct TZGNCoreRef {
1141103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    TZGNCore*       obj;
1142103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    int32_t         refCount;
1143103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    double          lastAccess;
1144103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius} TZGNCoreRef;
1145103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
1146103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius// TZGNCore object cache handling
114754dcd9b6a06071f647dac967e9e267abb9410720Craig Corneliusstatic UMutex gTZGNLock = U_MUTEX_INITIALIZER;
1148103e9ffba2cba345d0078eb8b8db33249f81840aCraig Corneliusstatic UHashtable *gTZGNCoreCache = NULL;
1149103e9ffba2cba345d0078eb8b8db33249f81840aCraig Corneliusstatic UBool gTZGNCoreCacheInitialized = FALSE;
1150103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
1151103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius// Access count - incremented every time up to SWEEP_INTERVAL,
1152103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius// then reset to 0
1153103e9ffba2cba345d0078eb8b8db33249f81840aCraig Corneliusstatic int32_t gAccessCount = 0;
1154103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
1155103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius// Interval for calling the cache sweep function - every 100 times
1156103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius#define SWEEP_INTERVAL 100
1157103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
1158103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius// Cache expiration in millisecond. When a cached entry is no
1159103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius// longer referenced and exceeding this threshold since last
1160103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius// access time, then the cache entry will be deleted by the sweep
1161103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius// function. For now, 3 minutes.
1162103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius#define CACHE_EXPIRATION 180000.0
1163103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
1164103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusU_CDECL_BEGIN
1165103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius/**
1166103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius * Cleanup callback func
1167103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius */
1168103e9ffba2cba345d0078eb8b8db33249f81840aCraig Corneliusstatic UBool U_CALLCONV tzgnCore_cleanup(void)
1169103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius{
1170103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    if (gTZGNCoreCache != NULL) {
1171103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        uhash_close(gTZGNCoreCache);
1172103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        gTZGNCoreCache = NULL;
1173103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    }
1174103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    gTZGNCoreCacheInitialized = FALSE;
1175103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    return TRUE;
1176103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius}
1177103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
1178103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius/**
1179103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius * Deleter for TZGNCoreRef
1180103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius */
1181103e9ffba2cba345d0078eb8b8db33249f81840aCraig Corneliusstatic void U_CALLCONV
1182103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusdeleteTZGNCoreRef(void *obj) {
1183103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    icu::TZGNCoreRef *entry = (icu::TZGNCoreRef*)obj;
1184103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    delete (icu::TZGNCore*) entry->obj;
1185103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    uprv_free(entry);
1186103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius}
1187103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusU_CDECL_END
1188103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
1189103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius/**
1190103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius * Function used for removing unreferrenced cache entries exceeding
1191103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius * the expiration time. This function must be called with in the mutex
1192103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius * block.
1193103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius */
1194103e9ffba2cba345d0078eb8b8db33249f81840aCraig Corneliusstatic void sweepCache() {
1195103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    int32_t pos = -1;
1196103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    const UHashElement* elem;
1197103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    double now = (double)uprv_getUTCtime();
1198103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
1199103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    while ((elem = uhash_nextElement(gTZGNCoreCache, &pos))) {
1200103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        TZGNCoreRef *entry = (TZGNCoreRef *)elem->value.pointer;
1201103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        if (entry->refCount <= 0 && (now - entry->lastAccess) > CACHE_EXPIRATION) {
1202103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            // delete this entry
1203103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            uhash_removeElement(gTZGNCoreCache, elem);
1204103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        }
1205103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    }
1206103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius}
1207103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
1208103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusTimeZoneGenericNames::TimeZoneGenericNames()
1209103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius: fRef(0) {
1210103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius}
1211103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
1212103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusTimeZoneGenericNames::~TimeZoneGenericNames() {
1213103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    umtx_lock(&gTZGNLock);
1214103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    {
1215103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        U_ASSERT(fRef->refCount > 0);
1216103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        // Just decrement the reference count
1217103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        fRef->refCount--;
1218103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    }
1219103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    umtx_unlock(&gTZGNLock);
1220103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius}
1221103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
1222103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusTimeZoneGenericNames*
1223103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusTimeZoneGenericNames::createInstance(const Locale& locale, UErrorCode& status) {
1224103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    if (U_FAILURE(status)) {
1225103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        return NULL;
1226103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    }
1227103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    TimeZoneGenericNames* instance = new TimeZoneGenericNames();
1228103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    if (instance == NULL) {
1229103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        status = U_MEMORY_ALLOCATION_ERROR;
1230103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        return NULL;
1231103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    }
1232103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
1233103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    UBool initialized;
1234103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    UMTX_CHECK(&gTZGNLock, gTZGNCoreCacheInitialized, initialized);
1235103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    if (!initialized) {
1236103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        // Create empty hashtable
1237103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        umtx_lock(&gTZGNLock);
1238103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        {
1239103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            if (!gTZGNCoreCacheInitialized) {
1240103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                gTZGNCoreCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
1241103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                if (U_SUCCESS(status)) {
1242103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                    uhash_setKeyDeleter(gTZGNCoreCache, uprv_free);
1243103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                    uhash_setValueDeleter(gTZGNCoreCache, deleteTZGNCoreRef);
1244103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                    gTZGNCoreCacheInitialized = TRUE;
1245103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                    ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONEGENERICNAMES, tzgnCore_cleanup);
1246103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                }
1247103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            }
1248103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        }
1249103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        umtx_unlock(&gTZGNLock);
1250103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
1251103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        if (U_FAILURE(status)) {
1252103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            return NULL;
1253103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        }
1254103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    }
1255103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
1256103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    // Check the cache, if not available, create new one and cache
1257103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    TZGNCoreRef *cacheEntry = NULL;
1258103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    umtx_lock(&gTZGNLock);
1259103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    {
1260103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        const char *key = locale.getName();
1261103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        cacheEntry = (TZGNCoreRef *)uhash_get(gTZGNCoreCache, key);
1262103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        if (cacheEntry == NULL) {
1263103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            TZGNCore *tzgnCore = NULL;
1264103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            char *newKey = NULL;
1265103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
1266103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            tzgnCore = new TZGNCore(locale, status);
1267103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            if (tzgnCore == NULL) {
1268103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                status = U_MEMORY_ALLOCATION_ERROR;
1269103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            }
1270103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            if (U_SUCCESS(status)) {
1271103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                newKey = (char *)uprv_malloc(uprv_strlen(key) + 1);
1272103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                if (newKey == NULL) {
1273103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                    status = U_MEMORY_ALLOCATION_ERROR;
1274103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                } else {
1275103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                    uprv_strcpy(newKey, key);
1276103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                }
1277103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            }
1278103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            if (U_SUCCESS(status)) {
1279103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                cacheEntry = (TZGNCoreRef *)uprv_malloc(sizeof(TZGNCoreRef));
1280103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                if (cacheEntry == NULL) {
1281103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                    status = U_MEMORY_ALLOCATION_ERROR;
1282103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                } else {
1283103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                    cacheEntry->obj = tzgnCore;
1284103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                    cacheEntry->refCount = 1;
1285103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                    cacheEntry->lastAccess = (double)uprv_getUTCtime();
1286103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
1287103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                    uhash_put(gTZGNCoreCache, newKey, cacheEntry, &status);
1288103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                }
1289103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            }
1290103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            if (U_FAILURE(status)) {
1291103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                if (tzgnCore != NULL) {
1292103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                    delete tzgnCore;
1293103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                }
1294103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                if (newKey != NULL) {
1295103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                    uprv_free(newKey);
1296103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                }
1297103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                if (cacheEntry != NULL) {
1298103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                    uprv_free(cacheEntry);
1299103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                }
1300103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                cacheEntry = NULL;
1301103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            }
1302103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        } else {
1303103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            // Update the reference count
1304103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            cacheEntry->refCount++;
1305103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            cacheEntry->lastAccess = (double)uprv_getUTCtime();
1306103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        }
1307103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        gAccessCount++;
1308103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        if (gAccessCount >= SWEEP_INTERVAL) {
1309103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            // sweep
1310103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            sweepCache();
1311103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            gAccessCount = 0;
1312103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        }
1313b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
1314103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    umtx_unlock(&gTZGNLock);
1315103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
1316103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    if (cacheEntry == NULL) {
1317103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        delete instance;
1318103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        return NULL;
1319103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    }
1320103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
1321103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    instance->fRef = cacheEntry;
1322103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    return instance;
1323103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius}
1324b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1325103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusUBool
1326103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusTimeZoneGenericNames::operator==(const TimeZoneGenericNames& other) const {
1327103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    // Just compare if the other object also use the same
1328103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    // ref entry
1329103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    return fRef == other.fRef;
1330103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius}
1331103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
1332103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusTimeZoneGenericNames*
1333103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusTimeZoneGenericNames::clone() const {
1334103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    TimeZoneGenericNames* other = new TimeZoneGenericNames();
1335103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    if (other) {
1336103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        umtx_lock(&gTZGNLock);
1337103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        {
1338103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            // Just increments the reference count
1339103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            fRef->refCount++;
1340103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            other->fRef = fRef;
1341103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        }
1342103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        umtx_unlock(&gTZGNLock);
1343103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    }
1344103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    return other;
1345103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius}
1346103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
1347103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusUnicodeString&
1348103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusTimeZoneGenericNames::getDisplayName(const TimeZone& tz, UTimeZoneGenericNameType type,
1349103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                        UDate date, UnicodeString& name) const {
1350103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    return fRef->obj->getDisplayName(tz, type, date, name);
1351103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius}
1352103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
1353103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusUnicodeString&
1354103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusTimeZoneGenericNames::getGenericLocationName(const UnicodeString& tzCanonicalID, UnicodeString& name) const {
1355103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    return fRef->obj->getGenericLocationName(tzCanonicalID, name);
1356103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius}
1357103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
1358103e9ffba2cba345d0078eb8b8db33249f81840aCraig Corneliusint32_t
1359103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusTimeZoneGenericNames::findBestMatch(const UnicodeString& text, int32_t start, uint32_t types,
1360103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        UnicodeString& tzID, UTimeZoneFormatTimeType& timeType, UErrorCode& status) const {
1361103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    return fRef->obj->findBestMatch(text, start, types, tzID, timeType, status);
1362b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
1363b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1364b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoU_NAMESPACE_END
1365b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#endif
1366