19596a2c1Sopenharmony_ci/*
29596a2c1Sopenharmony_ci * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
39596a2c1Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
49596a2c1Sopenharmony_ci * you may not use this file except in compliance with the License.
59596a2c1Sopenharmony_ci * You may obtain a copy of the License at
69596a2c1Sopenharmony_ci *
79596a2c1Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
89596a2c1Sopenharmony_ci *
99596a2c1Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
109596a2c1Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
119596a2c1Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
129596a2c1Sopenharmony_ci * See the License for the specific language governing permissions and
139596a2c1Sopenharmony_ci * limitations under the License.
149596a2c1Sopenharmony_ci */
159596a2c1Sopenharmony_ci#include "holiday_manager.h"
169596a2c1Sopenharmony_ci#include "i18n_hilog.h"
179596a2c1Sopenharmony_ci#include <algorithm>
189596a2c1Sopenharmony_ci#include <climits>
199596a2c1Sopenharmony_ci#include <ctime>
209596a2c1Sopenharmony_ci#include <filesystem>
219596a2c1Sopenharmony_ci#include <format>
229596a2c1Sopenharmony_ci#include <fstream>
239596a2c1Sopenharmony_ci#include <iostream>
249596a2c1Sopenharmony_ci#include <regex>
259596a2c1Sopenharmony_ci#include "map"
269596a2c1Sopenharmony_ci#include "utils.h"
279596a2c1Sopenharmony_ci
289596a2c1Sopenharmony_cinamespace OHOS {
299596a2c1Sopenharmony_cinamespace Global {
309596a2c1Sopenharmony_cinamespace I18n {
319596a2c1Sopenharmony_ciconst char* HolidayManager::ITEM_BEGIN_TAG = "BEGIN:VEVENT";
329596a2c1Sopenharmony_ciconst char* HolidayManager::ITEM_END_TAG = "END:VEVENT";
339596a2c1Sopenharmony_ciconst char* HolidayManager::ITEM_DTSTART_TAG = "DTSTART";
349596a2c1Sopenharmony_ciconst char* HolidayManager::ITEM_DTEND_TAG = "DTEND";
359596a2c1Sopenharmony_ciconst char* HolidayManager::ITEM_SUMMARY_TAG = "SUMMARY";
369596a2c1Sopenharmony_ciconst char* HolidayManager::ITEM_RESOURCES_TAG = "RESOURCES";
379596a2c1Sopenharmony_ci
389596a2c1Sopenharmony_ciHolidayManager::HolidayManager(const char* path)
399596a2c1Sopenharmony_ci{
409596a2c1Sopenharmony_ci    if (path == nullptr) {
419596a2c1Sopenharmony_ci        HILOG_ERROR_I18N("Failed: parameter path is NULL.");
429596a2c1Sopenharmony_ci        return;
439596a2c1Sopenharmony_ci    }
449596a2c1Sopenharmony_ci    std::string msg = ValidateHolidayFilePath(path);
459596a2c1Sopenharmony_ci    if (msg.length() != 0) {
469596a2c1Sopenharmony_ci        HILOG_ERROR_I18N("Failed: %{public}s .", msg.c_str());
479596a2c1Sopenharmony_ci        return;
489596a2c1Sopenharmony_ci    }
499596a2c1Sopenharmony_ci    std::vector<HolidayInfoItem> items = ReadHolidayFile(path);
509596a2c1Sopenharmony_ci    for (size_t i = 0; i < items.size(); i++) {
519596a2c1Sopenharmony_ci        struct tm tmObj = {.tm_mday = items[i].day, .tm_mon = items[i].month, .tm_year = items[i].year};
529596a2c1Sopenharmony_ci        char strDate[10];
539596a2c1Sopenharmony_ci        size_t resCode = strftime(strDate, sizeof(strDate), "%Y%m%d", &tmObj);
549596a2c1Sopenharmony_ci        if (resCode == 0) {
559596a2c1Sopenharmony_ci            HILOG_ERROR_I18N("Failed: strftime error:%{public}zu.", resCode);
569596a2c1Sopenharmony_ci            return;
579596a2c1Sopenharmony_ci        }
589596a2c1Sopenharmony_ci        std::string startDate(strDate);
599596a2c1Sopenharmony_ci        items[i].year += YEAR_START;
609596a2c1Sopenharmony_ci        items[i].month += MONTH_GREATER_ONE;
619596a2c1Sopenharmony_ci        if (holidayItemMap.find(startDate) != holidayItemMap.end()) {
629596a2c1Sopenharmony_ci            std::vector<HolidayInfoItem> *vetor = &(holidayItemMap.find(startDate)->second);
639596a2c1Sopenharmony_ci            vetor->push_back(items[i]);
649596a2c1Sopenharmony_ci        } else {
659596a2c1Sopenharmony_ci            std::vector<HolidayInfoItem> vetor;
669596a2c1Sopenharmony_ci            vetor.push_back(items[i]);
679596a2c1Sopenharmony_ci            holidayItemMap.insert(std::pair<std::string, std::vector<HolidayInfoItem>>(startDate, vetor));
689596a2c1Sopenharmony_ci        }
699596a2c1Sopenharmony_ci    }
709596a2c1Sopenharmony_ci}
719596a2c1Sopenharmony_ci
729596a2c1Sopenharmony_ciHolidayManager::~HolidayManager()
739596a2c1Sopenharmony_ci{
749596a2c1Sopenharmony_ci}
759596a2c1Sopenharmony_ci
769596a2c1Sopenharmony_civoid HolidayManager::SetHolidayData(std::map<std::string, std::vector<HolidayInfoItem>> holidayDataMap)
779596a2c1Sopenharmony_ci{
789596a2c1Sopenharmony_ci    holidayItemMap = holidayDataMap;
799596a2c1Sopenharmony_ci}
809596a2c1Sopenharmony_ci
819596a2c1Sopenharmony_cibool HolidayManager::IsHoliday()
829596a2c1Sopenharmony_ci{
839596a2c1Sopenharmony_ci    time_t timeStamp = time(NULL);
849596a2c1Sopenharmony_ci    struct tm* timObj = localtime(&timeStamp);
859596a2c1Sopenharmony_ci    if (timObj == nullptr) {
869596a2c1Sopenharmony_ci        return false;
879596a2c1Sopenharmony_ci    }
889596a2c1Sopenharmony_ci    int32_t year = timObj->tm_year + YEAR_START;
899596a2c1Sopenharmony_ci    int32_t month = timObj->tm_mon + MONTH_GREATER_ONE;
909596a2c1Sopenharmony_ci    return IsHoliday(year, month, timObj->tm_mday);
919596a2c1Sopenharmony_ci}
929596a2c1Sopenharmony_ci
939596a2c1Sopenharmony_cibool HolidayManager::IsHoliday(int32_t year, int32_t month, int32_t day)
949596a2c1Sopenharmony_ci{
959596a2c1Sopenharmony_ci    std::string startDate = Format(year, month, day);
969596a2c1Sopenharmony_ci    if (holidayItemMap.find(startDate) != holidayItemMap.end()) {
979596a2c1Sopenharmony_ci        std::vector<HolidayInfoItem> list = holidayItemMap.find(startDate)->second;
989596a2c1Sopenharmony_ci        return list.size() > 0;
999596a2c1Sopenharmony_ci    }
1009596a2c1Sopenharmony_ci    return false;
1019596a2c1Sopenharmony_ci}
1029596a2c1Sopenharmony_ci
1039596a2c1Sopenharmony_cistd::string HolidayManager::Format(int32_t year, int32_t month, int32_t day)
1049596a2c1Sopenharmony_ci{
1059596a2c1Sopenharmony_ci    std::string formated;
1069596a2c1Sopenharmony_ci    formated += std::to_string(year);
1079596a2c1Sopenharmony_ci    // Numbers less than 10 are one digit
1089596a2c1Sopenharmony_ci    formated += month < 10 ? ("0" + std::to_string(month)) : std::to_string(month);
1099596a2c1Sopenharmony_ci    // Numbers less than 10 are one digit
1109596a2c1Sopenharmony_ci    formated += day < 10 ? ("0" + std::to_string(day)) : std::to_string(day);
1119596a2c1Sopenharmony_ci    return formated;
1129596a2c1Sopenharmony_ci}
1139596a2c1Sopenharmony_ci
1149596a2c1Sopenharmony_cistd::vector<HolidayInfoItem> HolidayManager::GetHolidayInfoItemArray()
1159596a2c1Sopenharmony_ci{
1169596a2c1Sopenharmony_ci    time_t timeStamp = time(NULL);
1179596a2c1Sopenharmony_ci    struct tm* timObj = localtime(&timeStamp);
1189596a2c1Sopenharmony_ci    if (timObj == nullptr) {
1199596a2c1Sopenharmony_ci        std::vector<HolidayInfoItem> emptyList;
1209596a2c1Sopenharmony_ci        return emptyList;
1219596a2c1Sopenharmony_ci    }
1229596a2c1Sopenharmony_ci    int32_t realYear = timObj->tm_year + YEAR_START;
1239596a2c1Sopenharmony_ci    return GetHolidayInfoItemArray(realYear);
1249596a2c1Sopenharmony_ci}
1259596a2c1Sopenharmony_ci
1269596a2c1Sopenharmony_cistd::vector<HolidayInfoItem> HolidayManager::GetHolidayInfoItemArray(int32_t year)
1279596a2c1Sopenharmony_ci{
1289596a2c1Sopenharmony_ci    std::vector<HolidayInfoItem> vetor;
1299596a2c1Sopenharmony_ci    std::string formatedYear = std::to_string(year);
1309596a2c1Sopenharmony_ci    std::map<std::string, std::vector<HolidayInfoItem>>::iterator iter;
1319596a2c1Sopenharmony_ci    for (iter = holidayItemMap.begin(); iter != holidayItemMap.end(); ++iter) {
1329596a2c1Sopenharmony_ci        std::string key = iter->first;
1339596a2c1Sopenharmony_ci        if (formatedYear == key.substr(0, 4)) { // 4 is the length of full year
1349596a2c1Sopenharmony_ci            std::vector<HolidayInfoItem> temp = iter->second;
1359596a2c1Sopenharmony_ci            for (size_t i = 0; i < temp.size(); i++) {
1369596a2c1Sopenharmony_ci                vetor.push_back(temp[i]);
1379596a2c1Sopenharmony_ci            }
1389596a2c1Sopenharmony_ci        }
1399596a2c1Sopenharmony_ci    }
1409596a2c1Sopenharmony_ci    return vetor;
1419596a2c1Sopenharmony_ci}
1429596a2c1Sopenharmony_ci
1439596a2c1Sopenharmony_cistd::string HolidayManager::ValidateHolidayFilePath(const char* path)
1449596a2c1Sopenharmony_ci{
1459596a2c1Sopenharmony_ci    char *realpathRes = realpath(path, nullptr);
1469596a2c1Sopenharmony_ci    if (realpathRes == NULL) {
1479596a2c1Sopenharmony_ci        free(realpathRes);
1489596a2c1Sopenharmony_ci        return "the holiday resource file not exists.";
1499596a2c1Sopenharmony_ci    }
1509596a2c1Sopenharmony_ci    std::ifstream file(path);
1519596a2c1Sopenharmony_ci    if (!file.good()) {
1529596a2c1Sopenharmony_ci        free(realpathRes);
1539596a2c1Sopenharmony_ci        file.close();
1549596a2c1Sopenharmony_ci        return "the holiday resource file can't read.";
1559596a2c1Sopenharmony_ci    }
1569596a2c1Sopenharmony_ci    file.close();
1579596a2c1Sopenharmony_ci    free(realpathRes);
1589596a2c1Sopenharmony_ci    realpathRes = NULL;
1599596a2c1Sopenharmony_ci    return "";
1609596a2c1Sopenharmony_ci}
1619596a2c1Sopenharmony_ci
1629596a2c1Sopenharmony_cistd::vector<HolidayInfoItem> HolidayManager::ReadHolidayFile(const char* path)
1639596a2c1Sopenharmony_ci{
1649596a2c1Sopenharmony_ci    std::vector<HolidayInfoItem> items;
1659596a2c1Sopenharmony_ci    if (path == nullptr) {
1669596a2c1Sopenharmony_ci        return items;
1679596a2c1Sopenharmony_ci    }
1689596a2c1Sopenharmony_ci    std::ifstream fin;
1699596a2c1Sopenharmony_ci    fin.open(path, std::ios::in);
1709596a2c1Sopenharmony_ci    std::string line;
1719596a2c1Sopenharmony_ci    while (getline(fin, line)) {
1729596a2c1Sopenharmony_ci        line = Trim(line);
1739596a2c1Sopenharmony_ci        if (line.compare(ITEM_BEGIN_TAG) != 0) {
1749596a2c1Sopenharmony_ci            continue;
1759596a2c1Sopenharmony_ci        }
1769596a2c1Sopenharmony_ci        struct HolidayInfoItem holidayItem;
1779596a2c1Sopenharmony_ci        while (getline(fin, line)) {
1789596a2c1Sopenharmony_ci            line = Trim(line);
1799596a2c1Sopenharmony_ci            ParseFileLine(line, &(holidayItem));
1809596a2c1Sopenharmony_ci            if (line.compare(ITEM_END_TAG) == 0) {
1819596a2c1Sopenharmony_ci                items.push_back(holidayItem);
1829596a2c1Sopenharmony_ci                break;
1839596a2c1Sopenharmony_ci            }
1849596a2c1Sopenharmony_ci        }
1859596a2c1Sopenharmony_ci    }
1869596a2c1Sopenharmony_ci    fin.close();
1879596a2c1Sopenharmony_ci    return items;
1889596a2c1Sopenharmony_ci}
1899596a2c1Sopenharmony_ci
1909596a2c1Sopenharmony_civoid HolidayManager::ParseFileLine(const std::string &line, HolidayInfoItem *holidayItem)
1919596a2c1Sopenharmony_ci{
1929596a2c1Sopenharmony_ci    if (holidayItem == nullptr) {
1939596a2c1Sopenharmony_ci        return;
1949596a2c1Sopenharmony_ci    }
1959596a2c1Sopenharmony_ci    std::regex reg("([A-Z]+)[:;](.+)");
1969596a2c1Sopenharmony_ci    std::smatch match;
1979596a2c1Sopenharmony_ci    bool found = RegexSearchNoExcept(line, match, reg);
1989596a2c1Sopenharmony_ci    if (found) {
1999596a2c1Sopenharmony_ci        std::string tag = match[1].str();
2009596a2c1Sopenharmony_ci        std::string value = line.substr(line.find_last_of(":") + 1, line.length());
2019596a2c1Sopenharmony_ci        if (tag.compare(ITEM_DTSTART_TAG) == 0) {
2029596a2c1Sopenharmony_ci            std::string startDate = value.size() >= 8 ? value.substr(0, 8) : ""; // 8 is date formarted string length
2039596a2c1Sopenharmony_ci            if (startDate.size() == 8) {
2049596a2c1Sopenharmony_ci                struct tm timeObj;
2059596a2c1Sopenharmony_ci                strptime(startDate.c_str(), "%Y%m%d", &timeObj);
2069596a2c1Sopenharmony_ci                holidayItem->year = timeObj.tm_year;
2079596a2c1Sopenharmony_ci                holidayItem->month = timeObj.tm_mon;
2089596a2c1Sopenharmony_ci                holidayItem->day = timeObj.tm_mday;
2099596a2c1Sopenharmony_ci            }
2109596a2c1Sopenharmony_ci        } else if (tag.compare(ITEM_SUMMARY_TAG) == 0) {
2119596a2c1Sopenharmony_ci            holidayItem->baseName = value;
2129596a2c1Sopenharmony_ci        } else if (tag.compare(ITEM_RESOURCES_TAG) == 0) {
2139596a2c1Sopenharmony_ci            std::string displayName = line.substr(line.find_last_of("=") + 1, line.length());
2149596a2c1Sopenharmony_ci            std::string language = displayName.substr(0, displayName.find_first_of(":"));
2159596a2c1Sopenharmony_ci            std::string localName = displayName.substr(displayName.find_first_of(":") + 1, displayName.length());
2169596a2c1Sopenharmony_ci            transform(language.begin(), language.end(), language.begin(), ::tolower);
2179596a2c1Sopenharmony_ci            HolidayLocalName localeName = {language, PseudoLocalizationProcessor(localName)};
2189596a2c1Sopenharmony_ci            holidayItem->localNames.push_back(localeName);
2199596a2c1Sopenharmony_ci        }
2209596a2c1Sopenharmony_ci    }
2219596a2c1Sopenharmony_ci}
2229596a2c1Sopenharmony_ci
2239596a2c1Sopenharmony_cistd::string& HolidayManager::Trim(std::string &str)
2249596a2c1Sopenharmony_ci{
2259596a2c1Sopenharmony_ci    if (str.empty()) {
2269596a2c1Sopenharmony_ci        return str;
2279596a2c1Sopenharmony_ci    }
2289596a2c1Sopenharmony_ci    str.erase(0, str.find_first_not_of(" \t"));
2299596a2c1Sopenharmony_ci    str.erase(str.find_last_not_of("\r\n\t") + 1);
2309596a2c1Sopenharmony_ci    return str;
2319596a2c1Sopenharmony_ci}
2329596a2c1Sopenharmony_ci} // namespace I18n
2339596a2c1Sopenharmony_ci} // namespace Global
2349596a2c1Sopenharmony_ci} // namespace OHOS
235