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 <vector>
17#include "error_util.h"
18#include "i18n_hilog.h"
19#include "locale_config.h"
20#include "variable_convertor.h"
21#include "holiday_manager_addon.h"
22
23namespace OHOS {
24namespace Global {
25namespace I18n {
26HolidayManagerAddon::HolidayManagerAddon() : env_(nullptr) {}
27
28HolidayManagerAddon::~HolidayManagerAddon()
29{
30}
31
32void HolidayManagerAddon::Destructor(napi_env env, void *nativeObject, void *hint)
33{
34    if (!nativeObject) {
35        return;
36    }
37    delete reinterpret_cast<HolidayManagerAddon *>(nativeObject);
38    nativeObject = nullptr;
39}
40
41napi_value HolidayManagerAddon::InitHolidayManager(napi_env env, napi_value exports)
42{
43    napi_status status = napi_ok;
44    napi_property_descriptor properties[] = {
45        DECLARE_NAPI_FUNCTION("isHoliday", IsHoliday),
46        DECLARE_NAPI_FUNCTION("getHolidayInfoItemArray", GetHolidayInfoItemArray)
47    };
48
49    napi_value constructor = nullptr;
50    status = napi_define_class(env, "HolidayManager", NAPI_AUTO_LENGTH, HolidayManagerConstructor, nullptr,
51        sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
52    if (status != napi_ok) {
53        HILOG_ERROR_I18N("Define class failed when InitHolidayManager");
54        return nullptr;
55    }
56
57    status = napi_set_named_property(env, exports, "HolidayManager", constructor);
58    if (status != napi_ok) {
59        HILOG_ERROR_I18N("Set property failed when InitHolidayManager");
60        return nullptr;
61    }
62    return exports;
63}
64
65napi_value HolidayManagerAddon::HolidayManagerConstructor(napi_env env, napi_callback_info info)
66{
67    size_t argc = 1;
68    napi_value argv[1] = { 0 };
69    napi_value thisVar = nullptr;
70    void *data = nullptr;
71    napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
72    if (status != napi_ok) {
73        return nullptr;
74    } else if (argc < 1) {
75        ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "icsPath", "", true);
76        return nullptr;
77    }
78    napi_valuetype valueType = napi_valuetype::napi_undefined;
79    napi_typeof(env, argv[0], &valueType);
80    if (valueType != napi_valuetype::napi_string) {
81        ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "icsPath", "string", true);
82        return nullptr;
83    }
84    std::unique_ptr<HolidayManagerAddon> obj = std::make_unique<HolidayManagerAddon>();
85    status =
86        napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()), HolidayManagerAddon::Destructor, nullptr, nullptr);
87    if (status != napi_ok) {
88        HILOG_ERROR_I18N("Wrap HolidayManagerAddon failed");
89        return nullptr;
90    }
91    int32_t code = 0;
92    std::string path = VariableConvertor::GetString(env, argv[0], code);
93    if (code) {
94        return nullptr;
95    }
96    if (!obj->InitHolidayManagerContext(env, info, path.c_str())) {
97        HILOG_ERROR_I18N("Init HolidayManager failed");
98        return nullptr;
99    }
100    obj.release();
101    return thisVar;
102}
103
104bool HolidayManagerAddon::InitHolidayManagerContext(napi_env env, napi_callback_info info, const char* path)
105{
106    napi_value global = nullptr;
107    napi_status status = napi_get_global(env, &global);
108    if (status != napi_ok) {
109        HILOG_ERROR_I18N("Get global failed");
110        return false;
111    }
112    env_ = env;
113    holidayManager_ = std::make_unique<HolidayManager>(path);
114    return holidayManager_ != nullptr;
115}
116
117napi_value HolidayManagerAddon::IsHoliday(napi_env env, napi_callback_info info)
118{
119    size_t argc = 1;
120    napi_value argv[1] = { 0 };
121    napi_value thisVar = nullptr;
122    napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL);
123    if (status != napi_ok) {
124        return nullptr;
125    }
126    HolidayManagerAddon *obj = nullptr;
127    status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
128    if (status != napi_ok || !obj || !obj->holidayManager_) {
129        HILOG_ERROR_I18N("IsHoliday: Get HolidayManager object failed");
130        return nullptr;
131    }
132    napi_value result = nullptr;
133    bool flag = VariableConvertor::CheckNapiValueType(env, argv[0]);
134    bool res = false;
135    if (flag) {
136        std::vector<int> list = ValidateParamDate(env, argv[0]);
137        if (list.size() == 3) { // 3 is the number of parameters
138            // 0, 1, and 2 indicate that the first, second, and third parameters of the list are read
139            res = obj->holidayManager_->IsHoliday(list.at(0), list.at(1), list.at(2));
140        }
141    } else {
142        res = obj->holidayManager_->IsHoliday();
143    }
144    status = napi_get_boolean(env, res, &result);
145    return result;
146}
147
148napi_value HolidayManagerAddon::GetHolidayInfoItemArray(napi_env env, napi_callback_info info)
149{
150    size_t argc = 1;
151    napi_value argv[1] = { 0 };
152    argv[0] = nullptr;
153    napi_value thisVar = nullptr;
154    napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL);
155    if (status != napi_ok) {
156        return nullptr;
157    }
158    HolidayManagerAddon *obj = nullptr;
159    status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
160    if (status != napi_ok || !obj || !obj->holidayManager_) {
161        HILOG_ERROR_I18N("GetHolidayInfoItemArray: Get HolidayManager object failed");
162        return nullptr;
163    }
164    bool flag = VariableConvertor::CheckNapiValueType(env, argv[0]);
165    if (flag) {
166        int32_t year = ValidateParamNumber(env, argv[0]);
167        std::vector<HolidayInfoItem> itemList = obj->holidayManager_->GetHolidayInfoItemArray(year);
168        return GetHolidayInfoItemResult(env, itemList);
169    } else {
170        std::vector<HolidayInfoItem> itemList = obj->holidayManager_->GetHolidayInfoItemArray();
171        return GetHolidayInfoItemResult(env, itemList);
172    }
173}
174
175napi_value HolidayManagerAddon::GetHolidayInfoItemResult(napi_env env, std::vector<HolidayInfoItem> itemList)
176{
177    napi_value result = nullptr;
178    napi_status status = napi_create_array_with_length(env, itemList.size(), &result);
179    if (status != napi_ok) {
180        HILOG_ERROR_I18N("create HolidayInfoItem array failed.");
181        return nullptr;
182    }
183    for (size_t i = 0; i < itemList.size(); i++) {
184        napi_value item = CreateHolidayItem(env, itemList[i]);
185        status = napi_set_element(env, result, i, item);
186        if (status != napi_ok) {
187            HILOG_ERROR_I18N("Failed to set HolidayInfoItem element.");
188            return nullptr;
189        }
190    }
191    return result;
192}
193
194std::vector<int> HolidayManagerAddon::ValidateParamDate(napi_env &env, napi_value &argv)
195{
196    std::vector<int> list;
197    napi_valuetype valueType = napi_valuetype::napi_undefined;
198    napi_typeof(env, argv, &valueType);
199    if (valueType != napi_valuetype::napi_object) {
200        ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "date", "Date object", true);
201        return list;
202    }
203    list.push_back(GetDateValue(env, argv, "getFullYear"));
204    list.push_back(GetDateValue(env, argv, "getMonth") + MONTH_INCREASE_ONE);
205    list.push_back(GetDateValue(env, argv, "getDate"));
206    return list;
207}
208
209int HolidayManagerAddon::GetDateValue(napi_env env, napi_value value, const std::string method)
210{
211    int val = 0;
212    if (!value) {
213        return val;
214    }
215    napi_value funcGetDateInfo = nullptr;
216    napi_status status = napi_get_named_property(env, value, method.c_str(), &funcGetDateInfo);
217    if (status != napi_ok) {
218        HILOG_ERROR_I18N("Get method %{public}s failed", method.c_str());
219        return val;
220    }
221    napi_value ret_value = nullptr;
222    status = napi_call_function(env, value, funcGetDateInfo, 0, nullptr, &ret_value);
223    if (status != napi_ok) {
224        HILOG_ERROR_I18N("Get milliseconds failed");
225        return val;
226    }
227
228    status = napi_get_value_int32(env, ret_value, &val);
229    if (status != napi_ok) {
230        HILOG_ERROR_I18N("GetDateValue: Retrieve field failed");
231        return val;
232    }
233    return val;
234}
235
236int32_t HolidayManagerAddon::ValidateParamNumber(napi_env &env, napi_value &argv)
237{
238    napi_valuetype valueType = napi_valuetype::napi_undefined;
239    napi_typeof(env, argv, &valueType);
240    if (valueType != napi_valuetype::napi_number) {
241        ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "year", "number", true);
242        return -1;
243    }
244    int32_t val = 0;
245    napi_status status = napi_get_value_int32(env, argv, &val);
246    if (status != napi_ok) {
247        HILOG_ERROR_I18N("ValidateParamNumber: Retrieve field failed");
248        return -1;
249    }
250    if (val < 0) {
251        ErrorUtil::NapiThrow(env, I18N_NOT_VALID, "year", "a non-negative number", true);
252        return -1;
253    }
254    return val;
255}
256
257napi_value HolidayManagerAddon::CreateHolidayItem(napi_env env, const HolidayInfoItem &holidayItem)
258{
259    napi_value result;
260    napi_status status = napi_create_object(env, &result);
261    if (status != napi_ok) {
262        HILOG_ERROR_I18N("Create Holiday Item object failed.");
263        return nullptr;
264    }
265    status = napi_set_named_property(env, result, "baseName",
266        VariableConvertor::CreateString(env, holidayItem.baseName));
267    if (status != napi_ok) {
268        HILOG_ERROR_I18N("Failed to set element baseName.");
269        return nullptr;
270    }
271    status = napi_set_named_property(env, result, "year",
272                                     VariableConvertor::CreateNumber(env, holidayItem.year));
273    if (status != napi_ok) {
274        HILOG_ERROR_I18N("Failed to set element year.");
275        return nullptr;
276    }
277    status = napi_set_named_property(env, result, "month",
278                                     VariableConvertor::CreateNumber(env, holidayItem.month));
279    if (status != napi_ok) {
280        HILOG_ERROR_I18N("Failed to set element month.");
281        return nullptr;
282    }
283    status = napi_set_named_property(env, result, "day",
284                                     VariableConvertor::CreateNumber(env, holidayItem.day));
285    if (status != napi_ok) {
286        HILOG_ERROR_I18N("Failed to set element day.");
287        return nullptr;
288    }
289    napi_value localNames = HolidayLocalNameItem(env, holidayItem.localNames);
290    if (localNames != nullptr) {
291        status = napi_set_named_property(env, result, "localNames", localNames);
292        if (status != napi_ok) {
293            HILOG_ERROR_I18N("Failed to set element localNames.");
294            return nullptr;
295        }
296    }
297    return result;
298}
299
300napi_value HolidayManagerAddon::HolidayLocalNameItem(napi_env env, const std::vector<HolidayLocalName> localNames)
301{
302    napi_value result = nullptr;
303    napi_status status = napi_create_array_with_length(env, localNames.size(), &result);
304    if (status != napi_ok) {
305        HILOG_ERROR_I18N("create HolidayLocalName array failed.");
306        return nullptr;
307    }
308    for (size_t i = 0; i < localNames.size(); i++) {
309        napi_value localNameItem;
310        status = napi_create_object(env, &localNameItem);
311        if (status != napi_ok) {
312            HILOG_ERROR_I18N("Create HolidayLocalName Item object failed.");
313            return nullptr;
314        }
315        status = napi_set_named_property(env, localNameItem, "language",
316                                         VariableConvertor::CreateString(env, localNames[i].language));
317        if (status != napi_ok) {
318            HILOG_ERROR_I18N("Create HolidayLocalName.language Item object failed.");
319            return nullptr;
320        }
321        status = napi_set_named_property(env, localNameItem, "name",
322                                         VariableConvertor::CreateString(env, localNames[i].name));
323        if (status != napi_ok) {
324            HILOG_ERROR_I18N("Create HolidayLocalName.name Item object failed.");
325            return nullptr;
326        }
327        status = napi_set_element(env, result, i, localNameItem);
328        if (status != napi_ok) {
329            HILOG_ERROR_I18N("Failed to set HolidayLocalName element.");
330            return nullptr;
331        }
332    }
333    return result;
334}
335} // namespace I18n
336} // namespace Global
337} // namespace OHOS