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 <unicode/locid.h>
17#include "error_util.h"
18#include "i18n_hilog.h"
19#include "utils.h"
20#include "variable_convertor.h"
21#include "entity_recognizer_addon.h"
22
23namespace OHOS {
24namespace Global {
25namespace I18n {
26EntityRecognizerAddon::EntityRecognizerAddon() {}
27
28EntityRecognizerAddon::~EntityRecognizerAddon()
29{
30}
31
32void EntityRecognizerAddon::Destructor(napi_env env, void *nativeObject, void *hint)
33{
34    if (!nativeObject) {
35        return;
36    }
37    delete reinterpret_cast<EntityRecognizerAddon *>(nativeObject);
38    nativeObject = nullptr;
39}
40
41napi_value EntityRecognizerAddon::InitEntityRecognizer(napi_env env, napi_value exports)
42{
43    napi_property_descriptor properties[] = {
44        DECLARE_NAPI_FUNCTION("findEntityInfo", FindEntityInfo)
45    };
46    napi_value entityConstructor = nullptr;
47    napi_status status = napi_define_class(env, "EntityRecognizer", NAPI_AUTO_LENGTH, constructor, nullptr,
48        sizeof(properties) / sizeof(napi_property_descriptor), properties, &entityConstructor);
49    if (status != napi_ok) {
50        HILOG_ERROR_I18N("Failed to define class EntityRecognizer at Init.");
51        return nullptr;
52    }
53    status = napi_set_named_property(env, exports, "EntityRecognizer", entityConstructor);
54    if (status != napi_ok) {
55        HILOG_ERROR_I18N("Set property failed when InitEntityRecognizer");
56        return nullptr;
57    }
58    return exports;
59}
60
61napi_value EntityRecognizerAddon::constructor(napi_env env, napi_callback_info info)
62{
63    size_t argc = 1;
64    napi_value argv[1] = { nullptr };
65    napi_value thisVar = nullptr;
66    void *data = nullptr;
67    napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
68    if (status != napi_ok) {
69        return nullptr;
70    }
71    std::string localeStr;
72    if (argc < 1) {
73        localeStr = LocaleConfig::GetSystemLocale();
74    } else {
75        napi_valuetype valueType = napi_valuetype::napi_undefined;
76        napi_typeof(env, argv[0], &valueType);
77        if (valueType != napi_valuetype::napi_string) {
78            ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "locale", "string", true);
79            return nullptr;
80        }
81        int32_t code = 0;
82        localeStr = VariableConvertor::GetString(env, argv[0], code);
83        if (code != 0) {
84            return nullptr;
85        }
86    }
87    UErrorCode localeStatus = U_ZERO_ERROR;
88    icu::Locale locale = icu::Locale::forLanguageTag(localeStr, localeStatus);
89    if (!IsValidLocaleTag(locale)) {
90        ErrorUtil::NapiThrow(env, I18N_NOT_VALID, "locale", "a valid locale", true);
91        return nullptr;
92    }
93    std::unique_ptr<EntityRecognizerAddon> obj = std::make_unique<EntityRecognizerAddon>();
94    status = napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()),
95        EntityRecognizerAddon::Destructor, nullptr, nullptr);
96    if (status != napi_ok) {
97        return nullptr;
98    }
99    obj->entityRecognizer_ = std::make_unique<EntityRecognizer>(locale);
100    if (!obj->entityRecognizer_) {
101        return nullptr;
102    }
103    obj.release();
104    return thisVar;
105}
106
107napi_value EntityRecognizerAddon::FindEntityInfo(napi_env env, napi_callback_info info)
108{
109    size_t argc = 1;
110    napi_value argv[1] = { 0 };
111    napi_value thisVar = nullptr;
112    void *data = nullptr;
113    napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
114    if (status != napi_ok) {
115        return nullptr;
116    } else if (argc < 1) {
117        ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "text", "", true);
118        return nullptr;
119    }
120    napi_valuetype valueType = napi_valuetype::napi_undefined;
121    napi_typeof(env, argv[0], &valueType);
122    if (valueType != napi_valuetype::napi_string) {
123        ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "text", "string", true);
124        return nullptr;
125    }
126    int32_t code = 0;
127    std::string message = VariableConvertor::GetString(env, argv[0], code);
128    if (code != 0) {
129        return nullptr;
130    }
131    EntityRecognizerAddon *obj = nullptr;
132    status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
133    if (status != napi_ok || obj == nullptr || obj->entityRecognizer_ == nullptr) {
134        HILOG_ERROR_I18N("Get EntityRecognizer object failed");
135        return nullptr;
136    }
137    std::vector<std::vector<int>> entityInfo = obj->entityRecognizer_->FindEntityInfo(message);
138    napi_value result = GetEntityInfoItem(env, entityInfo);
139    return result;
140}
141
142napi_value EntityRecognizerAddon::GetEntityInfoItem(napi_env env, std::vector<std::vector<int>>& entityInfo)
143{
144    napi_value result = nullptr;
145    napi_status status = napi_create_array_with_length(env, entityInfo[0][0] + entityInfo[1][0], &result);
146    if (status != napi_ok) {
147        HILOG_ERROR_I18N("create EntityInfo array failed.");
148        return nullptr;
149    }
150    std::vector<std::string> types = {"phone_number", "date"};
151    int index = 0;
152    for (std::string::size_type t = 0; t < types.size(); t++) {
153        for (int i = 0; i < entityInfo[t][0]; i++) {
154            int begin = entityInfo[t][2 * i + 1];
155            int end = entityInfo[t][2 * i + 2];
156            std::string type = types[t];
157            napi_value item = CreateEntityInfoItem(env, begin, end, type);
158            status = napi_set_element(env, result, index, item);
159            index++;
160            if (status != napi_ok) {
161                HILOG_ERROR_I18N("Failed to set item element.");
162                return nullptr;
163            }
164        }
165    }
166    return result;
167}
168
169napi_value EntityRecognizerAddon::CreateEntityInfoItem(napi_env env, const int begin,
170    const int end, const std::string& type)
171{
172    napi_value result;
173    napi_status status = napi_create_object(env, &result);
174    if (status != napi_ok) {
175        HILOG_ERROR_I18N("Create EntityInfoItem object failed.");
176        return nullptr;
177    }
178    status = napi_set_named_property(env, result, "begin",
179        VariableConvertor::CreateNumber(env, begin));
180    if (status != napi_ok) {
181        HILOG_ERROR_I18N("Failed to set element begin.");
182        return nullptr;
183    }
184    status = napi_set_named_property(env, result, "end",
185        VariableConvertor::CreateNumber(env, end));
186    if (status != napi_ok) {
187        HILOG_ERROR_I18N("Failed to set element end.");
188        return nullptr;
189    }
190    status = napi_set_named_property(env, result, "type",
191        VariableConvertor::CreateString(env, type));
192    if (status != napi_ok) {
193        HILOG_ERROR_I18N("Failed to set element type.");
194        return nullptr;
195    }
196    return result;
197}
198
199} // namespace I18n
200} // namespace Global
201} // namespace OHOS