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 "scene_delegate.h"
17
18#include "normal_scene.h"
19#include "wukong_util.h"
20
21namespace OHOS {
22namespace WuKong {
23namespace {
24const float SAMEPERCENT = 0.8;
25const int ONELAYER = 1;
26const int ZEROLAYER = 0;
27const float MINCOVERAGE = 0.9;
28uint8_t LISTITEM_COUNT = 0;
29uint8_t GRID_COUNT = 0;
30uint8_t NUMBER_ZERO = 0;
31uint8_t LISTITEM_COUNT_LIMIT = 10;
32}  // namespace
33SceneDelegate::SceneDelegate()
34{
35}
36SceneDelegate::~SceneDelegate()
37{
38}
39
40ErrCode SceneDelegate::GetCurrentComponentInfo(std::shared_ptr<ComponentTree> componentinfo,
41                                               std::vector<std::shared_ptr<ComponentTree>> &componentlist)
42{
43    ErrCode result = OHOS::ERR_OK;
44    if (componentinfo == nullptr) {
45        return OHOS::ERR_NO_INIT;
46    }
47    auto componentinfos = componentinfo->GetChildren();
48    if (componentinfos.size() > 0) {
49        bool isListItem = false;
50        for (auto it : componentinfos) {
51            auto componenttree = std::static_pointer_cast<ComponentTree>(it);
52            if (componenttree->GetType() == "GridContainer") {
53                componentlist.push_back(componenttree);
54                componentType_.push_back("GridContainer");
55                GRID_COUNT++;
56                TRACK_LOG_STR("GridContainer count %u", GRID_COUNT);
57            }
58            if (componenttree->GetType() == "List") {
59                LISTITEM_COUNT = NUMBER_ZERO;
60            }
61            if (componenttree->GetType() == "ListItem") {
62                isListItem = true;
63                LISTITEM_COUNT++;
64            }
65            GetCurrentComponentInfo(componenttree, componentlist);
66            if (isListItem && LISTITEM_COUNT >= LISTITEM_COUNT_LIMIT) {
67                break;
68            }
69        }
70    } else if (GRID_COUNT <= componentlist.size() &&
71               std::static_pointer_cast<ComponentTree>(componentinfo)->IsVisible() &&
72               IsComponentInScreen(std::static_pointer_cast<ComponentTree>(componentinfo))) {
73        componentlist.emplace(componentlist.end() - GRID_COUNT, componentinfo);
74        componentType_.push_back(std::static_pointer_cast<ComponentTree>(componentinfo)->GetType());
75    }
76    return result;
77}
78
79ErrCode SceneDelegate::ChooseScene(bool isRandom)
80{
81    ErrCode result;
82    GRID_COUNT = 0;
83    componentType_.clear();
84    auto treemanager = TreeManager::GetInstance();
85    auto newpage = treemanager->GetNewPage();
86    if (newpage == nullptr) {
87        ERROR_LOG("newpage is nullptr");
88        return OHOS::ERR_NO_INIT;
89    }
90    auto newcomponents = treemanager->GetNewComponents();
91    if (newcomponents == nullptr) {
92        ERROR_LOG("newcomponents is nullptr");
93        return OHOS::ERR_NO_INIT;
94    }
95    std::vector<std::shared_ptr<ComponentTree>> allcomponentlist;
96    // get current component list
97    GetCurrentComponentInfo(newcomponents, allcomponentlist);
98    // set all component counts of new page
99    newpage->SetAllComponentCount(allcomponentlist.size());
100    // set valid component counts of new page
101    newpage->SetValidComponentCount(allcomponentlist.size());
102    // get current page node
103    std::shared_ptr<WuKongTree> currentpage = treemanager->GetCurrentPage();
104    if (currentpage == nullptr) {
105        DEBUG_LOG("first page");
106        treemanager->AddPage();
107        // set available component list of current page
108        result = SetAvailableComponentList(newcomponents, isRandom);
109        TRACK_LOG_STR("new component Node Id: %016llX", newcomponents->GetNodeId());
110        return result;
111    }
112    DEBUG_LOG_STR("new ID: %016llX ,old ID: %016llX", newpage->GetNodeId(), currentpage->GetNodeId());
113    auto currentcomponents = treemanager->GetCurrentComponents();
114    if (currentcomponents == nullptr) {
115        ERROR_LOG("currentcomponents is nullptr");
116        return OHOS::ERR_NO_INIT;
117    }
118    if (newpage->IsEqual(currentpage)) {
119        treemanager->SamePage();
120        DEBUG_LOG("at same page");
121        result = SetAvailableComponentList(currentcomponents, isRandom);
122        return result;
123    } else {
124        bool isFoundParent = false;
125        // find the same page in parent list
126        result = FindSamePageInParent(isFoundParent, isRandom);
127        if (result != OHOS::ERR_OK || isFoundParent) {
128            return result;
129        }
130        bool isFoundChildren = false;
131        // find the same page in chidren list
132        result = FindSamePageInChildren(isFoundChildren, isRandom);
133        if (result != OHOS::ERR_OK) {
134            return result;
135        }
136        if (!isFoundChildren) {
137            auto currentcomponentinfo = treemanager->GetCurrentComponents();
138            if (currentcomponentinfo == nullptr) {
139                ERROR_LOG("currentcomponentinfo is nullptr");
140                return OHOS::ERR_NO_INIT;
141            }
142            // compare new component tree and current component tree
143            CompareComponentInfos(newcomponents, currentcomponentinfo, isRandom);
144        }
145    }
146    return result;
147}
148
149ErrCode SceneDelegate::CompareComponentInfos(std::shared_ptr<ComponentTree> &newcomponentinfo,
150                                             std::shared_ptr<ComponentTree> &oldcomponentinfo, bool isRandom)
151{
152    ErrCode result;
153    DEBUG_LOG("compare page");
154    GRID_COUNT = 0;
155    componentType_.clear();
156    std::vector<std::shared_ptr<ComponentTree>> newChildList;
157    GetCurrentComponentInfo(newcomponentinfo, newChildList);
158    GRID_COUNT = 0;
159    componentType_.clear();
160    std::vector<std::shared_ptr<ComponentTree>> currentChildList;
161    GetCurrentComponentInfo(oldcomponentinfo, currentChildList);
162    auto treemanager = TreeManager::GetInstance();
163    DEBUG_LOG_STR("childlist size %d", currentChildList.size());
164    float samePercent = 0.0;
165    // get the same count in new component list and current component list
166    uint32_t samecount = FindSame(newChildList, currentChildList);
167    if (samecount > 0) {
168        if (newChildList.size() > currentChildList.size()) {
169            samePercent = (float)samecount / (float)currentChildList.size();
170        } else {
171            samePercent = (float)samecount / (float)newChildList.size();
172        }
173    }
174
175    DEBUG_LOG_STR("same percent: %2f", samePercent);
176    if (samePercent > SAMEPERCENT) {
177        if (!treemanager->UpdatePage(ZEROLAYER)) {
178            DEBUG_LOG("update failed");
179            return OHOS::ERR_NO_INIT;
180        }
181        auto currentComponentinfo = treemanager->GetCurrentComponents();
182        if (currentComponentinfo == nullptr) {
183            ERROR_LOG("current component is nullptr");
184            return OHOS::ERR_NO_INIT;
185        }
186        result = SetAvailableComponentList(currentComponentinfo, isRandom);
187    } else {
188        auto newcomponent = treemanager->GetNewComponents();
189        DEBUG_LOG("add new page");
190        treemanager->AddPage();
191        result = SetAvailableComponentList(newcomponent, isRandom);
192    }
193    return result;
194}
195
196ErrCode SceneDelegate::SetAvailableComponentList(std::shared_ptr<ComponentTree> componentinfo, bool isRandom)
197{
198    GRID_COUNT = 0;
199    componentType_.clear();
200    ErrCode result = OHOS::ERR_OK;
201    NormalScene normalscene;
202    std::vector<std::shared_ptr<ComponentTree>> componentlist;
203    std::shared_ptr<ComponentTree> inputcomponent = nullptr;
204    auto treemanager = TreeManager::GetInstance();
205    GetCurrentComponentInfo(componentinfo, componentlist);
206    if (isRandom) {
207        // get valid components from scene
208        normalscene.SetInputComponentList(componentlist);
209        isBack_ = normalscene.IsBackToPrePage();
210        TRACK_LOG_STR("is random back: %d", isBack_);
211        // set valid components to tree manager
212        treemanager->SetActiveComponent(componentlist);
213    } else {
214        // get valid component from scene
215        normalscene.SetInputComponent(componentlist, inputcomponent);
216        isBack_ = normalscene.IsBackToPrePage();
217        TRACK_LOG_STR("is special back: %d", isBack_);
218        if (inputcomponent != nullptr) {
219            // set valid component to tree manager
220            treemanager->SetActiveComponent(inputcomponent);
221        }
222    }
223    return result;
224}
225
226uint32_t SceneDelegate::FindSame(const std::vector<std::shared_ptr<ComponentTree>> &newcomponentlist,
227                                 const std::vector<std::shared_ptr<ComponentTree>> &oldcomponentlist)
228{
229    uint32_t count = 0;
230    for (auto newIt : newcomponentlist) {
231        for (auto oldIt : oldcomponentlist) {
232            if (newIt->IsEqual(oldIt)) {
233                count++;
234            }
235        }
236    }
237    return count;
238}
239
240ErrCode SceneDelegate::FindSamePageInChildren(bool &isFound, bool isRandom)
241{
242    ErrCode result = OHOS::ERR_OK;
243    auto treemanager = TreeManager::GetInstance();
244    auto newpage = treemanager->GetNewPage();
245    std::shared_ptr<WuKongTree> currentpage = treemanager->GetCurrentPage();
246    auto pagechild = currentpage->GetChildren();
247    if (pagechild.empty()) {
248        return result;
249    }
250    int childIndex = -1;
251    for (auto it : pagechild) {
252        TRACK_LOG_STR("current child ID: %016llX ", it->GetNodeId());
253        childIndex++;
254        if (newpage->IsEqual(it)) {
255            DEBUG_LOG("go to same page");
256            if (!treemanager->UpdatePage(ONELAYER, childIndex)) {
257                DEBUG_LOG("update failed");
258                return OHOS::ERR_NO_INIT;
259            }
260            auto gotocurrent = treemanager->GetCurrentComponents();
261            if (gotocurrent == nullptr) {
262                ERROR_LOG("goto current is nullptr");
263                return OHOS::ERR_NO_INIT;
264            }
265            result = SetAvailableComponentList(gotocurrent, isRandom);
266            isFound = true;
267            return result;
268        }
269    }
270    return result;
271}
272
273ErrCode SceneDelegate::FindSamePageInParent(bool &isFound, bool isRandom)
274{
275    ErrCode result = OHOS::ERR_OK;
276    auto treemanager = TreeManager::GetInstance();
277    auto newpage = treemanager->GetNewPage();
278    std::shared_ptr<WuKongTree> currentpage = treemanager->GetCurrentPage();
279    int layer = 0;
280    auto parentpage = currentpage->GetParent();
281    while (parentpage != nullptr) {
282        TRACK_LOG_STR("current parent ID: %016llX ", parentpage->GetNodeId());
283        layer--;
284        if (newpage->IsEqual(parentpage)) {
285            auto oldpage = treemanager->GetCurrentPage();
286            if (oldpage == nullptr) {
287                ERROR_LOG("old page is nullptr");
288                return OHOS::ERR_NO_INIT;
289            }
290            float coverage = 0.0;
291            if (oldpage->GetValidComponentCount() > 0) {
292                coverage = (float)oldpage->GetInputCount() / (float)oldpage->GetValidComponentCount();
293            }
294
295            TRACK_LOG_STR("layer: (%d)", layer);
296            if (!treemanager->UpdatePage(layer)) {
297                DEBUG_LOG("update failed");
298                return OHOS::ERR_NO_INIT;
299            }
300            if (coverage < MINCOVERAGE && !isRandom) {
301                DEBUG_LOG("continue to same page");
302                treemanager->SetActiveComponent(
303                    std::static_pointer_cast<PageTree>(parentpage)->GetCurrentComponentNode());
304            } else {
305                DEBUG_LOG("back to same page");
306                result = SetAvailableComponentList(treemanager->GetCurrentComponents(), isRandom);
307            }
308            isFound = true;
309            return result;
310        }
311        parentpage = parentpage->GetParent();
312    }
313    return result;
314}
315
316bool SceneDelegate::IsComponentInScreen(const std::shared_ptr<ComponentTree> componentinfo)
317{
318    int32_t width = -1;
319    int32_t height = -1;
320    ErrCode result = WuKongUtil::GetInstance()->GetScreenSize(width, height);
321    if (result != OHOS::ERR_OK) {
322        ERROR_LOG("failed to determine component position");
323        return false;
324    }
325    auto rect = componentinfo->GetPosition();
326    if ((rect.GetRightBottomXScreenPostion() <= width) && (rect.GetLeftTopXScreenPostion() <= width) &&
327        (rect.GetRightBottomYScreenPostion() <= height) && (rect.GetLeftTopYScreenPostion() <= height) &&
328        (rect.GetRightBottomXScreenPostion() >= 0) && (rect.GetLeftTopXScreenPostion() >= 0) &&
329        (rect.GetRightBottomYScreenPostion() >= 0) && (rect.GetLeftTopYScreenPostion() >= 0)) {
330        return true;
331    }
332    return false;
333}
334}  // namespace WuKong
335}  // namespace OHOS
336