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#include <sstream>
16#include <iomanip>
17#include "calendar_log.h"
18#include "native_util.h"
19#include <ctime>
20
21namespace OHOS::CalendarApi::Native {
22const int MIN_DAY_OF_WEEK = 1;
23const int MAX_DAY_OF_WEEK = 7;
24const int MIN_MONTH_OF_YEAR = -12;
25const int MAX_MONTH_OF_YEAR = 12;
26const int MIN_DAY_OF_MONTH = -31;
27const int MAX_DAY_OF_MONTH = 31;
28const int MIN_DAY_OF_YEAR = -366;
29const int MAX_DAY_OF_YEAR = 366;
30const int MIN_WEEK_OF_YEAR = -53;
31const int MAX_WEEK_OF_YEAR = 53;
32const int MIN_WEEK_OF_MONTH = -5;
33const int MAX_WEEK_OF_MONTH = 5;
34void DumpCalendarAccount(const CalendarAccount &account)
35{
36    LOG_DEBUG("account.name:%{private}s", account.name.c_str());
37    LOG_DEBUG("account.type:%{private}s", account.type.c_str());
38    LOG_DEBUG("account.displayName:%{private}s", account.displayName.value_or("").c_str());
39}
40
41void DumpEvent(const Event &event)
42{
43    LOG_DEBUG("id       :%{private}d", event.id.value_or(-1));
44    LOG_DEBUG("type     :%{private}d", event.type);
45    LOG_DEBUG("title    :%{private}s", event.title.value_or("[null]").c_str());
46    if (event.location) {
47        auto location = event.location.value();
48        LOG_DEBUG("location.location  :%{private}s", location.location.value_or("[null]").c_str());
49        LOG_DEBUG("location.longitude :%{private}lf", location.longitude.value_or(-1));
50        LOG_DEBUG("location.latitude  :%{private}lf", location.latitude.value_or(-1));
51    } else {
52        LOG_DEBUG("location [null]");
53    }
54    if (event.service) {
55        auto service = event.service.value();
56        LOG_DEBUG("service.type  :%{private}s", service.type.c_str());
57        LOG_DEBUG("service.description :%{private}s", service.description.value_or("[null]").c_str());
58        LOG_DEBUG("service.uri  :%{private}s", service.uri.c_str());
59    } else {
60        LOG_DEBUG("service [null]");
61    }
62    if (event.recurrenceRule.has_value()) {
63        LOG_DEBUG("recurrenceRule.recurrenceFrequency: %{private}d", event.recurrenceRule.value().recurrenceFrequency);
64    }
65    LOG_DEBUG("startTime    :%{private}s", std::to_string(event.startTime).c_str());
66    LOG_DEBUG("endTime      :%{private}s", std::to_string(event.endTime).c_str());
67    LOG_DEBUG("isAllDay :%{private}d", event.isAllDay.value_or(0));
68
69    for (const auto &attendee : event.attendees) {
70        LOG_DEBUG("attendee.name   :%{private}s", attendee.name.c_str());
71        LOG_DEBUG("attendee.email  :%{private}s", attendee.email.c_str());
72    }
73
74    LOG_DEBUG("timeZone     :%{private}s", event.timeZone.value_or("[null]").c_str());
75    LOG_DEBUG("description  :%{private}s", event.description.value_or("[null]").c_str());
76}
77
78void BuildEventLocation(DataShare::DataShareValuesBucket &valuesBucket, const Event &event)
79{
80    if (!event.location) {
81        return;
82    }
83    auto location = event.location.value();
84    if (location.location) {
85        valuesBucket.Put("eventLocation", location.location.value());
86    }
87    if (location.longitude) {
88        // longitude is string in db
89        valuesBucket.Put("location_longitude", std::to_string(location.longitude.value()));
90    }
91    if (location.latitude) {
92        // latitude is string in db
93        valuesBucket.Put("location_latitude", std::to_string(location.latitude.value()));
94    }
95}
96
97void BuildEventService(DataShare::DataShareValuesBucket &valuesBucket, const Event &event)
98{
99    if (!event.service) {
100        return;
101    }
102    const auto service = event.service.value();
103    if (service.description) {
104        valuesBucket.Put("service_description", service.description.value());
105    }
106    valuesBucket.Put("service_type", service.type);
107    valuesBucket.Put("service_cp_bz_uri", service.uri);
108}
109
110std::string GetUTCTime(const int64_t &timeValue)
111{
112    const int monOffset = 1;
113    const int strLen = 2;
114    const int baseYear = 1900;
115    time_t expire = timeValue / 1000;
116    std::tm expireTime = {0};
117#ifdef WINDOWS_PLATFORM
118    if (gmtime_s(&expireTime, &expire)) {
119#else
120    if (gmtime_r(&expire, &expireTime) == nullptr) {
121#endif
122        return {};
123    }
124    std::stringstream out;
125    out << (expireTime.tm_year + baseYear);
126    out << std::setfill('0') << std::setw(strLen) << expireTime.tm_mon + monOffset;
127    out << std::setfill('0') << std::setw(strLen) << expireTime.tm_mday;
128    out << "T";
129    out << std::setfill('0') << std::setw(strLen) << expireTime.tm_hour;
130    out << std::setfill('0') << std::setw(strLen) << expireTime.tm_min;
131    out << std::setfill('0') << std::setw(strLen) << expireTime.tm_sec;
132    out << "Z";
133
134    return out.str();
135}
136
137std::string GetUTCTimes(const std::vector<int64_t> &timeValues)
138{
139    std::stringstream out;
140    if (timeValues.size() == 0) {
141        return out.str();
142    }
143
144    const auto timeLen = timeValues.size() - 1;
145    if (timeLen == 0) {
146        out << GetUTCTime(timeValues[0]);
147        return out.str();
148    }
149
150    for (unsigned int i = 0; i <= timeLen; i++) {
151        out << GetUTCTime(timeValues[i]);
152        if (i != timeLen) {
153            out << ",";
154        }
155    }
156
157    return out.str();
158}
159
160std::string GetRule(const Event &event)
161{
162    const time_t now = event.startTime / 1000;
163    const std::tm *time = std::localtime(&now);
164    std::string rrule;
165    RecurrenceType recurrenceFrequency = event.recurrenceRule.value().recurrenceFrequency;
166    if (recurrenceFrequency == DAILY) {
167        rrule = "FREQ=DAILY" + GetEventRRule(event) + ";WKST=SU";
168    } else if (recurrenceFrequency == WEEKLY) {
169        rrule = "FREQ=WEEKLY" + GetEventRRule(event) + ";WKST=SU;BYDAY=";
170        if (time != nullptr) {
171            rrule += GetWeeklyRule(event, *time);
172        }
173    } else if (recurrenceFrequency == MONTHLY) {
174        rrule = "FREQ=MONTHLY" + GetEventRRule(event) + ";WKST=SU";
175        if (time != nullptr) {
176            rrule += GetMonthlyRule(event, *time);
177        }
178    } else if (recurrenceFrequency == YEARLY) {
179        rrule = "FREQ=YEARLY" + GetEventRRule(event) + ";WKST=SU";
180        if (time != nullptr) {
181            rrule += GetYearlyRule(event, *time);
182        }
183    }
184
185    return rrule;
186}
187
188std::string GetEventRRule(const Event &event)
189{
190    auto recurrenceRule = event.recurrenceRule.value();
191    std::string rrule;
192    if (recurrenceRule.expire.has_value() && recurrenceRule.expire.value() > 0) {
193        rrule += ";UNTIL=" + GetUTCTime(event.recurrenceRule.value().expire.value());
194    }
195    if (recurrenceRule.count.has_value() && recurrenceRule.count.value() > 0) {
196        rrule += ";COUNT=" + std::to_string(recurrenceRule.count.value());
197    }
198    if (recurrenceRule.interval.has_value() && recurrenceRule.interval.value() > 0) {
199        rrule += ";INTERVAL=" + std::to_string(recurrenceRule.interval.value());
200    }
201    return rrule;
202}
203
204std::string GetWeeklyRule(const Event &event, const std::tm &time)
205{
206    std::string rrule;
207    bool isHasSetData = false;
208    auto rRuleValue = event.recurrenceRule.value();
209    const std::vector<string> weekList = {"SU", "MO", "TU", "WE", "TH", "FR", "SA"};
210    if (rRuleValue.daysOfWeek.has_value()) {
211        isHasSetData = true;
212        auto daysOfWeekList = rRuleValue.daysOfWeek.value();
213        rrule = GetDaysOfWeekRule(MIN_DAY_OF_WEEK, MAX_DAY_OF_WEEK, daysOfWeekList);
214    }
215    if (isHasSetData == false) {
216        if (time.tm_wday < MAX_DAY_OF_WEEK) {
217            rrule = weekList[time.tm_wday];
218        }
219    }
220    return rrule;
221}
222
223std::string GetMonthlyRule(const Event &event, const std::tm &time)
224{
225    bool isHasSetData = false;
226    std::string rrule;
227    auto rruleValue = event.recurrenceRule.value();
228    if (rruleValue.daysOfWeek.has_value() && rruleValue.weeksOfMonth.has_value()) {
229        isHasSetData = true;
230        rrule += ";BYDAY=";
231        rrule += GetDaysOfWeekMonthRule(rruleValue.daysOfWeek.value(), rruleValue.weeksOfMonth.value());
232    }
233
234    if (rruleValue.daysOfMonth.has_value()) {
235        isHasSetData = true;
236        rrule += ";BYMONTHDAY=";
237        auto daysOfMonthList = rruleValue.daysOfMonth.value();
238        rrule += GetRRuleSerial(MIN_DAY_OF_MONTH, MAX_DAY_OF_MONTH, daysOfMonthList);
239    }
240    if (isHasSetData == false) {
241        rrule += ";BYMONTHDAY=";
242        rrule += std::to_string(time.tm_mday);
243    }
244    return rrule;
245}
246
247std::string GetYearlyRule(const Event &event, const std::tm &time)
248{
249    const int monOffset = 1;
250    bool isHasSetData = false;
251    std::string rrule;
252    auto rruleValue = event.recurrenceRule.value();
253    if (rruleValue.daysOfYear.has_value()) {
254        isHasSetData = true;
255        std::string days = GetRRuleSerial(MIN_DAY_OF_YEAR, MAX_DAY_OF_YEAR, rruleValue.daysOfYear.value());
256        rrule = ";BYYEARDAY=" + days;
257    }
258    if (rruleValue.weeksOfYear.has_value() && rruleValue.daysOfWeek.has_value()) {
259        isHasSetData = true;
260        auto weekOfYearList = rruleValue.weeksOfYear.value();
261        std::string weeks = GetRRuleSerial(MIN_WEEK_OF_YEAR, MAX_WEEK_OF_YEAR, weekOfYearList);
262        auto daysOfWeekList = rruleValue.daysOfWeek.value();
263        std::string weekdays = GetDaysOfWeekRule(MIN_DAY_OF_WEEK, MAX_DAY_OF_WEEK, daysOfWeekList);
264        rrule = ";BYWEEKNO=" + weeks + ";BYDAY=" + weekdays;
265    }
266    if (rruleValue.monthsOfYear.has_value() && rruleValue.daysOfMonth.has_value()) {
267        isHasSetData = true;
268        auto daysOfMonthList = rruleValue.daysOfMonth.value();
269        auto monthsOfYearList = rruleValue.monthsOfYear.value();
270        std::string days = GetRRuleSerial(MIN_DAY_OF_MONTH, MAX_DAY_OF_MONTH, daysOfMonthList);
271        std::string months = GetRRuleSerial(MIN_MONTH_OF_YEAR, MAX_MONTH_OF_YEAR, monthsOfYearList);
272        rrule = ";BYMONTHDAY=" + days + ";BYMONTH=" + months;
273    }
274    if (rruleValue.monthsOfYear.has_value() && rruleValue.weeksOfMonth.has_value() &&
275        rruleValue.daysOfWeek.has_value()) {
276        isHasSetData = true;
277        auto monthsOfYearList = rruleValue.monthsOfYear.value();
278        auto weeksOfMonthList = rruleValue.weeksOfMonth.value();
279        auto daysOfWeekList = rruleValue.daysOfWeek.value();
280        std::string months = GetRRuleSerial(MIN_MONTH_OF_YEAR, MAX_MONTH_OF_YEAR, monthsOfYearList);
281        std::string daysOfWeekMonth = GetDaysOfWeekMonthRule(daysOfWeekList, weeksOfMonthList);
282        rrule = ";BYDAY=" + daysOfWeekMonth + ";BYMONTH=" + months;
283    }
284    if (isHasSetData == false) {
285        rrule += ";BYMONTHDAY=";
286        rrule += std::to_string(time.tm_mday);
287        rrule += ";BYMONTH=";
288        rrule += std::to_string(time.tm_mon + monOffset);
289    }
290    return rrule;
291}
292
293std::string GetDaysOfWeekRule(int minValue, int maxValue, const std::vector<int64_t> &daysOfWeekList)
294{
295    std::string rrule;
296    const std::vector<string> weekDayList = {"MO", "TU", "WE", "TH", "FR", "SA", "SU"};
297    for (const auto &dayOfWeek : daysOfWeekList) {
298        if (dayOfWeek <= maxValue && dayOfWeek >= minValue) {
299            if (&dayOfWeek == &daysOfWeekList.back()) {
300                rrule = rrule + weekDayList[dayOfWeek - 1];
301                break;
302            }
303            rrule = rrule + weekDayList[dayOfWeek - 1] + ",";
304        }
305    }
306    return rrule;
307}
308
309std::string GetDaysOfWeekMonthRule(
310    const std::vector<int64_t> &daysOfWeekList, const std::vector<int64_t> &weeksOfMonthList)
311{
312    std::string rrule;
313    const std::vector<string> weekDayList = {"MO", "TU", "WE", "TH", "FR", "SA", "SU"};
314    auto daysLen = daysOfWeekList.size();
315    for (size_t i = 0; i < daysLen; i++) {
316        if (daysOfWeekList[i] >= MIN_DAY_OF_WEEK && daysOfWeekList[i] <= MAX_DAY_OF_WEEK &&
317            weeksOfMonthList[i] >= MIN_WEEK_OF_MONTH && weeksOfMonthList[i] <= MAX_WEEK_OF_MONTH) {
318            if (i == daysLen - 1) {
319                rrule = rrule + std::to_string(weeksOfMonthList[i]) + weekDayList[daysOfWeekList[i] - 1];
320                break;
321            } else {
322                rrule = rrule + std::to_string(weeksOfMonthList[i]) + weekDayList[daysOfWeekList[i] - 1] + ",";
323            }
324        }
325    }
326    return rrule;
327}
328
329std::string GetRRuleSerial(int minValue, int maxValue, const std::vector<int64_t> &serialList)
330{
331    std::string rrule;
332    for (const auto &serial : serialList) {
333        if (serial >= minValue && serial <= maxValue) {
334            if (&serial == &serialList.back()) {
335                rrule = rrule + std::to_string(serial);
336                break;
337            }
338            rrule = rrule + std::to_string(serial) + ",";
339        }
340    }
341    return rrule;
342}
343
344void BuildEventRecurrenceRule(DataShare::DataShareValuesBucket &valuesBucket, const Event &event)
345{
346    if (!event.recurrenceRule.has_value()) {
347        return;
348    }
349
350    std::string rrule = GetRule(event);
351    if (!rrule.empty()) {
352        valuesBucket.Put("rrule", rrule);
353    }
354
355    if (event.recurrenceRule.value().excludedDates.has_value()) {
356        const auto excludedDateStr = GetUTCTimes(event.recurrenceRule.value().excludedDates.value());
357        valuesBucket.Put("exdate", excludedDateStr);
358    }
359}
360
361DataShare::DataShareValuesBucket BuildValueEvent(const Event &event, int calendarId, int channelId)
362{
363    DataShare::DataShareValuesBucket valuesBucket;
364    valuesBucket.Put("calendar_id", calendarId);
365
366    LOG_DEBUG("title %{private}s", event.title.value_or("").c_str());
367    valuesBucket.Put("title", event.title.value_or(""));
368    valuesBucket.Put("important_event_type", event.type);
369    valuesBucket.Put("dtstart", event.startTime);
370    valuesBucket.Put("dtend", event.endTime);
371    valuesBucket.Put("channel_id", channelId);
372
373    BuildEventLocation(valuesBucket, event);
374    BuildEventService(valuesBucket, event);
375    BuildEventRecurrenceRule(valuesBucket, event);
376
377    LOG_DEBUG("description %{private}s", event.description.value_or("").c_str());
378
379    if (event.description.has_value()) {
380        valuesBucket.Put("description", event.description.value());
381    }
382    if (event.timeZone.has_value()) {
383        valuesBucket.Put("eventTimezone", event.timeZone.value());
384    }
385    if (event.isAllDay.has_value()) {
386        valuesBucket.Put("allDay", event.isAllDay.value());
387    }
388    if (event.identifier.has_value()) {
389        valuesBucket.Put("identifier", event.identifier.value());
390    }
391    if (event.isLunar.has_value()) {
392        valuesBucket.Put("event_calendar_type", event.isLunar.value());
393    }
394    return valuesBucket;
395}
396
397DataShare::DataShareValuesBucket BuildAttendeeValue(const Attendee &attendee, int eventId)
398{
399    DataShare::DataShareValuesBucket valuesBucket;
400    valuesBucket.Put("event_id", eventId);
401    valuesBucket.Put("attendeeName", attendee.name);
402    LOG_DEBUG("attendeeName %{private}s", attendee.name.c_str());
403    valuesBucket.Put("attendeeEmail", attendee.email);
404    LOG_DEBUG("attendeeEmail %{private}s", attendee.email.c_str());
405    if (attendee.role.has_value()) {
406        valuesBucket.Put("attendeeRelationship", attendee.role.value());
407    }
408
409    return valuesBucket;
410}
411
412int GetValue(DataShareResultSetPtr &resultSet, string_view fieldName, int& out)
413{
414    int index = 0;
415    auto ret = resultSet->GetColumnIndex(string(fieldName), index);
416    if (ret != DataShare::E_OK) {
417        return ret;
418    }
419    return resultSet->GetInt(index, out);
420}
421
422int GetIndexValue(const DataShareResultSetPtr &resultSet, int index, std::string& out)
423{
424    return resultSet->GetString(index, out);
425}
426
427int GetIndexValue(const DataShareResultSetPtr &resultSet, int index, int& out)
428{
429    return resultSet->GetInt(index, out);
430}
431
432int GetIndexValue(const DataShareResultSetPtr &resultSet, int index, int64_t& out)
433{
434    return resultSet->GetLong(index, out);
435}
436
437int GetValue(DataShareResultSetPtr &resultSet, string_view fieldName, std::string& out)
438{
439    int index = 0;
440    auto fieldNameStr = string(fieldName);
441    auto ret = resultSet->GetColumnIndex(fieldNameStr, index);
442    if (ret != DataShare::E_OK) {
443        LOG_WARN("GetValue [%{private}s] failed [%{private}d]", fieldNameStr.c_str(), ret);
444        return ret;
445    }
446    return resultSet->GetString(index, out);
447}
448
449std::vector<std::shared_ptr<Calendar>> ResultSetToCalendars(DataShareResultSetPtr &resultSet)
450{
451    std::vector<std::shared_ptr<Calendar>> result;
452    int rowCount = 0;
453    resultSet->GetRowCount(rowCount);
454    LOG_INFO("GetRowCount is %{public}d", rowCount);
455    if (rowCount == 0) {
456        return result;
457    }
458    auto err = resultSet->GoToFirstRow();
459    if (err != DataShare::E_OK) {
460        LOG_INFO("Failed GoToFirstRow %{public}d", err);
461        return result;
462    }
463    do {
464        int idValue = -1;
465        if (GetValue(resultSet, "_id", idValue) != DataShare::E_OK) {
466            break;
467        }
468        LOG_DEBUG("id: %{private}d", idValue);
469        std::string nameValue;
470        if (GetValue(resultSet, "account_name", nameValue) != DataShare::E_OK) {
471            break;
472        }
473        LOG_DEBUG("account_name: %{private}s", nameValue.c_str());
474        std::string typeValue;
475        if (GetValue(resultSet, "account_type", typeValue) != DataShare::E_OK) {
476            break;
477        }
478        LOG_DEBUG("account_type: %{private}s", typeValue.c_str());
479
480        std::string displayNameValue;
481        GetValue(resultSet, "calendar_displayName", displayNameValue);
482        LOG_DEBUG("calendar_displayName: %{private}s", displayNameValue.c_str());
483
484        int canReminder = -1;
485        GetValue(resultSet, "canReminder", canReminder);
486        LOG_DEBUG("canReminder: %{private}d", canReminder);
487
488        int colorValue = 0;
489        GetValue(resultSet, "calendar_color", colorValue);
490        CalendarAccount curAccount {nameValue, typeValue, displayNameValue};
491        result.emplace_back(std::make_shared<Calendar>(curAccount, idValue));
492    } while (resultSet->GoToNextRow() == DataShare::E_OK);
493    return result;
494}
495
496std::optional<Location> ResultSetToLocation(DataShareResultSetPtr &resultSet)
497{
498    Location out;
499    string value;
500    auto ret = GetValue(resultSet, "eventLocation", value);
501    out.location = std::make_optional<string>(value);
502    ret = GetValue(resultSet, "location_longitude", value);
503    double longitudeValue = -1;
504    std::stringstream str2digit;
505    str2digit << value;
506    str2digit >> longitudeValue;
507    if (longitudeValue != -1) {
508        out.longitude = std::make_optional<double>(longitudeValue);
509    }
510    ret = GetValue(resultSet, "location_latitude", value);
511    double latitudeValue = -1;
512    str2digit.clear();
513    str2digit << value;
514    str2digit >> latitudeValue;
515    if (latitudeValue != -1) {
516        out.latitude = std::make_optional<double>(latitudeValue);
517    }
518
519    if (ret != DataShare::E_OK) {
520        return std::nullopt;
521    }
522    return std::make_optional<Location>(out);
523}
524
525std::optional<EventService> ResultSetToEventService(DataShareResultSetPtr &resultSet)
526{
527    EventService out;
528    string value;
529    auto ret = GetValue(resultSet, "service_type", value);
530    if (ret != DataShare::E_OK) {
531        return std::nullopt;
532    }
533    const std::set<std::string> serviceType = {"Meeting", "Watching", "Repayment", "Live", "Shopping",
534                                               "Trip", "Class", "SportsEvents", "SportsExercise"};
535    if (serviceType.count(value)) {
536        out.type = value;
537    } else {
538        return std::nullopt;
539    }
540    ret = GetValue(resultSet, "service_cp_bz_uri", value);
541    if (ret != DataShare::E_OK) {
542        return std::nullopt;
543    }
544    out.uri = value;
545    ret = GetValue(resultSet, "service_description", value);
546    if (ret == DataShare::E_OK) {
547        out.description = std::make_optional<string>(value);
548    }
549    return std::make_optional<EventService>(out);
550}
551
552int StringToInt(const std::string &str)
553{
554    try {
555        return std::stoi(str);
556    } catch (std::exception &ex) {
557        LOG_ERROR("StringToInt conversion fail, str: %{public}s", str.c_str());
558        return 0;
559    }
560}
561
562std::time_t TimeToUTC(const std::string &strTime)
563{
564    const int baseYear = 1900;
565    const int offset = 2;
566    const int yearOffset = 4;
567    const int monBase = 4;
568    const int dayBase = 6;
569    const int hourBase = 9;
570    const int minBase = 11;
571    const int secBase = 13;
572    const int monCount = 12;
573    const int monRectify = 11;
574    const int micSecond = 1000;
575
576    std::tm expireTime = { 0 };
577    expireTime.tm_year = StringToInt(strTime.substr(0, yearOffset)) - baseYear;
578    expireTime.tm_mon = (StringToInt(strTime.substr(monBase, offset)) + monRectify) % monCount;
579    expireTime.tm_mday = StringToInt(strTime.substr(dayBase, offset));
580    if (strTime.find("T") != std::string::npos) {
581        expireTime.tm_hour = StringToInt(strTime.substr(hourBase, offset));
582        expireTime.tm_min = StringToInt(strTime.substr(minBase, offset));
583        expireTime.tm_sec = StringToInt(strTime.substr(secBase,  offset));
584    } else {
585        expireTime.tm_hour = 0;
586        expireTime.tm_min = 0;
587        expireTime.tm_sec = 0;
588    }
589
590    std::time_t utcTime = mktime(&expireTime) * micSecond; //精确到微秒
591
592    return utcTime;
593}
594
595std::vector<std::string> SplitString(const std::string &str, const std::string &flag)
596{
597    std::vector<std::string> result;
598    std::string::size_type pos1 = 0;
599    std::string::size_type pos2 = str.find(flag);
600    while (std::string::npos != pos2) {
601        result.push_back(str.substr(pos1, pos2 - pos1));
602        pos1 = pos2 + flag.size();
603        pos2 = str.find(flag, pos1);
604    }
605    if (pos1 != str.length()) {
606        result.push_back(str.substr(pos1));
607    }
608
609    return result;
610}
611
612std::optional<vector<int64_t>> ResultSetToExcludedDates(DataShareResultSetPtr &resultSet)
613{
614    std::string value;
615    auto ret = GetValue(resultSet, "exdate", value);
616    if (ret != DataShare::E_OK) {
617        return std::nullopt;
618    }
619    std::vector<string> strListExDate = SplitString(value, ",");
620
621    std::vector<int64_t> excludedDates;
622    for (const auto &str : strListExDate) {
623        auto exDate = TimeToUTC(str);
624        excludedDates.emplace_back(exDate);
625    }
626
627    return std::make_optional<vector<int64_t>>(excludedDates);
628}
629
630void ConvertRecurrenceFrequency(const std::string &frequency, RecurrenceRule &rule)
631{
632    if (frequency == "YEARLY") {
633        rule.recurrenceFrequency = YEARLY;
634        return;
635    }
636    if (frequency == "MONTHLY") {
637        rule.recurrenceFrequency = MONTHLY;
638        return;
639    }
640    if (frequency == "WEEKLY") {
641        rule.recurrenceFrequency = WEEKLY;
642        return;
643    }
644    if (frequency == "DAILY") {
645        rule.recurrenceFrequency = DAILY;
646    }
647}
648
649std::optional<RecurrenceRule> ResultSetToRecurrenceRule(DataShareResultSetPtr &resultSet)
650{
651    const int strListSize = 2;
652    RecurrenceRule out;
653    out.recurrenceFrequency = NORULE;
654    std::string value;
655    auto ret = GetValue(resultSet, "rrule", value);
656    if (ret != DataShare::E_OK) {
657        return std::nullopt;
658    }
659    std::map<std::string, std::string> ruleMap;
660    std::vector<std::string> strListRule = SplitString(value, ";");
661    for (const auto &str : strListRule) {
662        std::vector<std::string> keyAndValue = SplitString(str, "=");
663        if (keyAndValue.size() == strListSize) {
664            ruleMap.insert(std::pair<std::string, std::string>(keyAndValue[0], keyAndValue[1]));
665        }
666    }
667    SetRRuleValue(ruleMap, out);
668    out.excludedDates = ResultSetToExcludedDates(resultSet);
669
670    return std::make_optional<RecurrenceRule>(out);
671}
672
673void SetVecNum(std::optional<std::vector<int64_t>> &ruleVec, const std::string &ruleStr)
674{
675    std::vector<std::string> weekNumList = SplitString(ruleStr, ",");
676    for (const auto &weekNum : weekNumList) {
677        ruleVec->push_back(StringToInt(weekNum));
678    }
679}
680
681void SetRRuleValue(const std::map<std::string, std::string> &ruleMap, RecurrenceRule &out)
682{
683    std::map<std::string, std::string>::const_iterator iter;
684    for (iter = ruleMap.begin(); iter != ruleMap.end(); iter++) {
685        if (iter->first == "FREQ") {
686            ConvertRecurrenceFrequency(iter->second, out);
687            continue;
688        }
689        if (iter->first == "COUNT") {
690            out.count = std::make_optional<int64_t>(StringToInt(iter->second));
691            continue;
692        }
693        if (iter->first == "INTERVAL") {
694            out.interval = std::make_optional<int64_t>(StringToInt(iter->second));
695            continue;
696        }
697        if (iter->first == "UNTIL") {
698            out.expire = std::make_optional<int64_t>(TimeToUTC(iter->second));
699        }
700        if (iter->first == "BYDAY") {
701            std::vector<std::string> weekDayList = SplitString(iter->second, ",");
702            SetByDayOfRRule(weekDayList, out);
703        }
704        if (iter->first == "BYWEEKNO") {
705            out.weeksOfYear = std::make_optional<std::vector<int64_t>>();
706            SetVecNum(out.weeksOfYear, iter->second);
707        }
708        if (iter->first == "BYMONTHDAY") {
709            out.daysOfMonth = std::make_optional<std::vector<int64_t>>();
710            SetVecNum(out.daysOfMonth, iter->second);
711        }
712        if (iter->first == "BYYEARDAY") {
713            out.daysOfYear = std::make_optional<std::vector<int64_t>>();
714            SetVecNum(out.daysOfYear, iter->second);
715        }
716        if (iter->first == "BYMONTH") {
717            out.monthsOfYear = std::make_optional<std::vector<int64_t>>();
718            SetVecNum(out.monthsOfYear, iter->second);
719        }
720    }
721}
722
723void SetByDayOfRRule(const std::vector<std::string> &weekDayList, RecurrenceRule &out)
724{
725    const int weekStrLen = 2;
726    const std::vector<string> dayOfWeekList = {"MO", "TU", "WE", "TH", "FR", "SA", "SU"};
727    out.daysOfWeek = std::make_optional<vector<int64_t>>();
728    out.weeksOfMonth = std::make_optional<vector<int64_t>>();
729    for (const auto &weekday : weekDayList) {
730        if (weekday.length() > weekStrLen) {
731            std::string weekDayStr = weekday.substr(weekday.length() - weekStrLen, weekStrLen);
732            std::string WeekNumStr = weekday.substr(0, weekday.length() - weekStrLen);
733            auto it = std::find(dayOfWeekList.begin(), dayOfWeekList.end(), weekDayStr);
734            if (it != dayOfWeekList.end()) {
735                int dayNum = it - dayOfWeekList.begin();
736                out.daysOfWeek->push_back(dayNum + 1);
737                out.weeksOfMonth->push_back(StringToInt(WeekNumStr));
738            }
739        } else if (weekday.length() == weekStrLen) {
740            auto it = std::find(dayOfWeekList.begin(), dayOfWeekList.end(), weekday);
741            if (it != dayOfWeekList.end()) {
742                int dayNum = it - dayOfWeekList.begin();
743                out.daysOfWeek->push_back(dayNum + 1);
744            }
745        }
746    }
747}
748
749void ResultSetToEvent(Event &event, DataShareResultSetPtr &resultSet, const std::set<std::string>& columns)
750{
751    GetValueOptional(resultSet, "_id", event.id);
752    if (columns.count("type")) {
753        int type = 0;
754        GetValue(resultSet, "important_event_type", type);
755        event.type = static_cast<EventType>(type);
756    }
757    if (columns.count("title")) {
758        GetValueOptional(resultSet, "title", event.title);
759    }
760    if (columns.count("startTime")) {
761        LOG_DEBUG("TLQ get startTime");
762        GetValue(resultSet, "dtstart", event.startTime);
763    }
764    if (columns.count("endTime")) {
765        LOG_DEBUG("TLQ get endTime");
766        GetValue(resultSet, "dtend", event.endTime);
767    }
768    if (columns.count("isAllDay")) {
769        int isAllDay = 0;
770        GetValue(resultSet, "allDay", isAllDay);
771        event.isAllDay = static_cast<bool>(isAllDay);
772    }
773    if (columns.count("description")) {
774        GetValueOptional(resultSet, "description", event.description);
775    }
776    if (columns.count("timeZone")) {
777        GetValueOptional(resultSet, "eventTimezone", event.timeZone);
778    }
779    if (columns.count("location")) {
780        event.location = ResultSetToLocation(resultSet);
781    }
782    if (columns.count("service")) {
783        event.service = ResultSetToEventService(resultSet);
784    }
785    if (columns.count("recurrenceRule")) {
786        event.recurrenceRule = ResultSetToRecurrenceRule(resultSet);
787    }
788
789    if (columns.count("identifier")) {
790        GetValueOptional(resultSet, "identifier", event.identifier);
791    }
792
793    if (columns.count("isLunar")) {
794        int isLunar = 0;
795        GetValue(resultSet, "event_calendar_type", isLunar);
796        event.isLunar = static_cast<bool>(isLunar);
797    }
798}
799
800int ResultSetToEvents(std::vector<Event> &events, DataShareResultSetPtr &resultSet,
801    const std::set<std::string>& columns)
802{
803    int rowCount = 0;
804    resultSet->GetRowCount(rowCount);
805    LOG_INFO("GetRowCount is %{public}d", rowCount);
806    if (rowCount <= 0) {
807        return -1;
808    }
809    auto err = resultSet->GoToFirstRow();
810    if (err != DataShare::E_OK) {
811        LOG_ERROR("Failed GoToFirstRow %{public}d", err);
812        return -1;
813    }
814    do {
815        Event event;
816        ResultSetToEvent(event, resultSet, columns);
817        events.emplace_back(event);
818    } while (resultSet->GoToNextRow() == DataShare::E_OK);
819    return 0;
820}
821
822int ResultSetToAttendees(std::vector<Attendee> &attendees, DataShareResultSetPtr &resultSet)
823{
824    int rowCount = 0;
825    resultSet->GetRowCount(rowCount);
826    LOG_INFO("GetRowCount is %{public}d", rowCount);
827    if (rowCount <= 0) {
828        return -1;
829    }
830    auto err = resultSet->GoToFirstRow();
831    if (err != DataShare::E_OK) {
832        LOG_ERROR("Failed GoToFirstRow %{public}d", err);
833        return -1;
834    }
835    int roleValue = 0;
836    do {
837        Attendee attendee;
838        GetValue(resultSet, "attendeeName", attendee.name);
839        GetValue(resultSet, "attendeeEmail", attendee.email);
840        GetValue(resultSet, "attendeeRelationship",  roleValue);
841        if (roleValue == PARTICIPANT) {
842            attendee.role = std::make_optional<RoleType>(PARTICIPANT);
843        } else if (roleValue == ORGANIZER) {
844            attendee.role = std::make_optional<RoleType>(ORGANIZER);
845        }
846
847        attendees.emplace_back(attendee);
848    } while (resultSet->GoToNextRow() == DataShare::E_OK);
849    return 0;
850}
851
852int ResultSetToReminders(std::vector<int> &reminders, DataShareResultSetPtr &resultSet)
853{
854    int rowCount = 0;
855    resultSet->GetRowCount(rowCount);
856    LOG_INFO("GetRowCount is %{public}d", rowCount);
857    if (rowCount <= 0) {
858        return -1;
859    }
860    auto err = resultSet->GoToFirstRow();
861    if (err != DataShare::E_OK) {
862        LOG_ERROR("Failed GoToFirstRow %{public}d", err);
863        return -1;
864    }
865    do {
866        int minutes;
867        GetValue(resultSet, "minutes", minutes);
868        reminders.emplace_back(minutes);
869    } while (resultSet->GoToNextRow() == DataShare::E_OK);
870    return 0;
871}
872
873bool IsValidHexString(const std::string& colorStr)
874{
875    if (colorStr.empty()) {
876        return false;
877    }
878    for (char ch : colorStr) {
879        if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) {
880            continue;
881        }
882        return false;
883    }
884    return true;
885}
886
887bool ColorParse(const std::string& colorStr, variant<string, int64_t>& colorValue)
888{
889    if (colorStr.empty()) {
890        LOG_ERROR("color string is empty");
891        return false;
892    }
893
894    if (colorStr[0] != '#') { // start with '#'
895        LOG_ERROR("color string not start with #");
896        return false;
897    }
898
899    const int rgbLen = 7;
900    const int argbLen = 9;
901    if (colorStr.size() != rgbLen && colorStr.size() != argbLen) {
902        LOG_ERROR("color string length is not 7 or 9");
903        return false;
904    }
905
906    std::string colorStrSub = colorStr.substr(1);
907    if (!IsValidHexString(colorStrSub)) {
908        LOG_DEBUG("color string is not valid hex string");
909        return false;
910    }
911
912    LOG_DEBUG("color string size is 7 or 9");
913    colorValue.emplace<1>(std::stoll(colorStrSub, NULL, 16)); // 16 is convert hex string to number
914    if (std::get_if<1>(&colorValue)) {
915        LOG_DEBUG("colorStrSub -> colorValue colorValue:%{public}s", std::to_string(std::get<1>(colorValue)).c_str());
916        return true;
917    }
918    LOG_DEBUG("color is null");
919    return false;
920}
921
922void SetFieldInfo(const std::vector<string>& eventKey, std::vector<string>& queryField,
923    std::set<string>& resultSetField, const std::map<string, string> eventField)
924{
925    for (const auto& field : eventKey) {
926        if (field == "location") {
927            queryField.emplace_back("eventLocation");
928            queryField.emplace_back("location_longitude");
929            queryField.emplace_back("location_latitude");
930            resultSetField.insert(field);
931            continue;
932        }
933        if (field == "service") {
934            queryField.emplace_back("service_type");
935            queryField.emplace_back("service_cp_bz_uri");
936            queryField.emplace_back("service_description");
937            resultSetField.insert(field);
938            continue;
939        }
940        if (field == "attendee") {
941            resultSetField.insert(field);
942            continue;
943        }
944        if (field == "reminderTime") {
945            resultSetField.insert(field);
946            continue;
947        }
948        if (field == "identifier") {
949            queryField.emplace_back("identifier");
950            resultSetField.insert(field);
951            continue;
952        }
953        if (field == "recurrenceRule") {
954            queryField.emplace_back("rrule");
955            queryField.emplace_back("exdate");
956            resultSetField.insert(field);
957            continue;
958        }
959        if (field == "isLunar") {
960            queryField.emplace_back("event_calendar_type");
961            resultSetField.insert(field);
962            continue;
963        }
964        if (field == "id") {
965            continue;
966        }
967        queryField.emplace_back(eventField.at(field));
968        resultSetField.insert(field);
969    }
970}
971
972void SetField(const std::vector<string>& eventKey, std::vector<string>& queryField, std::set<string>& resultSetField)
973{
974    const std::map<string, string> eventField = { { "id", "_id" },
975                                                  { "type", "important_event_type" },
976                                                  { "title", "title" },
977                                                  { "startTime", "dtstart" },
978                                                  { "endTime", "dtend" },
979                                                  { "isAllDay", "allDay" },
980                                                  { "timeZone", "eventTimezone" },
981                                                  { "description", "description" }};
982    SetFieldInfo(eventKey, queryField, resultSetField, eventField);
983}
984}