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
16#ifndef ECMASCRIPT_BASE_GLOBAL_INTL_HELPER_H
17#define ECMASCRIPT_BASE_GLOBAL_INTL_HELPER_H
18
19#include <iostream>
20#include <cstdint>
21#include <cmath>
22#include <vector>
23#include <map>
24#include <string>
25#include <chrono>
26#include <math.h>
27
28#include "ecmascript/ecma_vm.h"
29#include "ecmascript/mem/native_area_allocator.h"
30#include "ecmascript/js_handle.h"
31#include "base/global/i18n/frameworks/intl/include/collator.h"
32#if defined(__clang__)
33#pragma clang diagnostic push
34#pragma clang diagnostic ignored "-Wshadow"
35#elif defined(__GNUC__)
36#pragma GCC diagnostic push
37#pragma GCC diagnostic ignored "-Wshadow"
38#endif
39#include "base/global/i18n/frameworks/intl/include/number_format.h"
40#include "base/global/i18n/frameworks/intl/include/date_time_format.h"
41#if defined(__clang__)
42#pragma clang diagnostic pop
43#elif defined(__GNUC__)
44#pragma GCC diagnostic pop
45#endif
46
47namespace panda::ecmascript::intl {
48using GlobalCollator = OHOS::Global::I18n::Collator;
49using GlobalNumberFormat = OHOS::Global::I18n::NumberFormat;
50using GlobalDateFormatter = OHOS::Global::I18n::DateTimeFormat;
51using GlobalCompareResult = OHOS::Global::I18n::CompareResult;
52
53enum class GlobalFormatterType {
54    DateFormatter,
55    SimpleDateFormatDate,
56    SimpleDateFormatTime,
57    NumberFormatter,
58    Collator
59};
60
61class GlobalIntlHelper {
62public:
63    GlobalIntlHelper(JSThread *thread, const GlobalFormatterType matterType);
64    ~GlobalIntlHelper()
65    {
66        if (dateUnitArr != nullptr) {
67            delete[] dateUnitArr;
68        }
69        globalObject = nullptr;
70    }
71
72    template<typename T>
73    std::unique_ptr<T> GetGlobalObject(JSThread *thread, const JSHandle<JSTaggedValue> &locales,
74        const JSHandle<JSTaggedValue> &options, GlobalFormatterType types)
75    {
76        std::vector<std::string> cacheEntryVector;
77        cacheEntryVector = LocalesToVector(thread, locales);
78        std::map<std::string, std::string> inputOptions;
79        if (!options->IsUndefined()) {
80            inputOptions = OptionsToMap(thread, options, types);
81        }
82        auto result = std::make_unique<T>(cacheEntryVector, inputOptions);
83        return result;
84    }
85
86    template<typename T>
87    T *GetGlobalObject(JSThread *thread, const JSHandle<JSTaggedValue> &locales,
88        const JSHandle<JSTaggedValue> &options, GlobalFormatterType types, const bool cache)
89    {
90        IcuFormatterType icuType;
91        switch (types) {
92            case GlobalFormatterType::Collator:
93                icuType = IcuFormatterType::COLLATOR;
94                break;
95            case GlobalFormatterType::SimpleDateFormatDate:
96                icuType = IcuFormatterType::SIMPLE_DATE_FORMAT_DATE;
97                break;
98            case GlobalFormatterType::SimpleDateFormatTime:
99                icuType = IcuFormatterType::SIMPLE_DATE_FORMAT_TIME;
100                break;
101            case GlobalFormatterType::DateFormatter:
102                icuType = IcuFormatterType::SIMPLE_DATE_FORMAT_DEFAULT;
103                break;
104            case GlobalFormatterType::NumberFormatter:
105                icuType = IcuFormatterType::NUMBER_FORMATTER;
106                break;
107        }
108        EcmaVM *ecmaVm = thread->GetEcmaVM();
109        std::string cacheEntry = locales->IsUndefined() ? "" :
110            EcmaStringAccessor(locales.GetTaggedValue()).ToStdString();
111        if (cache) {
112            void *cachedCollator = ecmaVm->GetIcuFormatterFromCache(icuType, cacheEntry);
113            if (cachedCollator != nullptr) {
114                return reinterpret_cast<T *>(cachedCollator);
115            }
116        }
117        std::unique_ptr<T> tObject = GetGlobalObject<T>(thread, locales, options, types);
118        if (cache) {
119            T *cacheObject = tObject.release();
120            switch (icuType) {
121                case IcuFormatterType::COLLATOR:
122                    ecmaVm->SetIcuFormatterToCache(icuType, cacheEntry, cacheObject, FreeCollatorFormat);
123                    break;
124                case IcuFormatterType::SIMPLE_DATE_FORMAT_DATE:
125                case IcuFormatterType::SIMPLE_DATE_FORMAT_TIME:
126                case IcuFormatterType::SIMPLE_DATE_FORMAT_DEFAULT:
127                    ecmaVm->SetIcuFormatterToCache(icuType, cacheEntry, cacheObject, FreeDateTimeFormat);
128                    break;
129                case IcuFormatterType::NUMBER_FORMATTER:
130                    ecmaVm->SetIcuFormatterToCache(icuType, cacheEntry, cacheObject, FreeNumberFormat);
131                    break;
132            }
133            return cacheObject;
134        }
135        globalObject = tObject.release();
136        return reinterpret_cast<T *>(globalObject);
137    }
138    static void FreeCollatorFormat([[maybe_unused]] void *env, void *pointer, void *data)
139    {
140        if (pointer == nullptr) {
141            return;
142        }
143        auto globalCollator = reinterpret_cast<GlobalCollator*>(pointer);
144        globalCollator->~Collator();
145        if (data != nullptr) {
146            reinterpret_cast<EcmaVM *>(data)->GetNativeAreaAllocator()->FreeBuffer(pointer);
147        }
148    }
149    static void FreeNumberFormat([[maybe_unused]] void *env, void *pointer, void *data)
150    {
151        if (pointer == nullptr) {
152            return;
153        }
154        auto globalNumberFormat = reinterpret_cast<GlobalNumberFormat*>(pointer);
155        globalNumberFormat->~NumberFormat();
156        if (data != nullptr) {
157            reinterpret_cast<EcmaVM *>(data)->GetNativeAreaAllocator()->FreeBuffer(pointer);
158        }
159    }
160    static void FreeDateTimeFormat([[maybe_unused]] void *env, void *pointer, void *data)
161    {
162        if (pointer == nullptr) {
163            return;
164        }
165        auto globalDateFormatter = reinterpret_cast<GlobalDateFormatter*>(pointer);
166        globalDateFormatter->~DateTimeFormat();
167        if (data != nullptr) {
168            reinterpret_cast<EcmaVM *>(data)->GetNativeAreaAllocator()->FreeBuffer(pointer);
169        }
170    }
171    std::vector<std::string> LocalesToVector(JSThread *thread, const JSHandle<JSTaggedValue> &locales);
172    std::map<std::string, std::string> OptionsToMap(JSThread *thread,
173        const JSHandle<JSTaggedValue> &options, GlobalFormatterType types);
174    uint64_t *ConvertDateToUnit(uint64_t timestamp);
175    static int64_t DoubleToInt64(double value);
176private:
177    void *globalObject = nullptr;
178    uint64_t *dateUnitArr = nullptr;
179    void InitCollatorData(const GlobalEnvConstants *globalConst);
180    void InitNumberData(const GlobalEnvConstants *globalConst);
181    void InitDateData(const GlobalEnvConstants *globalConst);
182    std::map<std::string, std::string> OptionsWithDataFormatter(std::map<std::string,
183        std::string> &options, GlobalFormatterType &types);
184    std::map<GlobalFormatterType, std::map<std::string, JSHandle<JSTaggedValue>>> optionMaps;
185    std::string EcmaConvertToStr(const JSHandle<EcmaString> &string);
186    std::vector<std::string> TaggedArrayToVector(JSThread *thread, JSHandle<TaggedArray> &taggedarray);
187};
188}  // panda::ecmascript::base
189#endif  // ECMASCRIPT_BASE_GLOBAL_INTL_HELPER_H