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
16#include "tooling/client/manager/variable_manager.h"
17
18#include <iomanip>
19
20#include "common/log_wrapper.h"
21
22using PtJson = panda::ecmascript::tooling::PtJson;
23namespace OHOS::ArkCompiler::Toolchain {
24void TreeNode::AddChild(std::unique_ptr<PropertyDescriptor> descriptor)
25{
26    children.push_back(std::make_unique<TreeNode>(std::move(descriptor)));
27}
28
29void TreeNode::AddChild(DescriptorMap descriptorMap)
30{
31    children.push_back(std::make_unique<TreeNode>(std::move(descriptorMap)));
32}
33
34void TreeNode::AddChild(std::unique_ptr<TreeNode> child)
35{
36    children.push_back(std::move(child));
37}
38
39void TreeNode::Print(int depth) const
40{
41    int actualIndent = 0;
42    if (depth > 1) {
43        actualIndent = (depth - 1) * 4; // 4: four spaces
44    }
45    std::string indent(actualIndent, ' ');
46
47    if (std::holds_alternative<int32_t>(data)) {
48        std::cout << indent << "CallFrameId: " << std::get<int32_t>(data) << std::endl;
49    } else if (std::holds_alternative<std::map<int32_t, std::map<int32_t, std::string>>>(data)) {
50        const auto& outerMap = std::get<std::map<int32_t, std::map<int32_t, std::string>>>(data);
51        for (const auto& [key, innerMap] : outerMap) {
52            for (const auto& [innerKey, value] : innerMap) {
53                std::cout << key << ". " << value << std::endl;
54            }
55        }
56    } else if (std::holds_alternative<std::unique_ptr<PropertyDescriptor>>(data)) {
57        const auto &descriptor = std::get<std::unique_ptr<PropertyDescriptor>>(data);
58        if (descriptor && descriptor->GetValue()) {
59            if (descriptor->GetValue()->HasDescription()) {
60                std::cout << indent << "   " << descriptor->GetName() << " = "
61                      << descriptor->GetValue()->GetDescription() << std::endl;
62            } else {
63                std::cout << indent << "   " << descriptor->GetName() << " = "
64                      << descriptor->GetValue()->GetType() << std::endl;
65            }
66        }
67    } else if (std::holds_alternative<DescriptorMap>(data)) {
68        const auto &descriptorMap = std::get<DescriptorMap>(data);
69        for (const auto& [key, descriptor] : descriptorMap) {
70            std::cout << indent << key << ". ";
71            if (descriptor && descriptor->GetValue()) {
72                std::cout << descriptor->GetName() << " = " << descriptor->GetValue()->GetDescription() << std::endl;
73            }
74        }
75    }
76
77    for (const auto &child : children) {
78        child->Print(depth + 1);
79    }
80}
81
82Tree::Tree(const std::map<int32_t, std::map<int32_t, std::string>>& dataMap, int32_t index)
83{
84    root_ = std::make_unique<TreeNode>(index);
85
86    auto it = dataMap.find(index);
87    if (it != dataMap.end()) {
88        for (const auto& [key, value] : it->second) {
89            std::map<int32_t, std::map<int32_t, std::string>> childData;
90            childData[index_] = {{key, value}};
91            root_->children.push_back(std::make_unique<TreeNode>(childData));
92            index_++;
93        }
94    }
95}
96
97void Tree::PrintRootAndImmediateChildren() const
98{
99    if (std::holds_alternative<int32_t>(root_->data)) {
100        std::cout << "CallFrame ID: " << std::get<int32_t>(root_->data) << std::endl;
101    }
102
103    for (const auto& child : root_->children) {
104        if (std::holds_alternative<std::map<int32_t, std::map<int32_t, std::string>>>(child->data)) {
105            const auto& outerMap = std::get<std::map<int32_t, std::map<int32_t, std::string>>>(child->data);
106            for (const auto& [index, innerMap] : outerMap) {
107                std::cout << "  Index: " << index << std::endl;
108                for (const auto& [objectId, type] : innerMap) {
109                    std::cout << "    Object ID: " << objectId << ", Type: " << type << std::endl;
110                }
111            }
112        }
113    }
114}
115
116void Tree::Clear()
117{
118    if (root_ != nullptr) {
119        root_.reset();
120    }
121}
122
123void Tree::Print() const
124{
125    if (root_) {
126        root_->Print();
127    }
128}
129
130TreeNode* Tree::FindNodeWithObjectId(int32_t objectId) const
131{
132    return FindNodeWithObjectIdRecursive(root_.get(), objectId);
133}
134
135void Tree::AddVariableNode(TreeNode* parentNode, std::unique_ptr<PropertyDescriptor> descriptor)
136{
137    if (!parentNode) {
138        return;
139    }
140    parentNode->AddChild(std::move(descriptor));
141}
142
143void Tree::AddObjectNode(TreeNode* parentNode, std::unique_ptr<PropertyDescriptor> descriptor)
144{
145    if (!parentNode) {
146        return;
147    }
148    DescriptorMap descriptorMap;
149    descriptorMap[index_] = std::move(descriptor);
150    parentNode->AddChild(std::move(descriptorMap));
151    index_++;
152}
153
154TreeNode* Tree::GetRoot() const
155{
156    return root_.get();
157}
158
159TreeNode* Tree::FindNodeWithObjectIdRecursive(TreeNode* node, int32_t objectId) const
160{
161    if (!node) {
162        return nullptr;
163    }
164
165    if (std::holds_alternative<std::map<int32_t, std::map<int32_t, std::string>>>(node->data)) {
166        const auto& outerMap = std::get<std::map<int32_t, std::map<int32_t, std::string>>>(node->data);
167        for (const auto& [key, innerMap] : outerMap) {
168            if (innerMap.find(objectId) != innerMap.end()) {
169                return node;
170            }
171        }
172    } else if (std::holds_alternative<DescriptorMap>(node->data)) {
173        const auto& descriptorMap = std::get<DescriptorMap>(node->data);
174        for (const auto& [key, descriptor] : descriptorMap) {
175            if (descriptor && descriptor->GetValue() && descriptor->GetValue()->GetObjectId() == objectId) {
176                return node;
177            }
178        }
179    }
180
181    for (const auto& child : node->children) {
182        TreeNode* foundNode = FindNodeWithObjectIdRecursive(child.get(), objectId);
183        if (foundNode) {
184            return foundNode;
185        }
186    }
187
188    return nullptr;
189}
190
191TreeNode* Tree::FindNodeWithInnerKeyZero(TreeNode* node) const
192{
193    if (!node) {
194        return nullptr;
195    }
196
197    if (std::holds_alternative<std::map<int32_t, std::map<int32_t, std::string>>>(node->data)) {
198        const auto &outerMap = std::get<std::map<int32_t, std::map<int32_t, std::string>>>(node->data);
199        for (const auto &innerMapPair : outerMap) {
200            if (innerMapPair.second.find(0) != innerMapPair.second.end()) {
201                return node;
202            }
203        }
204    }
205
206    for (const auto &child : node->children) {
207        TreeNode* foundNode = FindNodeWithInnerKeyZero(child.get());
208        if (foundNode) {
209            return foundNode;
210        }
211    }
212
213    return nullptr;
214}
215TreeNode* Tree::FindNodeWithCondition() const
216{
217    return FindNodeWithInnerKeyZero(root_.get());
218}
219
220int32_t Tree::FindObjectByIndex(int32_t index) const
221{
222    return FindObjectByIndexRecursive(root_.get(), index);
223}
224
225int32_t Tree::FindObjectByIndexRecursive(const TreeNode* node, int32_t index) const
226{
227    if (!node) {
228        return 0;
229    }
230
231    if (std::holds_alternative<std::map<int32_t, std::map<int32_t, std::string>>>(node->data)) {
232        const auto &outerMap = std::get<std::map<int32_t, std::map<int32_t, std::string>>>(node->data);
233        auto it = outerMap.find(index);
234        if (it != outerMap.end() && !it->second.empty()) {
235            return it->second.begin()->first;
236        }
237    } else if (std::holds_alternative<DescriptorMap>(node->data)) {
238        const auto &descriptorMap = std::get<DescriptorMap>(node->data);
239        auto it = descriptorMap.find(index);
240        if (it != descriptorMap.end() && it->second && it->second->GetValue()) {
241            return it->second->GetValue()->GetObjectId();
242        }
243    }
244
245    for (const auto& child : node->children) {
246        int32_t result = FindObjectByIndexRecursive(child.get(), index);
247        if (result != 0) {
248            return result;
249        }
250    }
251
252    return 0;
253}
254
255void VariableManager::SetHeapUsageInfo(std::unique_ptr<GetHeapUsageReturns> heapUsageReturns)
256{
257    heapUsageInfo_.SetUsedSize(heapUsageReturns->GetUsedSize());
258    heapUsageInfo_.SetTotalSize(heapUsageReturns->GetTotalSize());
259}
260
261void VariableManager::ShowHeapUsageInfo() const
262{
263    std::cout << std::endl;
264    std::cout << "UsedSize is: " << heapUsageInfo_.GetUsedSize() << std::endl;
265    std::cout << "TotalSize is: " << std::fixed << std::setprecision(0) << heapUsageInfo_.GetTotalSize() << std::endl;
266}
267
268void VariableManager::ShowVariableInfos() const
269{
270    variableInfo_.Print();
271}
272
273void VariableManager::ClearVariableInfo()
274{
275    variableInfo_.Clear();
276}
277void VariableManager::InitializeTree(std::map<int32_t, std::map<int32_t, std::string>> dataMap, int index)
278{
279    variableInfo_ = Tree(dataMap, index);
280}
281
282void VariableManager::PrintVariableInfo()
283{
284    variableInfo_.Print();
285}
286
287TreeNode* VariableManager::FindNodeWithObjectId(int32_t objectId)
288{
289    return variableInfo_.FindNodeWithObjectId(objectId);
290}
291
292void VariableManager::AddVariableInfo(TreeNode *parentNode, std::unique_ptr<PropertyDescriptor> variableInfo)
293{
294    if (variableInfo && variableInfo->GetValue() && variableInfo->GetValue()->HasObjectId()) {
295        variableInfo_.AddObjectNode(parentNode, std::move(variableInfo));
296    } else {
297        variableInfo_.AddVariableNode(parentNode, std::move(variableInfo));
298    }
299}
300
301TreeNode* VariableManager::FindNodeObjectZero()
302{
303    return variableInfo_.FindNodeWithCondition();
304}
305
306int32_t VariableManager::FindObjectIdWithIndex(int index)
307{
308    return variableInfo_.FindObjectByIndex(index);
309}
310
311void VariableManager::Printinfo() const
312{
313    variableInfo_.PrintRootAndImmediateChildren();
314}
315}