1fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius/*
2fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius******************************************************************************
3fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius* Copyright (C) 2014, International Business Machines Corporation and
4fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius* others. All Rights Reserved.
5fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius******************************************************************************
6fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius*
7fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius* File RELDATEFMT.CPP
8fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius******************************************************************************
9fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius*/
10fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
11fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/reldatefmt.h"
12fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
13fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#if !UCONFIG_NO_FORMATTING
14fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
15fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/localpointer.h"
16fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "quantityformatter.h"
17fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/plurrule.h"
18fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/msgfmt.h"
19fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/decimfmt.h"
20fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/numfmt.h"
21fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "lrucache.h"
22fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "uresimp.h"
23fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/ures.h"
24fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "cstring.h"
25fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "ucln_in.h"
26fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "mutex.h"
27fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "charstr.h"
28fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
29fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "sharedptr.h"
30fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "sharedpluralrules.h"
31fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "sharednumberformat.h"
32fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
33fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius// Copied from uscript_props.cpp
34fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
35fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
36fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic icu::LRUCache *gCache = NULL;
37fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic UMutex gCacheMutex = U_MUTEX_INITIALIZER;
38fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic icu::UInitOnce gCacheInitOnce = U_INITONCE_INITIALIZER;
39fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
40fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusU_CDECL_BEGIN
41fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic UBool U_CALLCONV reldatefmt_cleanup() {
42fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    gCacheInitOnce.reset();
43fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (gCache) {
44fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        delete gCache;
45fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        gCache = NULL;
46fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
47fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    return TRUE;
48fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
49fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusU_CDECL_END
50fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
51fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusU_NAMESPACE_BEGIN
52fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
53fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius// RelativeDateTimeFormatter specific data for a single locale
54fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusclass RelativeDateTimeCacheData: public SharedObject {
55fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliuspublic:
56fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    RelativeDateTimeCacheData() : combinedDateAndTime(NULL) { }
57fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    virtual ~RelativeDateTimeCacheData();
58fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
59fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // no numbers: e.g Next Tuesday; Yesterday; etc.
60fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    UnicodeString absoluteUnits[UDAT_ABSOLUTE_UNIT_COUNT][UDAT_DIRECTION_COUNT];
61fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
62fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // has numbers: e.g Next Tuesday; Yesterday; etc. For second index, 0
63fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // means past e.g 5 days ago; 1 means future e.g in 5 days.
64fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    QuantityFormatter relativeUnits[UDAT_RELATIVE_UNIT_COUNT][2];
65fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
66fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    void adoptCombinedDateAndTime(MessageFormat *mfToAdopt) {
67fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        delete combinedDateAndTime;
68fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        combinedDateAndTime = mfToAdopt;
69fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
70fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    const MessageFormat *getCombinedDateAndTime() const {
71fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return combinedDateAndTime;
72fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
73fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusprivate:
74fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    MessageFormat *combinedDateAndTime;
75fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    RelativeDateTimeCacheData(const RelativeDateTimeCacheData &other);
76fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    RelativeDateTimeCacheData& operator=(
77fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            const RelativeDateTimeCacheData &other);
78fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius};
79fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
80fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusRelativeDateTimeCacheData::~RelativeDateTimeCacheData() {
81fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    delete combinedDateAndTime;
82fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
83fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
84fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic UBool getStringWithFallback(
85fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const UResourceBundle *resource,
86fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const char *key,
87fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UnicodeString &result,
88fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UErrorCode &status) {
89fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t len = 0;
90fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    const UChar *resStr = ures_getStringByKeyWithFallback(
91fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        resource, key, &len, &status);
92fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
93fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return FALSE;
94fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
95fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    result.setTo(TRUE, resStr, len);
96fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    return TRUE;
97fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
98fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
99fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic UBool getOptionalStringWithFallback(
100fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const UResourceBundle *resource,
101fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const char *key,
102fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UnicodeString &result,
103fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UErrorCode &status) {
104fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
105fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return FALSE;
106fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
107fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t len = 0;
108fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    const UChar *resStr = ures_getStringByKey(
109fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        resource, key, &len, &status);
110fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (status == U_MISSING_RESOURCE_ERROR) {
111fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        result.remove();
112fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        status = U_ZERO_ERROR;
113fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return TRUE;
114fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
115fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
116fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return FALSE;
117fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
118fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    result.setTo(TRUE, resStr, len);
119fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    return TRUE;
120fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
121fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
122fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic UBool getString(
123fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const UResourceBundle *resource,
124fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UnicodeString &result,
125fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UErrorCode &status) {
126fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t len = 0;
127fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    const UChar *resStr = ures_getString(resource, &len, &status);
128fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
129fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return FALSE;
130fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
131fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    result.setTo(TRUE, resStr, len);
132fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    return TRUE;
133fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
134fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
135fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic UBool getStringByIndex(
136fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const UResourceBundle *resource,
137fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        int32_t idx,
138fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UnicodeString &result,
139fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UErrorCode &status) {
140fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t len = 0;
141fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    const UChar *resStr = ures_getStringByIndex(
142fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            resource, idx, &len, &status);
143fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
144fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return FALSE;
145fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
146fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    result.setTo(TRUE, resStr, len);
147fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    return TRUE;
148fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
149fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
150fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic void initAbsoluteUnit(
151fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            const UResourceBundle *resource,
152fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            const UnicodeString &unitName,
153fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            UnicodeString *absoluteUnit,
154fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            UErrorCode &status) {
155fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    getStringWithFallback(
156fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            resource,
157fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            "-1",
158fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            absoluteUnit[UDAT_DIRECTION_LAST],
159fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status);
160fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    getStringWithFallback(
161fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            resource,
162fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            "0",
163fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            absoluteUnit[UDAT_DIRECTION_THIS],
164fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status);
165fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    getStringWithFallback(
166fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            resource,
167fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            "1",
168fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            absoluteUnit[UDAT_DIRECTION_NEXT],
169fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status);
170fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    getOptionalStringWithFallback(
171fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            resource,
172fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            "-2",
173fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            absoluteUnit[UDAT_DIRECTION_LAST_2],
174fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status);
175fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    getOptionalStringWithFallback(
176fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            resource,
177fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            "2",
178fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            absoluteUnit[UDAT_DIRECTION_NEXT_2],
179fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status);
180fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    absoluteUnit[UDAT_DIRECTION_PLAIN] = unitName;
181fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
182fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
183fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic void initQuantityFormatter(
184fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const UResourceBundle *resource,
185fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        QuantityFormatter &formatter,
186fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UErrorCode &status) {
187fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
188fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return;
189fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
190fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t size = ures_getSize(resource);
191fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    for (int32_t i = 0; i < size; ++i) {
192fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        LocalUResourceBundlePointer pluralBundle(
193fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                ures_getByIndex(resource, i, NULL, &status));
194fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if (U_FAILURE(status)) {
195fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            return;
196fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
197fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UnicodeString rawPattern;
198fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if (!getString(pluralBundle.getAlias(), rawPattern, status)) {
199fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            return;
200fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
201fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if (!formatter.add(
202fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                ures_getKey(pluralBundle.getAlias()),
203fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                rawPattern,
204fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                status)) {
205fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            return;
206fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
207fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
208fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
209fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
210fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic void initRelativeUnit(
211fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const UResourceBundle *resource,
212fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        QuantityFormatter *relativeUnit,
213fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UErrorCode &status) {
214fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    LocalUResourceBundlePointer topLevel(
215fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            ures_getByKeyWithFallback(
216fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    resource, "relativeTime", NULL, &status));
217fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
218fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return;
219fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
220fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    LocalUResourceBundlePointer futureBundle(ures_getByKeyWithFallback(
221fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            topLevel.getAlias(), "future", NULL, &status));
222fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
223fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return;
224fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
225fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    initQuantityFormatter(
226fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            futureBundle.getAlias(),
227fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            relativeUnit[1],
228fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status);
229fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    LocalUResourceBundlePointer pastBundle(ures_getByKeyWithFallback(
230fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            topLevel.getAlias(), "past", NULL, &status));
231fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
232fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return;
233fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
234fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    initQuantityFormatter(
235fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            pastBundle.getAlias(),
236fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            relativeUnit[0],
237fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status);
238fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
239fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
240fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic void initRelativeUnit(
241fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const UResourceBundle *resource,
242fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const char *path,
243fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        QuantityFormatter *relativeUnit,
244fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UErrorCode &status) {
245fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    LocalUResourceBundlePointer topLevel(
246fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            ures_getByKeyWithFallback(resource, path, NULL, &status));
247fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
248fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return;
249fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
250fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    initRelativeUnit(topLevel.getAlias(), relativeUnit, status);
251fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
252fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
253fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic void addTimeUnit(
254fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const UResourceBundle *resource,
255fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const char *path,
256fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        QuantityFormatter *relativeUnit,
257fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UnicodeString *absoluteUnit,
258fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UErrorCode &status) {
259fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    LocalUResourceBundlePointer topLevel(
260fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            ures_getByKeyWithFallback(resource, path, NULL, &status));
261fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
262fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return;
263fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
264fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    initRelativeUnit(topLevel.getAlias(), relativeUnit, status);
265fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    UnicodeString unitName;
266fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (!getStringWithFallback(topLevel.getAlias(), "dn", unitName, status)) {
267fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return;
268fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
269fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // TODO(Travis Keep): This is a hack to get around CLDR bug 6818.
270fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    const char *localeId = ures_getLocaleByType(
271fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            topLevel.getAlias(), ULOC_ACTUAL_LOCALE, &status);
272fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
273fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return;
274fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
275fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    Locale locale(localeId);
276fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (uprv_strcmp("en", locale.getLanguage()) == 0) {
277fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius         unitName.toLower();
278fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
279fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // end hack
280fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    ures_getByKeyWithFallback(
281fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            topLevel.getAlias(), "relative", topLevel.getAlias(), &status);
282fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
283fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return;
284fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
285fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    initAbsoluteUnit(
286fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            topLevel.getAlias(),
287fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            unitName,
288fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            absoluteUnit,
289fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status);
290fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
291fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
292fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic void readDaysOfWeek(
293fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const UResourceBundle *resource,
294fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const char *path,
295fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UnicodeString *daysOfWeek,
296fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UErrorCode &status) {
297fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    LocalUResourceBundlePointer topLevel(
298fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            ures_getByKeyWithFallback(resource, path, NULL, &status));
299fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
300fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return;
301fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
302fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t size = ures_getSize(topLevel.getAlias());
303fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (size != 7) {
304fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        status = U_INTERNAL_PROGRAM_ERROR;
305fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return;
306fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
307fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    for (int32_t i = 0; i < size; ++i) {
308fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if (!getStringByIndex(topLevel.getAlias(), i, daysOfWeek[i], status)) {
309fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            return;
310fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
311fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
312fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
313fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
314fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic void addWeekDay(
315fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const UResourceBundle *resource,
316fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const char *path,
317fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const UnicodeString *daysOfWeek,
318fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UDateAbsoluteUnit absoluteUnit,
319fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UnicodeString absoluteUnits[][UDAT_DIRECTION_COUNT],
320fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UErrorCode &status) {
321fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    LocalUResourceBundlePointer topLevel(
322fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            ures_getByKeyWithFallback(resource, path, NULL, &status));
323fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
324fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return;
325fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
326fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    initAbsoluteUnit(
327fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            topLevel.getAlias(),
328fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            daysOfWeek[absoluteUnit - UDAT_ABSOLUTE_SUNDAY],
329fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            absoluteUnits[absoluteUnit],
330fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status);
331fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
332fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
333fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic UBool loadUnitData(
334fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const UResourceBundle *resource,
335fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        RelativeDateTimeCacheData &cacheData,
336fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UErrorCode &status) {
337fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    addTimeUnit(
338fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            resource,
339fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            "fields/day",
340fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            cacheData.relativeUnits[UDAT_RELATIVE_DAYS],
341fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            cacheData.absoluteUnits[UDAT_ABSOLUTE_DAY],
342fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status);
343fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    addTimeUnit(
344fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            resource,
345fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            "fields/week",
346fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            cacheData.relativeUnits[UDAT_RELATIVE_WEEKS],
347fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            cacheData.absoluteUnits[UDAT_ABSOLUTE_WEEK],
348fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status);
349fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    addTimeUnit(
350fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            resource,
351fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            "fields/month",
352fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            cacheData.relativeUnits[UDAT_RELATIVE_MONTHS],
353fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            cacheData.absoluteUnits[UDAT_ABSOLUTE_MONTH],
354fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status);
355fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    addTimeUnit(
356fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            resource,
357fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            "fields/year",
358fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            cacheData.relativeUnits[UDAT_RELATIVE_YEARS],
359fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            cacheData.absoluteUnits[UDAT_ABSOLUTE_YEAR],
360fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status);
361fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    initRelativeUnit(
362fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            resource,
363fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            "fields/second",
364fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            cacheData.relativeUnits[UDAT_RELATIVE_SECONDS],
365fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status);
366fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    initRelativeUnit(
367fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            resource,
368fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            "fields/minute",
369fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            cacheData.relativeUnits[UDAT_RELATIVE_MINUTES],
370fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status);
371fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    initRelativeUnit(
372fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            resource,
373fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            "fields/hour",
374fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            cacheData.relativeUnits[UDAT_RELATIVE_HOURS],
375fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status);
376fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    getStringWithFallback(
377fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            resource,
378fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            "fields/second/relative/0",
379fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            cacheData.absoluteUnits[UDAT_ABSOLUTE_NOW][UDAT_DIRECTION_PLAIN],
380fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status);
381fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    UnicodeString daysOfWeek[7];
382fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    readDaysOfWeek(
383fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            resource,
384fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            "calendar/gregorian/dayNames/stand-alone/wide",
385fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            daysOfWeek,
386fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status);
387fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    addWeekDay(
388fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            resource,
389fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            "fields/mon/relative",
390fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            daysOfWeek,
391fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            UDAT_ABSOLUTE_MONDAY,
392fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            cacheData.absoluteUnits,
393fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status);
394fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    addWeekDay(
395fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            resource,
396fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            "fields/tue/relative",
397fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            daysOfWeek,
398fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            UDAT_ABSOLUTE_TUESDAY,
399fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            cacheData.absoluteUnits,
400fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status);
401fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    addWeekDay(
402fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            resource,
403fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            "fields/wed/relative",
404fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            daysOfWeek,
405fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            UDAT_ABSOLUTE_WEDNESDAY,
406fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            cacheData.absoluteUnits,
407fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status);
408fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    addWeekDay(
409fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            resource,
410fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            "fields/thu/relative",
411fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            daysOfWeek,
412fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            UDAT_ABSOLUTE_THURSDAY,
413fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            cacheData.absoluteUnits,
414fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status);
415fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    addWeekDay(
416fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            resource,
417fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            "fields/fri/relative",
418fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            daysOfWeek,
419fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            UDAT_ABSOLUTE_FRIDAY,
420fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            cacheData.absoluteUnits,
421fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status);
422fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    addWeekDay(
423fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            resource,
424fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            "fields/sat/relative",
425fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            daysOfWeek,
426fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            UDAT_ABSOLUTE_SATURDAY,
427fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            cacheData.absoluteUnits,
428fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status);
429fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    addWeekDay(
430fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            resource,
431fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            "fields/sun/relative",
432fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            daysOfWeek,
433fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            UDAT_ABSOLUTE_SUNDAY,
434fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            cacheData.absoluteUnits,
435fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status);
436fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    return U_SUCCESS(status);
437fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
438fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
439fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic UBool getDateTimePattern(
440fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const UResourceBundle *resource,
441fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UnicodeString &result,
442fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UErrorCode &status) {
443fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    UnicodeString defaultCalendarName;
444fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (!getStringWithFallback(
445fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            resource,
446fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            "calendar/default",
447fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            defaultCalendarName,
448fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status)) {
449fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return FALSE;
450fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
451fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    CharString pathBuffer;
452fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    pathBuffer.append("calendar/", status)
453fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            .appendInvariantChars(defaultCalendarName, status)
454fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            .append("/DateTimePatterns", status);
455fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    LocalUResourceBundlePointer topLevel(
456fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            ures_getByKeyWithFallback(
457fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    resource, pathBuffer.data(), NULL, &status));
458fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
459fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return FALSE;
460fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
461fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t size = ures_getSize(topLevel.getAlias());
462fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (size <= 8) {
463fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        // Oops, size is to small to access the index that we want, fallback
464fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        // to a hard-coded value.
465fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        result = UNICODE_STRING_SIMPLE("{1} {0}");
466fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return TRUE;
467fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
468fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    return getStringByIndex(topLevel.getAlias(), 8, result, status);
469fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
470fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
471fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius// Creates RelativeDateTimeFormatter specific data for a given locale
472fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic SharedObject *U_CALLCONV createData(
473fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const char *localeId, UErrorCode &status) {
474fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    LocalUResourceBundlePointer topLevel(ures_open(NULL, localeId, &status));
475fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
476fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return NULL;
477fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
478fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    LocalPointer<RelativeDateTimeCacheData> result(
479fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            new RelativeDateTimeCacheData());
480fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (result.isNull()) {
481fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        status = U_MEMORY_ALLOCATION_ERROR;
482fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return NULL;
483fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
484fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (!loadUnitData(
485fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            topLevel.getAlias(),
486fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            *result,
487fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status)) {
488fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return NULL;
489fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
490fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    UnicodeString dateTimePattern;
491fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (!getDateTimePattern(topLevel.getAlias(), dateTimePattern, status)) {
492fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return NULL;
493fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
494fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    result->adoptCombinedDateAndTime(
495fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            new MessageFormat(dateTimePattern, localeId, status));
496fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
497fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return NULL;
498fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
499fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    return result.orphan();
500fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
501fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
502fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic void U_CALLCONV cacheInit(UErrorCode &status) {
503fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    U_ASSERT(gCache == NULL);
504fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    ucln_i18n_registerCleanup(UCLN_I18N_RELDATEFMT, reldatefmt_cleanup);
505fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    gCache = new SimpleLRUCache(100, &createData, status);
506fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
507fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        delete gCache;
508fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        gCache = NULL;
509fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
510fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
511fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
512fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic UBool getFromCache(
513fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const char *locale,
514fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const RelativeDateTimeCacheData *&ptr,
515fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UErrorCode &status) {
516fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    umtx_initOnce(gCacheInitOnce, &cacheInit, status);
517fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
518fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return FALSE;
519fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
520fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    Mutex lock(&gCacheMutex);
521fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    gCache->get(locale, ptr, status);
522fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    return U_SUCCESS(status);
523fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
524fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
525fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusRelativeDateTimeFormatter::RelativeDateTimeFormatter(UErrorCode& status)
526fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        : cache(NULL), numberFormat(NULL), pluralRules(NULL) {
527fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    init(Locale::getDefault(), NULL, status);
528fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
529fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
530fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusRelativeDateTimeFormatter::RelativeDateTimeFormatter(
531fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const Locale& locale, UErrorCode& status)
532fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        : cache(NULL), numberFormat(NULL), pluralRules(NULL) {
533fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    init(locale, NULL, status);
534fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
535fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
536fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusRelativeDateTimeFormatter::RelativeDateTimeFormatter(
537fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const Locale& locale, NumberFormat *nfToAdopt, UErrorCode& status)
538fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        : cache(NULL), numberFormat(NULL), pluralRules(NULL) {
539fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    init(locale, nfToAdopt, status);
540fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
541fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
542fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusRelativeDateTimeFormatter::RelativeDateTimeFormatter(
543fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const RelativeDateTimeFormatter& other)
544fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        : cache(other.cache),
545fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius          numberFormat(other.numberFormat),
546fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius          pluralRules(other.pluralRules) {
547fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    cache->addRef();
548fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    numberFormat->addRef();
549fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    pluralRules->addRef();
550fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
551fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
552fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusRelativeDateTimeFormatter& RelativeDateTimeFormatter::operator=(
553fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const RelativeDateTimeFormatter& other) {
554fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (this != &other) {
555fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        SharedObject::copyPtr(other.cache, cache);
556fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        SharedObject::copyPtr(other.numberFormat, numberFormat);
557fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        SharedObject::copyPtr(other.pluralRules, pluralRules);
558fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
559fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    return *this;
560fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
561fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
562fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusRelativeDateTimeFormatter::~RelativeDateTimeFormatter() {
563fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (cache != NULL) {
564fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        cache->removeRef();
565fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
566fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (numberFormat != NULL) {
567fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        numberFormat->removeRef();
568fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
569fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (pluralRules != NULL) {
570fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        pluralRules->removeRef();
571fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
572fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
573fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
574fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusconst NumberFormat& RelativeDateTimeFormatter::getNumberFormat() const {
575fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    return **numberFormat;
576fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
577fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
578fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusUnicodeString& RelativeDateTimeFormatter::format(
579fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        double quantity, UDateDirection direction, UDateRelativeUnit unit,
580fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UnicodeString& appendTo, UErrorCode& status) const {
581fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
582fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return appendTo;
583fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
584fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (direction != UDAT_DIRECTION_LAST && direction != UDAT_DIRECTION_NEXT) {
585fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        status = U_ILLEGAL_ARGUMENT_ERROR;
586fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return appendTo;
587fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
588fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t bFuture = direction == UDAT_DIRECTION_NEXT ? 1 : 0;
589fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    FieldPosition pos(FieldPosition::DONT_CARE);
590fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    return cache->relativeUnits[unit][bFuture].format(
591fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            quantity,
592fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            **numberFormat,
593fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            **pluralRules,
594fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            appendTo,
595fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            pos,
596fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status);
597fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
598fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
599fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusUnicodeString& RelativeDateTimeFormatter::format(
600fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UDateDirection direction, UDateAbsoluteUnit unit,
601fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UnicodeString& appendTo, UErrorCode& status) const {
602fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
603fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return appendTo;
604fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
605fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (unit == UDAT_ABSOLUTE_NOW && direction != UDAT_DIRECTION_PLAIN) {
606fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        status = U_ILLEGAL_ARGUMENT_ERROR;
607fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return appendTo;
608fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
609fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    return appendTo.append(cache->absoluteUnits[unit][direction]);
610fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
611fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
612fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusUnicodeString& RelativeDateTimeFormatter::combineDateAndTime(
613fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    const UnicodeString& relativeDateString, const UnicodeString& timeString,
614fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    UnicodeString& appendTo, UErrorCode& status) const {
615fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    Formattable args[2] = {timeString, relativeDateString};
616fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    FieldPosition fpos(0);
617fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    return cache->getCombinedDateAndTime()->format(
618fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            args, 2, appendTo, fpos, status);
619fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
620fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
621fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusvoid RelativeDateTimeFormatter::init(
622fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const Locale &locale, NumberFormat *nfToAdopt, UErrorCode &status) {
623fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    LocalPointer<NumberFormat> nf(nfToAdopt);
624fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (!getFromCache(locale.getName(), cache, status)) {
625fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return;
626fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
627fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    SharedObject::copyPtr(
628fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            PluralRules::createSharedInstance(
629fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    locale, UPLURAL_TYPE_CARDINAL, status),
630fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            pluralRules);
631fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
632fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return;
633fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
634fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    pluralRules->removeRef();
635fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (nf.isNull()) {
636fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius       SharedObject::copyPtr(
637fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius               NumberFormat::createSharedInstance(
638fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                       locale, UNUM_DECIMAL, status),
639fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius               numberFormat);
640fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if (U_FAILURE(status)) {
641fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            return;
642fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
643fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        numberFormat->removeRef();
644fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    } else {
645fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        SharedNumberFormat *shared = new SharedNumberFormat(nf.getAlias());
646fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if (shared == NULL) {
647fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status = U_MEMORY_ALLOCATION_ERROR;
648fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            return;
649fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
650fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        nf.orphan();
651fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        SharedObject::copyPtr(shared, numberFormat);
652fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
653fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
654fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
655fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
656fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusU_NAMESPACE_END
657fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
658fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#endif /* !UCONFIG_NO_FORMATTING */
659fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
660