1 /*
2  * Copyright (c) 2023 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 
16 #include <unordered_map>
17 #include <unordered_set>
18 
19 #include "error_util.h"
20 #include "i18n_hilog.h"
21 #include "i18n_calendar_addon.h"
22 #include "js_utils.h"
23 #include "variable_convertor.h"
24 
25 namespace OHOS {
26 namespace Global {
27 namespace I18n {
28 static thread_local napi_ref* g_constructor = nullptr;
29 static std::unordered_map<std::string, UCalendarDateFields> g_fieldsMap {
30     { "era", UCAL_ERA },
31     { "year", UCAL_YEAR },
32     { "month", UCAL_MONTH },
33     { "week_of_year", UCAL_WEEK_OF_YEAR },
34     { "week_of_month", UCAL_WEEK_OF_MONTH },
35     { "date", UCAL_DATE },
36     { "day_of_year", UCAL_DAY_OF_YEAR },
37     { "day_of_week", UCAL_DAY_OF_WEEK },
38     { "day_of_week_in_month", UCAL_DAY_OF_WEEK_IN_MONTH },
39     { "ap_pm", UCAL_AM_PM },
40     { "hour", UCAL_HOUR },
41     { "hour_of_day", UCAL_HOUR_OF_DAY },
42     { "minute", UCAL_MINUTE },
43     { "second", UCAL_SECOND },
44     { "millisecond", UCAL_MILLISECOND },
45     { "zone_offset", UCAL_ZONE_OFFSET },
46     { "dst_offset", UCAL_DST_OFFSET },
47     { "year_woy", UCAL_YEAR_WOY },
48     { "dow_local", UCAL_DOW_LOCAL },
49     { "extended_year", UCAL_EXTENDED_YEAR },
50     { "julian_day", UCAL_JULIAN_DAY },
51     { "milliseconds_in_day", UCAL_MILLISECONDS_IN_DAY },
52     { "is_leap_month", UCAL_IS_LEAP_MONTH },
53 };
54 static std::unordered_set<std::string> g_fieldsInFunctionAdd {
55     "year", "month", "date", "hour", "minute", "second", "millisecond",
56     "week_of_year", "week_of_month", "day_of_year", "day_of_week",
57     "day_of_week_in_month", "hour_of_day", "milliseconds_in_day",
58 };
59 static std::unordered_map<std::string, CalendarType> g_typeMap {
60     { "buddhist", CalendarType::BUDDHIST },
61     { "chinese", CalendarType::CHINESE },
62     { "coptic", CalendarType::COPTIC },
63     { "ethiopic", CalendarType::ETHIOPIC },
64     { "hebrew", CalendarType::HEBREW },
65     { "gregory", CalendarType::GREGORY },
66     { "indian", CalendarType::INDIAN },
67     { "islamic_civil", CalendarType::ISLAMIC_CIVIL },
68     { "islamic_tbla", CalendarType::ISLAMIC_TBLA },
69     { "islamic_umalqura", CalendarType::ISLAMIC_UMALQURA },
70     { "japanese", CalendarType::JAPANESE },
71     { "persion", CalendarType::PERSIAN },
72 };
73 
I18nCalendarAddon()74 I18nCalendarAddon::I18nCalendarAddon() {}
75 
~I18nCalendarAddon()76 I18nCalendarAddon::~I18nCalendarAddon() {}
77 
Destructor(napi_env env,void * nativeObject,void * hint)78 void I18nCalendarAddon::Destructor(napi_env env, void *nativeObject, void *hint)
79 {
80     if (!nativeObject) {
81         return;
82     }
83     delete reinterpret_cast<I18nCalendarAddon *>(nativeObject);
84     nativeObject = nullptr;
85 }
86 
InitI18nCalendar(napi_env env,napi_value exports)87 napi_value I18nCalendarAddon::InitI18nCalendar(napi_env env, napi_value exports)
88 {
89     napi_property_descriptor properties[] = {
90         DECLARE_NAPI_FUNCTION("setTime", SetTime),
91         DECLARE_NAPI_FUNCTION("set", Set),
92         DECLARE_NAPI_FUNCTION("getTimeZone", GetTimeZone),
93         DECLARE_NAPI_FUNCTION("setTimeZone", SetTimeZone),
94         DECLARE_NAPI_FUNCTION("getFirstDayOfWeek", GetFirstDayOfWeek),
95         DECLARE_NAPI_FUNCTION("setFirstDayOfWeek", SetFirstDayOfWeek),
96         DECLARE_NAPI_FUNCTION("getMinimalDaysInFirstWeek", GetMinimalDaysInFirstWeek),
97         DECLARE_NAPI_FUNCTION("setMinimalDaysInFirstWeek", SetMinimalDaysInFirstWeek),
98         DECLARE_NAPI_FUNCTION("get", Get),
99         DECLARE_NAPI_FUNCTION("add", Add),
100         DECLARE_NAPI_FUNCTION("getDisplayName", GetDisplayName),
101         DECLARE_NAPI_FUNCTION("getTimeInMillis", GetTimeInMillis),
102         DECLARE_NAPI_FUNCTION("isWeekend", IsWeekend),
103         DECLARE_NAPI_FUNCTION("compareDays", CompareDays)
104     };
105     napi_value constructor = nullptr;
106     napi_status status = napi_define_class(env, "Calendar", NAPI_AUTO_LENGTH, I18nCalendarConstructor, nullptr,
107         sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
108     if (status != napi_ok) {
109         HILOG_ERROR_I18N("Failed to define class at Init");
110         return nullptr;
111     }
112     exports = I18nCalendarAddon::InitCalendar(env, exports);
113     g_constructor = new (std::nothrow) napi_ref;
114     if (!g_constructor) {
115         HILOG_ERROR_I18N("Failed to create ref at init");
116         return nullptr;
117     }
118     status = napi_create_reference(env, constructor, 1, g_constructor);
119     if (status != napi_ok) {
120         HILOG_ERROR_I18N("Failed to create reference at init");
121         return nullptr;
122     }
123     return exports;
124 }
125 
InitCalendar(napi_env env,napi_value exports)126 napi_value I18nCalendarAddon::InitCalendar(napi_env env, napi_value exports)
127 {
128     napi_property_descriptor properties[] = {};
129     napi_value constructor = nullptr;
130     napi_status status = napi_define_class(env, "I18nCalendar", NAPI_AUTO_LENGTH, JSUtils::DefaultConstructor, nullptr,
131         sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
132     if (status != napi_ok) {
133         HILOG_ERROR_I18N("InitCalendar: Failed to define class Calendar.");
134         return nullptr;
135     }
136     status = napi_set_named_property(env, exports, "Calendar", constructor);
137     if (status != napi_ok) {
138         HILOG_ERROR_I18N("InitCalendar: Set property failed When InitCalendar.");
139         return nullptr;
140     }
141     return exports;
142 }
143 
GetCalendar(napi_env env,napi_callback_info info)144 napi_value I18nCalendarAddon::GetCalendar(napi_env env, napi_callback_info info)
145 {
146     size_t argc = 2; // retrieve 2 arguments
147     napi_value argv[2] = { 0 };
148     argv[0] = nullptr;
149     argv[1] = nullptr;
150     napi_value thisVar = nullptr;
151     void *data = nullptr;
152     napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
153     napi_value constructor = nullptr;
154     napi_status status = napi_get_reference_value(env, *g_constructor, &constructor);
155     if (status != napi_ok) {
156         HILOG_ERROR_I18N("Failed to create reference at GetCalendar");
157         return nullptr;
158     }
159     napi_valuetype valueType = napi_valuetype::napi_undefined;
160     napi_typeof(env, argv[1], &valueType);
161     if (valueType != napi_valuetype::napi_string) {
162         status = napi_create_string_utf8(env, "", NAPI_AUTO_LENGTH, argv + 1);
163         if (status != napi_ok) {
164             return nullptr;
165         }
166     }
167     napi_value result = nullptr;
168     status = napi_new_instance(env, constructor, 2, argv, &result); // 2 arguments
169     if (status != napi_ok) {
170         HILOG_ERROR_I18N("Get calendar create instance failed");
171         return nullptr;
172     }
173     return result;
174 }
175 
I18nCalendarConstructor(napi_env env,napi_callback_info info)176 napi_value I18nCalendarAddon::I18nCalendarConstructor(napi_env env, napi_callback_info info)
177 {
178     size_t argc = 2;
179     napi_value argv[2] = { 0 };
180     argv[0] = nullptr;
181     argv[1] = nullptr;
182     napi_value thisVar = nullptr;
183     void *data = nullptr;
184     napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
185     if (status != napi_ok) {
186         return nullptr;
187     }
188     napi_valuetype valueType = napi_valuetype::napi_undefined;
189     napi_typeof(env, argv[0], &valueType);
190     if (valueType != napi_valuetype::napi_string) {
191         HILOG_ERROR_I18N("CalendarConstructor: Parameter type does not match");
192         return nullptr;
193     }
194     int32_t code = 0;
195     std::string localeTag = VariableConvertor::GetString(env, argv[0], code);
196     if (code) {
197         return nullptr;
198     }
199     CalendarType type = GetCalendarType(env, argv[1]);
200     std::unique_ptr<I18nCalendarAddon> obj = nullptr;
201     obj = std::make_unique<I18nCalendarAddon>();
202     status =
203         napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()), I18nCalendarAddon::Destructor, nullptr, nullptr);
204     if (status != napi_ok) {
205         HILOG_ERROR_I18N("CalendarConstructor: Wrap II18nAddon failed");
206         return nullptr;
207     }
208     if (!obj->InitCalendarContext(env, info, localeTag, type)) {
209         return nullptr;
210     }
211     obj.release();
212     return thisVar;
213 }
214 
SetTime(napi_env env,napi_callback_info info)215 napi_value I18nCalendarAddon::SetTime(napi_env env, napi_callback_info info)
216 {
217     size_t argc = 1;
218     napi_value argv[1] = { 0 };
219     argv[0] = nullptr;
220     napi_value thisVar = nullptr;
221     void *data = nullptr;
222     napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
223     if (!argv[0]) {
224         return nullptr;
225     }
226     I18nCalendarAddon *obj = nullptr;
227     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
228     if (status != napi_ok || !obj || !obj->calendar_) {
229         HILOG_ERROR_I18N("SetTime: Get calendar object failed");
230         return nullptr;
231     }
232     napi_valuetype type = napi_valuetype::napi_undefined;
233     status = napi_typeof(env, argv[0], &type);
234     if (status != napi_ok) {
235         return nullptr;
236     }
237     if (type == napi_valuetype::napi_number) {
238         obj->SetMilliseconds(env, argv[0]);
239         return nullptr;
240     } else {
241         napi_value val = GetDate(env, argv[0]);
242         if (!val) {
243             return nullptr;
244         }
245         obj->SetMilliseconds(env, val);
246         return nullptr;
247     }
248 }
249 
Set(napi_env env,napi_callback_info info)250 napi_value I18nCalendarAddon::Set(napi_env env, napi_callback_info info)
251 {
252     size_t argc = 6; // Set may have 6 arguments
253     napi_value argv[6] = { 0 };
254     for (size_t i = 0; i < argc; ++i) {
255         argv[i] = nullptr;
256     }
257     napi_value thisVar = nullptr;
258     void *data = nullptr;
259     napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
260     napi_valuetype valueType = napi_valuetype::napi_undefined;
261     napi_status status = napi_ok;
262     int32_t times[3] = { 0 }; // There are at least 3 arguments.
263     for (int i = 0; i < 3; ++i) { // There are at least 3 arguments.
264         napi_typeof(env, argv[i], &valueType);
265         if (valueType != napi_valuetype::napi_number) {
266             HILOG_ERROR_I18N("Set: Parameter type does not match");
267             return nullptr;
268         }
269         status = napi_get_value_int32(env, argv[i], times + i);
270         if (status != napi_ok) {
271             HILOG_ERROR_I18N("Set: Retrieve time value failed");
272             return nullptr;
273         }
274     }
275     I18nCalendarAddon *obj = nullptr;
276     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
277     if (status != napi_ok || !obj || !obj->calendar_) {
278         HILOG_ERROR_I18N("Set: Get calendar object failed");
279         return nullptr;
280     }
281     obj->calendar_->Set(times[0], times[1], times[2]); // 2 is the index of date
282     obj->SetField(env, argv[3], UCalendarDateFields::UCAL_HOUR_OF_DAY); // 3 is the index of hour
283     obj->SetField(env, argv[4], UCalendarDateFields::UCAL_MINUTE); // 4 is the index of minute
284     obj->SetField(env, argv[5], UCalendarDateFields::UCAL_SECOND); // 5 is the index of second
285     return nullptr;
286 }
287 
GetTimeZone(napi_env env,napi_callback_info info)288 napi_value I18nCalendarAddon::GetTimeZone(napi_env env, napi_callback_info info)
289 {
290     size_t argc = 0;
291     napi_value *argv = nullptr;
292     napi_value thisVar = nullptr;
293     void *data = nullptr;
294     napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
295     I18nCalendarAddon *obj = nullptr;
296     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
297     if (status != napi_ok || !obj || !obj->calendar_) {
298         HILOG_ERROR_I18N("GetTimeZone: Get calendar object failed");
299         return nullptr;
300     }
301     std::string temp = obj->calendar_->GetTimeZone();
302     napi_value result = nullptr;
303     status = napi_create_string_utf8(env, temp.c_str(), NAPI_AUTO_LENGTH, &result);
304     if (status != napi_ok) {
305         HILOG_ERROR_I18N("Create timezone string failed");
306         return nullptr;
307     }
308     return result;
309 }
310 
SetTimeZone(napi_env env,napi_callback_info info)311 napi_value I18nCalendarAddon::SetTimeZone(napi_env env, napi_callback_info info)
312 {
313     size_t argc = 1;
314     napi_value argv[1] = { 0 };
315     argv[0] = nullptr;
316     napi_value thisVar = nullptr;
317     void *data = nullptr;
318     napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
319     napi_valuetype valueType = napi_valuetype::napi_undefined;
320     napi_typeof(env, argv[0], &valueType);
321     if (valueType != napi_valuetype::napi_string) {
322         HILOG_ERROR_I18N("SetTimeZone: Parameter type does not match");
323         return nullptr;
324     }
325     size_t len = 0;
326     napi_status status = napi_get_value_string_utf8(env, argv[0], nullptr, 0, &len);
327     if (status != napi_ok) {
328         HILOG_ERROR_I18N("SetTimeZone: Get timezone length failed");
329         return nullptr;
330     }
331     std::vector<char> buf(len + 1);
332     status = napi_get_value_string_utf8(env, argv[0], buf.data(), len + 1, &len);
333     if (status != napi_ok) {
334         HILOG_ERROR_I18N("SetTimeZone: Get timezone failed");
335         return nullptr;
336     }
337     std::string timezone(buf.data());
338     I18nCalendarAddon *obj = nullptr;
339     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
340     if (status != napi_ok || !obj || !obj->calendar_) {
341         HILOG_ERROR_I18N("SetTimeZone: Get calendar object failed");
342         return nullptr;
343     }
344     obj->calendar_->SetTimeZone(timezone);
345     return nullptr;
346 }
347 
GetFirstDayOfWeek(napi_env env,napi_callback_info info)348 napi_value I18nCalendarAddon::GetFirstDayOfWeek(napi_env env, napi_callback_info info)
349 {
350     size_t argc = 0;
351     napi_value *argv = nullptr;
352     napi_value thisVar = nullptr;
353     void *data = nullptr;
354     napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
355     I18nCalendarAddon *obj = nullptr;
356     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
357     if (status != napi_ok || !obj || !obj->calendar_) {
358         HILOG_ERROR_I18N("GetFirstDayOfWeek: Get calendar object failed");
359         return nullptr;
360     }
361     int32_t temp = obj->calendar_->GetFirstDayOfWeek();
362     napi_value result = nullptr;
363     status = napi_create_int32(env, temp, &result);
364     if (status != napi_ok) {
365         HILOG_ERROR_I18N("GetFirstDayOfWeek: Create int32 failed");
366         return nullptr;
367     }
368     return result;
369 }
370 
SetFirstDayOfWeek(napi_env env,napi_callback_info info)371 napi_value I18nCalendarAddon::SetFirstDayOfWeek(napi_env env, napi_callback_info info)
372 {
373     size_t argc = 1;
374     napi_value argv[1] = { 0 };
375     argv[0] = nullptr;
376     napi_value thisVar = nullptr;
377     void *data = nullptr;
378     napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
379     napi_valuetype valueType = napi_valuetype::napi_undefined;
380     napi_typeof(env, argv[0], &valueType);
381     if (valueType != napi_valuetype::napi_number) {
382         HILOG_ERROR_I18N("SetFirstDayOfWeek: Parameter type does not match");
383         return nullptr;
384     }
385     int32_t value = 0;
386     napi_status status = napi_get_value_int32(env, argv[0], &value);
387     if (status != napi_ok) {
388         HILOG_ERROR_I18N("SetFirstDayOfWeek: Get int32 failed");
389         return nullptr;
390     }
391     I18nCalendarAddon *obj = nullptr;
392     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
393     if (status != napi_ok || !obj || !obj->calendar_) {
394         HILOG_ERROR_I18N("SetFirstDayOfWeek: Get calendar object failed");
395         return nullptr;
396     }
397     obj->calendar_->SetFirstDayOfWeek(value);
398     return nullptr;
399 }
400 
GetMinimalDaysInFirstWeek(napi_env env,napi_callback_info info)401 napi_value I18nCalendarAddon::GetMinimalDaysInFirstWeek(napi_env env, napi_callback_info info)
402 {
403     size_t argc = 0;
404     napi_value *argv = nullptr;
405     napi_value thisVar = nullptr;
406     void *data = nullptr;
407     napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
408     I18nCalendarAddon *obj = nullptr;
409     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
410     if (status != napi_ok || !obj || !obj->calendar_) {
411         HILOG_ERROR_I18N("GetMinimalDaysInFirstWeek: Get calendar object failed");
412         return nullptr;
413     }
414     int32_t temp = obj->calendar_->GetMinimalDaysInFirstWeek();
415     napi_value result = nullptr;
416     status = napi_create_int32(env, temp, &result);
417     if (status != napi_ok) {
418         HILOG_ERROR_I18N("GetMinimalDaysInFirstWeek: Create int32 failed");
419         return nullptr;
420     }
421     return result;
422 }
423 
SetMinimalDaysInFirstWeek(napi_env env,napi_callback_info info)424 napi_value I18nCalendarAddon::SetMinimalDaysInFirstWeek(napi_env env, napi_callback_info info)
425 {
426     size_t argc = 1;
427     napi_value argv[1] = { 0 };
428     argv[0] = nullptr;
429     napi_value thisVar = nullptr;
430     void *data = nullptr;
431     napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
432     napi_valuetype valueType = napi_valuetype::napi_undefined;
433     napi_typeof(env, argv[0], &valueType);
434     if (valueType != napi_valuetype::napi_number) {
435         HILOG_ERROR_I18N("SetMinimalDaysInFirstWeek: Parameter type does not match");
436         return nullptr;
437     }
438     int32_t value = 0;
439     napi_status status = napi_get_value_int32(env, argv[0], &value);
440     if (status != napi_ok) {
441         HILOG_ERROR_I18N("SetMinimalDaysInFirstWeek: Get int32 failed");
442         return nullptr;
443     }
444     I18nCalendarAddon *obj = nullptr;
445     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
446     if (status != napi_ok || !obj || !obj->calendar_) {
447         HILOG_ERROR_I18N("SetMinimalDaysInFirstWeek: Get calendar object failed");
448         return nullptr;
449     }
450     obj->calendar_->SetMinimalDaysInFirstWeek(value);
451     return nullptr;
452 }
453 
Get(napi_env env,napi_callback_info info)454 napi_value I18nCalendarAddon::Get(napi_env env, napi_callback_info info)
455 {
456     size_t argc = 1;
457     napi_value argv[1] = { 0 };
458     argv[0] = nullptr;
459     napi_value thisVar = nullptr;
460     void *data = nullptr;
461     napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
462     napi_valuetype valueType = napi_valuetype::napi_undefined;
463     napi_typeof(env, argv[0], &valueType);
464     if (valueType != napi_valuetype::napi_string) {
465         HILOG_ERROR_I18N("Get: Parameter type does not match");
466         return nullptr;
467     }
468     size_t len = 0;
469     napi_status status = napi_get_value_string_utf8(env, argv[0], nullptr, 0, &len);
470     if (status != napi_ok) {
471         HILOG_ERROR_I18N("Get field length failed");
472         return nullptr;
473     }
474     std::vector<char> buf(len + 1);
475     status = napi_get_value_string_utf8(env, argv[0], buf.data(), len + 1, &len);
476     if (status != napi_ok) {
477         HILOG_ERROR_I18N("Get field failed");
478         return nullptr;
479     }
480     std::string field(buf.data());
481     if (g_fieldsMap.find(field) == g_fieldsMap.end()) {
482         HILOG_ERROR_I18N("Invalid field");
483         return nullptr;
484     }
485     I18nCalendarAddon *obj = nullptr;
486     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
487     if (status != napi_ok || !obj || !obj->calendar_) {
488         HILOG_ERROR_I18N("Get: Get calendar object failed");
489         return nullptr;
490     }
491     int32_t value = obj->calendar_->Get(g_fieldsMap[field]);
492     napi_value result = nullptr;
493     status = napi_create_int32(env, value, &result);
494     if (status != napi_ok) {
495         HILOG_ERROR_I18N("Get: Create int32 failed");
496         return nullptr;
497     }
498     return result;
499 }
500 
Add(napi_env env,napi_callback_info info)501 napi_value I18nCalendarAddon::Add(napi_env env, napi_callback_info info)
502 {
503     size_t argc = 2;
504     napi_value argv[2] = { 0 };
505     napi_value thisVar = nullptr;
506     void *data = nullptr;
507     napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
508     if (status != napi_ok) {
509         HILOG_ERROR_I18N("Add: can not obtain add function param.");
510         return nullptr;
511     }
512     napi_valuetype valueType = napi_valuetype::napi_undefined;
513     napi_typeof(env, argv[0], &valueType);
514     if (valueType != napi_valuetype::napi_string) {
515         HILOG_ERROR_I18N("Parameter type does not match argv[0]");
516         ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "field", "string", true);
517         return nullptr;
518     }
519     int32_t code = 0;
520     std::string field = GetAddField(env, argv[0], code);
521     if (code) {
522         return nullptr;
523     }
524     napi_typeof(env, argv[1], &valueType);
525     if (valueType != napi_valuetype::napi_number) {
526         HILOG_ERROR_I18N("Parameter type does not match argv[1]");
527         ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "amount", "number", true);
528         return nullptr;
529     }
530     int32_t amount;
531     status = napi_get_value_int32(env, argv[1], &amount);
532     if (status != napi_ok) {
533         HILOG_ERROR_I18N("Add: Can not obtain add function param.");
534         return nullptr;
535     }
536     I18nCalendarAddon *obj = nullptr;
537     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
538     if (status != napi_ok || !obj || !obj->calendar_) {
539         HILOG_ERROR_I18N("Add: Get calendar object failed");
540         return nullptr;
541     }
542     obj->calendar_->Add(g_fieldsMap[field], amount);
543     return nullptr;
544 }
545 
GetDisplayName(napi_env env,napi_callback_info info)546 napi_value I18nCalendarAddon::GetDisplayName(napi_env env, napi_callback_info info)
547 {
548     size_t argc = 1;
549     napi_value argv[1] = { 0 };
550     argv[0] = nullptr;
551     napi_value thisVar = nullptr;
552     void *data = nullptr;
553     napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
554     napi_valuetype valueType = napi_valuetype::napi_undefined;
555     napi_typeof(env, argv[0], &valueType);
556     if (valueType != napi_valuetype::napi_string) {
557         HILOG_ERROR_I18N("GetDisplayName: Parameter type does not match");
558         return nullptr;
559     }
560     int32_t code = 0;
561     std::string localeTag = VariableConvertor::GetString(env, argv[0], code);
562     if (code) {
563         return nullptr;
564     }
565     I18nCalendarAddon *obj = nullptr;
566     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
567     if (status != napi_ok || !obj || !obj->calendar_) {
568         HILOG_ERROR_I18N("GetDisplayName: Get calendar object failed");
569         return nullptr;
570     }
571     if (!obj->calendar_) {
572         return nullptr;
573     }
574     std::string name = obj->calendar_->GetDisplayName(localeTag);
575     napi_value result = nullptr;
576     status = napi_create_string_utf8(env, name.c_str(), NAPI_AUTO_LENGTH, &result);
577     if (status != napi_ok) {
578         HILOG_ERROR_I18N("Create calendar name string failed");
579         return nullptr;
580     }
581     return result;
582 }
583 
GetTimeInMillis(napi_env env,napi_callback_info info)584 napi_value I18nCalendarAddon::GetTimeInMillis(napi_env env, napi_callback_info info)
585 {
586     bool flag = true;
587     size_t argc = 0;
588     napi_value *argv = nullptr;
589     napi_value thisVar = nullptr;
590     void *data = nullptr;
591     napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
592     I18nCalendarAddon *obj = nullptr;
593     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
594     if (status != napi_ok || !obj || !obj->calendar_) {
595         HILOG_ERROR_I18N("GetTimeInMillis: Get calendar object failed");
596         flag = false;
597     }
598     UDate temp = 0;
599     if (flag) {
600         temp = obj->calendar_->GetTimeInMillis();
601     }
602     napi_value result = nullptr;
603     status = napi_create_double(env, temp, &result);
604     if (status != napi_ok) {
605         HILOG_ERROR_I18N("Create UDate failed");
606         napi_create_double(env, 0, &result);
607     }
608     return result;
609 }
610 
IsWeekend(napi_env env,napi_callback_info info)611 napi_value I18nCalendarAddon::IsWeekend(napi_env env, napi_callback_info info)
612 {
613     size_t argc = 1;
614     napi_value argv[1] = { 0 };
615     argv[0] = nullptr;
616     napi_value thisVar = nullptr;
617     void *data = nullptr;
618     napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
619     I18nCalendarAddon *obj = nullptr;
620     bool isWeekEnd = false;
621     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
622     do {
623         if (status != napi_ok || !obj || !obj->calendar_) {
624             HILOG_ERROR_I18N("IsWeekend: Get calendar object failed");
625             break;
626         }
627         if (!VariableConvertor::CheckNapiValueType(env, argv[0])) {
628             isWeekEnd = obj->calendar_->IsWeekend();
629         } else {
630             napi_value funcGetDateInfo = nullptr;
631             status = napi_get_named_property(env, argv[0], "valueOf", &funcGetDateInfo);
632             if (status != napi_ok) {
633                 HILOG_ERROR_I18N("Get method now failed");
634                 break;
635             }
636             napi_value value = nullptr;
637             status = napi_call_function(env, argv[0], funcGetDateInfo, 0, nullptr, &value);
638             if (status != napi_ok) {
639                 HILOG_ERROR_I18N("IsWeekend: Get milliseconds failed");
640                 break;
641             }
642             double milliseconds = 0;
643             status = napi_get_value_double(env, value, &milliseconds);
644             if (status != napi_ok) {
645                 HILOG_ERROR_I18N("IsWeekend: Retrieve milliseconds failed");
646                 break;
647             }
648             UErrorCode error = U_ZERO_ERROR;
649             isWeekEnd = obj->calendar_->IsWeekend(milliseconds, error);
650         }
651     } while (false);
652     napi_value result = nullptr;
653     status = napi_get_boolean(env, isWeekEnd, &result);
654     if (status != napi_ok) {
655         HILOG_ERROR_I18N("Create boolean failed");
656         return nullptr;
657     }
658     return result;
659 }
660 
CompareDays(napi_env env,napi_callback_info info)661 napi_value I18nCalendarAddon::CompareDays(napi_env env, napi_callback_info info)
662 {
663     size_t argc = 1;
664     napi_value argv[1] = { 0 };
665     napi_value thisVar = nullptr;
666     void *data = nullptr;
667     napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
668     napi_value result = nullptr;
669     UDate milliseconds = 0;
670     napi_status status = napi_get_date_value(env, argv[0], &milliseconds);
671     if (status != napi_ok) {
672         HILOG_ERROR_I18N("compareDays: function param is not Date");
673         return nullptr;
674     }
675 
676     I18nCalendarAddon *obj = nullptr;
677     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
678     if (status != napi_ok || !obj || !obj->calendar_) {
679         HILOG_ERROR_I18N("CompareDays: Get calendar object failed");
680         status = napi_create_int32(env, 0, &result); // if error return 0
681         return result;
682     }
683 
684     int32_t diff_date = obj->calendar_->CompareDays(milliseconds);
685     status = napi_create_int32(env, diff_date, &result);
686     return result;
687 }
688 
InitCalendarContext(napi_env env,napi_callback_info info,const std::string & localeTag,CalendarType type)689 bool I18nCalendarAddon::InitCalendarContext(napi_env env, napi_callback_info info, const std::string &localeTag,
690     CalendarType type)
691 {
692     calendar_ = std::make_unique<I18nCalendar>(localeTag, type);
693     return calendar_ != nullptr;
694 }
695 
GetCalendarType(napi_env env,napi_value value)696 CalendarType I18nCalendarAddon::GetCalendarType(napi_env env, napi_value value)
697 {
698     CalendarType type = CalendarType::UNDEFINED;
699     if (value != nullptr) {
700         napi_valuetype valueType = napi_valuetype::napi_undefined;
701         napi_typeof(env, value, &valueType);
702         if (valueType != napi_valuetype::napi_string) {
703             HILOG_ERROR_I18N("GetCalendarType: Parameter type does not match");
704             return type;
705         }
706         int32_t code = 0;
707         std::string calendarType = VariableConvertor::GetString(env, value, code);
708         if (code) {
709             return type;
710         }
711         if (g_typeMap.find(calendarType) != g_typeMap.end()) {
712             type = g_typeMap[calendarType];
713         }
714     }
715     return type;
716 }
717 
SetField(napi_env env,napi_value value,UCalendarDateFields field)718 void I18nCalendarAddon::SetField(napi_env env, napi_value value, UCalendarDateFields field)
719 {
720     if (!VariableConvertor::CheckNapiValueType(env, value)) {
721         return;
722     }
723     int32_t val = 0;
724     napi_valuetype valueType = napi_valuetype::napi_undefined;
725     napi_typeof(env, value, &valueType);
726     if (valueType != napi_valuetype::napi_number) {
727         HILOG_ERROR_I18N("SetField: Parameter type does not match");
728         return;
729     }
730     napi_status status = napi_get_value_int32(env, value, &val);
731     if (status != napi_ok) {
732         HILOG_ERROR_I18N("SetField: Retrieve field failed");
733         return;
734     }
735     if (calendar_ != nullptr) {
736         calendar_->Set(field, val);
737     }
738 }
739 
GetAddField(napi_env & env,napi_value & value,int32_t & code)740 std::string I18nCalendarAddon::GetAddField(napi_env &env, napi_value &value, int32_t &code)
741 {
742     std::string field = VariableConvertor::GetString(env, value, code);
743     if (code != 0) {
744         HILOG_ERROR_I18N("GetAddField: can't get string from js array param.");
745         return field;
746     }
747     if (g_fieldsInFunctionAdd.find(field) == g_fieldsInFunctionAdd.end()) {
748         code = 1;
749         HILOG_ERROR_I18N("Parameter rangs do not match");
750         ErrorUtil::NapiThrow(env, I18N_NOT_VALID, "field", "a valid field", true);
751         return field;
752     }
753     return field;
754 }
755 
GetDate(napi_env env,napi_value value)756 napi_value I18nCalendarAddon::GetDate(napi_env env, napi_value value)
757 {
758     if (!value) {
759         return nullptr;
760     }
761     napi_value funcGetDateInfo = nullptr;
762     napi_status status = napi_get_named_property(env, value, "valueOf", &funcGetDateInfo);
763     if (status != napi_ok) {
764         HILOG_ERROR_I18N("Get method valueOf failed");
765         return nullptr;
766     }
767     napi_value ret_value = nullptr;
768     status = napi_call_function(env, value, funcGetDateInfo, 0, nullptr, &ret_value);
769     if (status != napi_ok) {
770         HILOG_ERROR_I18N("GetDate: Get milliseconds failed");
771         return nullptr;
772     }
773     return ret_value;
774 }
775 
SetMilliseconds(napi_env env,napi_value value)776 void I18nCalendarAddon::SetMilliseconds(napi_env env, napi_value value)
777 {
778     if (!value) {
779         return;
780     }
781     double milliseconds = 0;
782     napi_valuetype valueType = napi_valuetype::napi_undefined;
783     napi_typeof(env, value, &valueType);
784     if (valueType != napi_valuetype::napi_number) {
785         HILOG_ERROR_I18N("SetMilliseconds: Parameter type does not match");
786         return;
787     }
788     napi_status status = napi_get_value_double(env, value, &milliseconds);
789     if (status != napi_ok) {
790         HILOG_ERROR_I18N("SetMilliseconds: Retrieve milliseconds failed");
791         return;
792     }
793     if (calendar_ != nullptr) {
794         calendar_->SetTime(milliseconds);
795     }
796 }
797 
798 } // namespace I18n
799 } // namespace Global
800 } // namespace OHOS