1/*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15#include "i18n_calendar.h"
16
17#include "buddhcal.h"
18#include "chnsecal.h"
19#include "coptccal.h"
20#include "ethpccal.h"
21#include "hebrwcal.h"
22#include "indiancal.h"
23#include "islamcal.h"
24#include "japancal.h"
25#include "unicode/locdspnm.h"
26#include "persncal.h"
27#include "string"
28#include "ureslocs.h"
29#include "ulocimp.h"
30#include "unicode/umachine.h"
31#include "unicode/gregocal.h"
32#include "unicode/timezone.h"
33#include "unicode/unistr.h"
34#include "unicode/urename.h"
35#include "ustr_imp.h"
36#include "unicode/ustring.h"
37#include "utils.h"
38
39namespace OHOS {
40namespace Global {
41namespace I18n {
42I18nCalendar::I18nCalendar(std::string localeTag)
43{
44    UErrorCode status = U_ZERO_ERROR;
45    icu::Locale tempLocale = icu::Locale::forLanguageTag(localeTag, status);
46    if (U_FAILURE(status)) {
47        calendar_ = new icu::GregorianCalendar(status);
48        if (!U_SUCCESS(status)) {
49            if (calendar_ != nullptr) {
50                delete calendar_;
51            }
52            calendar_ = nullptr;
53        }
54        return;
55    }
56    calendar_ = icu::Calendar::createInstance(tempLocale, status);
57    if (U_FAILURE(status)) {
58        if (calendar_ != nullptr) {
59            delete calendar_;
60        }
61        calendar_ = nullptr;
62    }
63}
64
65I18nCalendar::I18nCalendar(std::string localeTag, CalendarType type)
66{
67    UErrorCode status = U_ZERO_ERROR;
68    icu::Locale tempLocale = icu::Locale::forLanguageTag(localeTag, status);
69    if (U_FAILURE(status)) {
70        calendar_ = new icu::GregorianCalendar(status);
71        if (!U_SUCCESS(status)) {
72            if (calendar_ != nullptr) {
73                delete calendar_;
74            }
75            calendar_ = nullptr;
76        }
77        return;
78    }
79    InitCalendar(tempLocale, type);
80}
81
82void I18nCalendar::InitCalendar(const icu::Locale &locale, CalendarType type)
83{
84    UErrorCode status = U_ZERO_ERROR;
85    switch (type) {
86        case BUDDHIST: {
87            calendar_ = new icu::BuddhistCalendar(locale, status);
88            break;
89        }
90        case CHINESE: {
91            calendar_ = new icu::ChineseCalendar(locale, status);
92            break;
93        }
94        case COPTIC: {
95            calendar_ = new icu::CopticCalendar(locale, status);
96            break;
97        }
98        case ETHIOPIC: {
99            calendar_ = new icu::EthiopicCalendar(locale, status);
100            break;
101        }
102        case HEBREW: {
103            calendar_ = new icu::HebrewCalendar(locale, status);
104            break;
105        }
106        case INDIAN: {
107            calendar_ = new icu::IndianCalendar(locale, status);
108            break;
109        }
110        case ISLAMIC_CIVIL: {
111            calendar_ = new icu::IslamicCalendar(locale, status, icu::IslamicCalendar::ECalculationType::CIVIL);
112            break;
113        }
114        default: {
115            InitCalendar2(locale, type, status);
116        }
117    }
118    if (!U_SUCCESS(status)) {
119        if (calendar_ != nullptr) {
120            delete calendar_;
121        }
122        calendar_ = nullptr;
123    }
124}
125
126void I18nCalendar::InitCalendar2(const icu::Locale &locale, CalendarType type, UErrorCode &status)
127{
128    switch (type) {
129        case ISLAMIC_TBLA: {
130            calendar_ = new icu::IslamicCalendar(locale, status, icu::IslamicCalendar::ECalculationType::TBLA);
131            break;
132        }
133        case ISLAMIC_UMALQURA: {
134            calendar_ = new icu::IslamicCalendar(locale, status, icu::IslamicCalendar::ECalculationType::UMALQURA);
135            break;
136        }
137        case JAPANESE: {
138            calendar_ = new icu::JapaneseCalendar(locale, status);
139            break;
140        }
141        case PERSIAN: {
142            calendar_ = new icu::PersianCalendar(locale, status);
143            break;
144        }
145        case GREGORY: {
146            calendar_ = new icu::GregorianCalendar(locale, status);
147            break;
148        }
149        default: {
150            calendar_ = icu::Calendar::createInstance(locale, status);
151        }
152    }
153}
154
155I18nCalendar::~I18nCalendar()
156{
157    if (calendar_ != nullptr) {
158        delete calendar_;
159    }
160}
161
162void I18nCalendar::SetTime(double value)
163{
164    icu::Calendar* icuCalendar = GetIcuCalendar();
165    if (icuCalendar != nullptr) {
166        UErrorCode status = U_ZERO_ERROR;
167        icuCalendar->setTime(value, status);
168        return;
169    }
170}
171
172void I18nCalendar::SetTimeZone(std::string id)
173{
174    icu::UnicodeString zone = icu::UnicodeString::fromUTF8(id);
175    icu::TimeZone *timezone = icu::TimeZone::createTimeZone(zone);
176    if (timezone != nullptr) {
177        icu::Calendar* icuCalendar = GetIcuCalendar();
178        if (icuCalendar != nullptr) {
179            icuCalendar->setTimeZone(*timezone);
180        }
181        delete(timezone);
182    }
183}
184
185std::string I18nCalendar::GetTimeZone(void)
186{
187    std::string ret;
188    icu::Calendar* icuCalendar = GetIcuCalendar();
189    if (icuCalendar) {
190        icu::UnicodeString unistr;
191        icuCalendar->getTimeZone().getID(unistr);
192        unistr.toUTF8String<std::string>(ret);
193    }
194    return ret;
195}
196
197void I18nCalendar::Set(int32_t year, int32_t month, int32_t date)
198{
199    icu::Calendar* icuCalendar = GetIcuCalendar();
200    if (icuCalendar != nullptr) {
201        icuCalendar->set(year, month, date);
202        return;
203    }
204}
205
206void I18nCalendar::Set(UCalendarDateFields field, int32_t value)
207{
208    icu::Calendar* icuCalendar = GetIcuCalendar();
209    if (icuCalendar != nullptr) {
210        icuCalendar->set(field, value);
211        return;
212    }
213}
214
215int32_t I18nCalendar::Get(UCalendarDateFields field) const
216{
217    icu::Calendar* icuCalendar = GetIcuCalendar();
218    if (icuCalendar != nullptr) {
219        UErrorCode status = U_ZERO_ERROR;
220        return icuCalendar->get(field, status);
221    }
222    return 0;
223}
224
225void I18nCalendar::Add(UCalendarDateFields field, int32_t amount)
226{
227    icu::Calendar* icuCalendar = GetIcuCalendar();
228    if (icuCalendar != nullptr) {
229        UErrorCode status = U_ZERO_ERROR;
230        icuCalendar->add(field, amount, status);
231    }
232}
233
234void I18nCalendar::SetMinimalDaysInFirstWeek(int32_t value)
235{
236    icu::Calendar* icuCalendar = GetIcuCalendar();
237    if (icuCalendar != nullptr) {
238        icuCalendar->setMinimalDaysInFirstWeek((uint8_t)value);
239        return;
240    }
241}
242
243void I18nCalendar::SetFirstDayOfWeek(int32_t value)
244{
245    if (value < UCalendarDaysOfWeek::UCAL_SUNDAY || value > UCAL_SATURDAY) {
246        return;
247    }
248    icu::Calendar* icuCalendar = GetIcuCalendar();
249    if (icuCalendar != nullptr) {
250        icuCalendar->setFirstDayOfWeek(UCalendarDaysOfWeek(value));
251        return;
252    }
253}
254
255UDate I18nCalendar::GetTimeInMillis(void)
256{
257    icu::Calendar* icuCalendar = GetIcuCalendar();
258    if (icuCalendar != nullptr) {
259        UErrorCode status = U_ZERO_ERROR;
260        return icuCalendar->getTime(status);
261    }
262    return 0;
263}
264
265int32_t I18nCalendar::GetMinimalDaysInFirstWeek(void)
266{
267    icu::Calendar* icuCalendar = GetIcuCalendar();
268    if (icuCalendar != nullptr) {
269        return icuCalendar->getMinimalDaysInFirstWeek();
270    }
271    return 1;
272}
273
274int32_t I18nCalendar::GetFirstDayOfWeek(void)
275{
276    icu::Calendar* icuCalendar = GetIcuCalendar();
277    if (icuCalendar != nullptr) {
278        return static_cast<int>(icuCalendar->getFirstDayOfWeek());
279    }
280    return UCAL_SUNDAY;
281}
282
283bool I18nCalendar::IsWeekend(int64_t date, UErrorCode &status)
284{
285    icu::Calendar* icuCalendar = GetIcuCalendar();
286    if (icuCalendar != nullptr) {
287        return icuCalendar->isWeekend(date, status);
288    }
289    return false;
290}
291
292bool I18nCalendar::IsWeekend(void)
293{
294    icu::Calendar* icuCalendar = GetIcuCalendar();
295    if (icuCalendar != nullptr) {
296        return icuCalendar->isWeekend();
297    }
298    return false;
299}
300
301std::string I18nCalendar::GetDisplayName(std::string &displayLocaleTag)
302{
303    icu::Calendar* icuCalendar = GetIcuCalendar();
304    if (icuCalendar == nullptr) {
305        return PseudoLocalizationProcessor("");
306    }
307    const char *type = icuCalendar->getType();
308    if (type == nullptr) {
309        return PseudoLocalizationProcessor("");
310    }
311    UErrorCode status = U_ZERO_ERROR;
312    icu::Locale displayLocale = icu::Locale::forLanguageTag(displayLocaleTag, status);
313    if (U_FAILURE(status)) {
314        return PseudoLocalizationProcessor("");
315    }
316    icu::LocaleDisplayNames *dspName = icu::LocaleDisplayNames::createInstance(displayLocale);
317    icu::UnicodeString unistr;
318    if (dspName != nullptr) {
319        dspName->keyValueDisplayName("calendar", type, unistr);
320        delete dspName;
321    }
322    std::string ret;
323    unistr.toUTF8String<std::string>(ret);
324    return PseudoLocalizationProcessor(ret);
325}
326
327int32_t I18nCalendar::CompareDays(UDate date)
328{
329    icu::Calendar* icuCalendar = GetIcuCalendar();
330    if (icuCalendar != nullptr) {
331        UErrorCode status = U_ZERO_ERROR;
332        UDate nowMs = icuCalendar->getTime(status);
333        double ret = (date - nowMs) / (24 * 60 * 60 * 1000); // Convert 24 hours into milliseconds
334        return ret > 0 ? std::ceil(ret) : std::floor(ret);
335    }
336    return 0;
337}
338
339icu::Calendar* I18nCalendar::GetIcuCalendar() const
340{
341    return this->calendar_;
342}
343} // namespace I18n
344} // namespace Global
345} // namespace OHOS