1/*
2 * Copyright (c) 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#include "ime_cfg_manager.h"
17
18#include <algorithm>
19#include <fcntl.h>
20#include <ios>
21#include <string>
22
23#include "file_operator.h"
24#include "global.h"
25namespace OHOS {
26namespace MiscServices {
27namespace {
28constexpr const char *IME_CFG_FILE_PATH = "/data/service/el1/public/imf/ime_cfg.json";
29} // namespace
30ImeCfgManager &ImeCfgManager::GetInstance()
31{
32    static ImeCfgManager instance;
33    return instance;
34}
35
36void ImeCfgManager::Init()
37{
38    ReadImeCfg();
39}
40
41void ImeCfgManager::ReadImeCfg()
42{
43    if (!FileOperator::IsExist(IME_CFG_FILE_PATH)) {
44        IMSA_HILOGD("ime cfg file not found.");
45        return;
46    }
47    std::string cfg;
48    bool ret = FileOperator::Read(IME_CFG_FILE_PATH, cfg);
49    if (!ret) {
50        IMSA_HILOGE("failed to ReadJsonFile!");
51        return;
52    }
53    ParseImeCfg(cfg);
54}
55
56void ImeCfgManager::WriteImeCfg()
57{
58    auto content = PackageImeCfg();
59    if (content.empty()) {
60        IMSA_HILOGE("failed to Package imeCfg!");
61        return;
62    }
63    if (!FileOperator::Write(IME_CFG_FILE_PATH, content, O_CREAT | O_WRONLY | O_SYNC | O_TRUNC)) {
64        IMSA_HILOGE("failed to WriteJsonFile!");
65    }
66}
67
68bool ImeCfgManager::ParseImeCfg(const std::string &content)
69{
70    IMSA_HILOGD("content: %{public}s", content.c_str());
71    ImePersistCfg cfg;
72    auto ret = cfg.Unmarshall(content);
73    if (!ret) {
74        IMSA_HILOGE("Unmarshall failed!");
75        return false;
76    }
77    std::lock_guard<std::recursive_mutex> lock(imeCfgLock_);
78    imeConfigs_ = cfg.imePersistInfo;
79    return true;
80}
81
82std::string ImeCfgManager::PackageImeCfg()
83{
84    ImePersistCfg cfg;
85    {
86        std::lock_guard<std::recursive_mutex> lock(imeCfgLock_);
87        cfg.imePersistInfo = imeConfigs_;
88    }
89    std::string content;
90    auto ret = cfg.Marshall(content);
91    IMSA_HILOGD("ret: %{public}d, content: %{public}s, size: %{public}zu", ret, content.c_str(),
92        cfg.imePersistInfo.size());
93    return content;
94}
95
96void ImeCfgManager::AddImeCfg(const ImePersistInfo &cfg)
97{
98    std::lock_guard<std::recursive_mutex> lock(imeCfgLock_);
99    imeConfigs_.push_back(cfg);
100    WriteImeCfg();
101}
102
103void ImeCfgManager::ModifyImeCfg(const ImePersistInfo &cfg)
104{
105    std::lock_guard<std::recursive_mutex> lock(imeCfgLock_);
106    auto it = std::find_if(imeConfigs_.begin(), imeConfigs_.end(),
107        [&cfg](const ImePersistInfo &imeCfg) { return imeCfg.userId == cfg.userId && !cfg.currentIme.empty(); });
108    if (it != imeConfigs_.end()) {
109        if (it->isDefaultImeSet) {
110            ImePersistInfo imePersistInfo;
111            imePersistInfo.userId = cfg.userId;
112            imePersistInfo.currentIme = cfg.currentIme;
113            imePersistInfo.currentSubName = cfg.currentSubName;
114            imePersistInfo.isDefaultImeSet = true;
115            *it = imePersistInfo;
116        } else {
117            *it = cfg;
118        }
119    }
120
121    WriteImeCfg();
122}
123
124void ImeCfgManager::DeleteImeCfg(int32_t userId)
125{
126    std::lock_guard<std::recursive_mutex> lock(imeCfgLock_);
127    for (auto iter = imeConfigs_.begin(); iter != imeConfigs_.end(); iter++) {
128        if (iter->userId == userId) {
129            imeConfigs_.erase(iter);
130            break;
131        }
132    }
133    WriteImeCfg();
134}
135
136ImePersistInfo ImeCfgManager::GetImeCfg(int32_t userId)
137{
138    std::lock_guard<std::recursive_mutex> lock(imeCfgLock_);
139    auto it = std::find_if(imeConfigs_.begin(), imeConfigs_.end(),
140        [userId](const ImePersistInfo &cfg) { return cfg.userId == userId; });
141    if (it != imeConfigs_.end()) {
142        return *it;
143    }
144    return {};
145}
146
147std::shared_ptr<ImeNativeCfg> ImeCfgManager::GetCurrentImeCfg(int32_t userId)
148{
149    auto cfg = GetImeCfg(userId);
150    ImeNativeCfg info;
151    info.subName = cfg.currentSubName;
152    info.imeId = cfg.currentIme;
153    auto pos = info.imeId.find('/');
154    if (pos != std::string::npos && pos + 1 < info.imeId.size()) {
155        info.bundleName = info.imeId.substr(0, pos);
156        info.extName = info.imeId.substr(pos + 1);
157    }
158    return std::make_shared<ImeNativeCfg>(info);
159}
160
161bool ImeCfgManager::IsDefaultImeSet(int32_t userId)
162{
163    IMSA_HILOGI("ImeCfgManager::IsDefaultImeSet enter.");
164    auto cfg = GetImeCfg(userId);
165    IMSA_HILOGI("isDefaultImeSet: %{public}d", cfg.isDefaultImeSet);
166    return cfg.isDefaultImeSet;
167}
168} // namespace MiscServices
169} // namespace OHOS