1/*
2 * Copyright (c) 2021-2024 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_JS_DATE_TIME_FORMAT_H
17#define ECMASCRIPT_JS_DATE_TIME_FORMAT_H
18
19#include "ecmascript/ecma_context.h"
20#include "ecmascript/js_locale.h"
21
22namespace panda::ecmascript {
23enum class CalendarOption : uint8_t { UNDEFINED = 0x01 };
24enum class DateTimeStyleOption : uint8_t { FULL = 0x01, LONG, MEDIUM, SHORT, UNDEFINED, EXCEPTION };
25enum class DefaultsOption : uint8_t { DATE = 0x01, TIME, ALL };
26enum class HourCycleOption : uint8_t { H11 = 0x01, H12, H23, H24, UNDEFINED, EXCEPTION };
27enum class RequiredOption : uint8_t { DATE = 0x01, TIME, ANY };
28enum class Value : uint8_t { SHARED, START_RANGE, END_RANGE };
29enum class IcuCacheType : uint8_t {NOT_CACHE, DEFAULT, DATE, TIME};
30
31constexpr int CAPACITY_3 = 3;
32constexpr int CAPACITY_4 = 4;
33constexpr int CAPACITY_5 = 5;
34constexpr int CAPACITY_8 = 8;
35constexpr int STRING_LENGTH_2 = 2;
36constexpr int STRING_LENGTH_3 = 3;
37constexpr int STRING_LENGTH_7 = 7;
38constexpr int STRING_LENGTH_8 = 8;
39constexpr int STRING_LENGTH_9 = 9;
40constexpr int STRING_LENGTH_10 = 10;
41
42class IcuPatternDesc;
43
44std::vector<IcuPatternDesc> BuildIcuPatternDescs();
45std::vector<IcuPatternDesc> InitializePattern(const IcuPatternDesc &hourData);
46icu::DateFormat::EStyle DateTimeStyleToEStyle(DateTimeStyleOption style);
47HourCycleOption HourCycleFromPattern(const icu::UnicodeString pattern);
48icu::UnicodeString ReplaceSkeleton(const icu::UnicodeString input, HourCycleOption hc);
49std::unique_ptr<icu::SimpleDateFormat> DateTimeStylePattern(DateTimeStyleOption dateStyle,
50                                                            DateTimeStyleOption timeStyle,
51                                                            icu::Locale &icuLocale,
52                                                            HourCycleOption hc,
53                                                            icu::DateTimePatternGenerator *generator);
54
55using IcuPatternDescVect = std::vector<IcuPatternDesc>;
56using IcuPatternEntry = std::pair<std::string, std::string>;
57
58class IcuPatternDesc {
59public:
60    IcuPatternDesc(std::string property, const std::vector<IcuPatternEntry> &pairs,
61                   std::vector<std::string> allowedValues) : property(std::move(property)), pairs(std::move(pairs)),
62                                                             allowedValues(std::move(allowedValues))
63    {
64        for (const auto &pair : pairs) {
65            map.emplace(pair.second, pair.first);
66        }
67    }
68
69    virtual ~IcuPatternDesc() = default;
70
71    std::string property;   // NOLINT(misc-non-private-member-variables-in-classes)
72    std::vector<IcuPatternEntry> pairs; // NOLINT(misc-non-private-member-variables-in-classes)
73    std::map<const std::string, const std::string> map; // NOLINT(misc-non-private-member-variables-in-classes)
74    std::vector<std::string> allowedValues; // NOLINT(misc-non-private-member-variables-in-classes)
75
76    DEFAULT_COPY_SEMANTIC(IcuPatternDesc);
77    // NOLINT(performance-noexcept-move-constructor, hicpp-noexcept-move)
78    DEFAULT_NOEXCEPT_MOVE_SEMANTIC(IcuPatternDesc);
79};
80
81class Pattern {
82public:
83    Pattern(const std::string &data1, const std::string &data2) : data(InitializePattern(
84        IcuPatternDesc("hour", {{data1, "2-digit"}, {data2, "numeric"}}, {"2-digit", "numeric"}))) {}
85    virtual ~Pattern() = default;
86    std::vector<IcuPatternDesc> Get() const
87    {
88        return data;
89    }
90
91private:
92    std::vector<IcuPatternDesc> data{};
93    NO_COPY_SEMANTIC(Pattern);
94    NO_MOVE_SEMANTIC(Pattern);
95};
96
97class JSDateTimeFormat : public JSObject {
98public:
99    CAST_CHECK(JSDateTimeFormat, IsJSDateTimeFormat);
100
101    static constexpr size_t LOCALE_OFFSET = JSObject::SIZE;
102    ACCESSORS(Locale, LOCALE_OFFSET, CALENDAR_OFFSET)
103    ACCESSORS(Calendar, CALENDAR_OFFSET, NUMBER_STRING_SYSTEM_OFFSET)
104    ACCESSORS(NumberingSystem, NUMBER_STRING_SYSTEM_OFFSET, TIME_ZONE_OFFSET)
105    ACCESSORS(TimeZone, TIME_ZONE_OFFSET, LOCALE_ICU_OFFSET)
106    ACCESSORS(LocaleIcu, LOCALE_ICU_OFFSET, SIMPLE_DATE_TIME_FORMAT_ICU_OFFSET)
107    ACCESSORS(SimpleDateTimeFormatIcu, SIMPLE_DATE_TIME_FORMAT_ICU_OFFSET, ISO8601_OFFSET)
108    ACCESSORS(Iso8601, ISO8601_OFFSET, BOUND_FORMAT_OFFSET)
109    ACCESSORS(BoundFormat, BOUND_FORMAT_OFFSET, BIT_FIELD_OFFSET)
110    ACCESSORS_BIT_FIELD(BitField, BIT_FIELD_OFFSET, LAST_OFFSET)
111    DEFINE_ALIGN_SIZE(LAST_OFFSET);
112
113    // define BitField
114    static constexpr size_t HONOR_CYCLE_BITS = 3;
115    static constexpr size_t DATE_STYLE_BITS = 3;
116    static constexpr size_t TIME_STYLE_BITS = 3;
117    FIRST_BIT_FIELD(BitField, HourCycle, HourCycleOption, HONOR_CYCLE_BITS)
118    NEXT_BIT_FIELD(BitField, DateStyle, DateTimeStyleOption, DATE_STYLE_BITS, HourCycle)
119    NEXT_BIT_FIELD(BitField, TimeStyle, DateTimeStyleOption, TIME_STYLE_BITS, DateStyle)
120
121    DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, LOCALE_OFFSET, BIT_FIELD_OFFSET)
122    DECL_DUMP()
123
124    icu::Locale *GetIcuLocale() const;
125    static void SetIcuLocale(JSThread *thread, JSHandle<JSDateTimeFormat> obj,
126        const icu::Locale &icuLocale, const NativePointerCallback &callback);
127    static void FreeIcuLocale(void *env, void *pointer, void *data);
128
129    icu::SimpleDateFormat *GetIcuSimpleDateFormat() const;
130    static void SetIcuSimpleDateFormat(JSThread *thread, JSHandle<JSDateTimeFormat> obj,
131        const icu::SimpleDateFormat &icuSimpleDateTimeFormat, const NativePointerCallback &callback);
132    static void FreeSimpleDateFormat(void *env, void *pointer, void *data);
133    static icu::SimpleDateFormat *GetCachedIcuSimpleDateFormat(JSThread *thread,
134                                                               const JSHandle<JSTaggedValue> &locales,
135                                                               IcuFormatterType type);
136
137    // 13.1.1 InitializeDateTimeFormat (dateTimeFormat, locales, options)
138    static JSHandle<JSDateTimeFormat> InitializeDateTimeFormat(JSThread *thread,
139                                                               const JSHandle<JSDateTimeFormat> &dateTimeFormat,
140                                                               const JSHandle<JSTaggedValue> &locales,
141                                                               const JSHandle<JSTaggedValue> &options,
142                                                               IcuCacheType type = IcuCacheType::NOT_CACHE);
143
144    // 13.1.2 ToDateTimeOptions (options, required, defaults)
145    static JSHandle<JSObject> ToDateTimeOptions(JSThread *thread, const JSHandle<JSTaggedValue> &options,
146                                                const RequiredOption &required, const DefaultsOption &defaults);
147
148    static void ToDateTimeSkeleton(JSThread *thread, const std::vector<std::string> &options,
149                                   std::string &skeleton, HourCycleOption hc,
150                                   const RequiredOption &required, const DefaultsOption &defaults);
151
152    // 13.1.7 FormatDateTime(dateTimeFormat, x)
153    static JSHandle<EcmaString> FormatDateTime(JSThread *thread, const JSHandle<JSDateTimeFormat> &dateTimeFormat,
154                                               double x);
155    static JSHandle<EcmaString> FormatDateTime(JSThread *thread, const icu::SimpleDateFormat *simpleDateFormat,
156                                               double x);
157
158    // 13.1.8 FormatDateTimeToParts (dateTimeFormat, x)
159    static JSHandle<JSArray> FormatDateTimeToParts(JSThread *thread, const JSHandle<JSDateTimeFormat> &dateTimeFormat,
160                                                   double x);
161
162    // 13.1.10 UnwrapDateTimeFormat(dtf)
163    static JSHandle<JSTaggedValue> UnwrapDateTimeFormat(JSThread *thread,
164                                                        const JSHandle<JSTaggedValue> &dateTimeFormat);
165
166    static JSHandle<TaggedArray> GainAvailableLocales(JSThread *thread);
167
168    static void ResolvedOptions(JSThread *thread, const JSHandle<JSDateTimeFormat> &dateTimeFormat,
169                                const JSHandle<JSObject> &options);
170
171    static JSHandle<EcmaString> NormDateTimeRange(JSThread *thread, const JSHandle<JSDateTimeFormat> &dtf, double x,
172                                                    double y);
173
174    static JSHandle<JSArray> NormDateTimeRangeToParts(JSThread *thread, const JSHandle<JSDateTimeFormat> &dtf,
175                                                        double x, double y);
176
177private:
178    static HourCycleOption OptionToHourCycle(const std::string &hc);
179    // 2: number of elements
180    static Value TrackValue(int32_t beginning, int32_t ending, std::array<int32_t, 2> begin,
181                            std::array<int32_t, 2> end); // 2: number of elements
182
183    static HourCycleOption OptionToHourCycle(UDateFormatHourCycle hc);
184
185    static std::string ToHourCycleString(HourCycleOption hc);
186
187    static std::unique_ptr<icu::TimeZone> ConstructTimeZone(const std::string &timezone);
188
189    static std::string ConstructFormattedTimeZoneID(const std::string &input);
190
191    static std::string ToTitleCaseTimezonePosition(const std::string &input);
192
193    static std::unique_ptr<icu::DateIntervalFormat> ConstructDateIntervalFormat(const JSHandle<JSDateTimeFormat> &dtf);
194
195    static std::string ConstructGMTTimeZoneID(const std::string &input);
196
197    static std::unique_ptr<icu::Calendar> BuildCalendar(const icu::Locale &locale, const icu::TimeZone &timeZone);
198
199    static std::map<std::string, std::string> GetSpecialTimeZoneMap();
200
201    static JSHandle<JSArray> ConstructFDateIntervalToJSArray(JSThread *thread,
202                                                             const icu::FormattedDateInterval &formatted);
203
204    static std::vector<IcuPatternDesc> GetIcuPatternDesc(const HourCycleOption &hourCycle);
205
206    static std::unique_ptr<icu::SimpleDateFormat> CreateICUSimpleDateFormat(const icu::Locale &icuLocale,
207                                                               const icu::UnicodeString &skeleton,
208                                                               icu::DateTimePatternGenerator *generator,
209                                                               HourCycleOption hc);
210
211    static JSHandle<JSTaggedValue> ConvertFieldIdToDateType(JSThread *thread, int32_t fieldId);
212
213    static icu::UnicodeString ChangeHourCyclePattern(const icu::UnicodeString &pattern, HourCycleOption hc);
214
215    static std::string ToTitleCaseFunction(const std::string &input);
216
217    static bool IsValidTimeZoneInput(const std::string &input);
218
219    static JSHandle<EcmaString> ToValueString(JSThread *thread, Value value);
220
221    static icu::FormattedDateInterval ConstructDTFRange(JSThread *thread, const JSHandle<JSDateTimeFormat> &dtf,
222                                                        double x, double y);
223};
224}  // namespace panda::ecmascript
225#endif  // ECMASCRIPT_JS_DATE_TIME_FORMAT_H
226