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