18bf80f4bSopenharmony_ci/*
28bf80f4bSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License.
58bf80f4bSopenharmony_ci * You may obtain a copy of the License at
68bf80f4bSopenharmony_ci *
78bf80f4bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
88bf80f4bSopenharmony_ci *
98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and
138bf80f4bSopenharmony_ci * limitations under the License.
148bf80f4bSopenharmony_ci */
158bf80f4bSopenharmony_ci
168bf80f4bSopenharmony_ci#include "container.h"
178bf80f4bSopenharmony_ci
188bf80f4bSopenharmony_ci#include <algorithm>
198bf80f4bSopenharmony_ci
208bf80f4bSopenharmony_ci#include <base/math/mathf.h>
218bf80f4bSopenharmony_ci
228bf80f4bSopenharmony_ci#include <meta/base/interface_utils.h>
238bf80f4bSopenharmony_ci#include <meta/interface/intf_containable.h>
248bf80f4bSopenharmony_ci#include <meta/interface/intf_content.h>
258bf80f4bSopenharmony_ci#include <meta/interface/property/intf_property.h>
268bf80f4bSopenharmony_ci
278bf80f4bSopenharmony_ciMETA_BEGIN_NAMESPACE()
288bf80f4bSopenharmony_ci
298bf80f4bSopenharmony_ciIObject::Ptr Container::FindAny(const META_NS::IContainer::FindOptions& options) const
308bf80f4bSopenharmony_ci{
318bf80f4bSopenharmony_ci    return ContainerBase::FindAnyImpl(options, false);
328bf80f4bSopenharmony_ci}
338bf80f4bSopenharmony_ci
348bf80f4bSopenharmony_ciBASE_NS::vector<IObject::Ptr> Container::FindAll(const META_NS::IContainer::FindOptions& options) const
358bf80f4bSopenharmony_ci{
368bf80f4bSopenharmony_ci    return ContainerBase::FindAllImpl(options, false);
378bf80f4bSopenharmony_ci}
388bf80f4bSopenharmony_ci
398bf80f4bSopenharmony_cibool Container::Add(const META_NS::IObject::Ptr& object)
408bf80f4bSopenharmony_ci{
418bf80f4bSopenharmony_ci    if (!object) {
428bf80f4bSopenharmony_ci        return false;
438bf80f4bSopenharmony_ci    }
448bf80f4bSopenharmony_ci    const auto direct = !OnAdding()->HasHandlers();
458bf80f4bSopenharmony_ci    SizeType index;
468bf80f4bSopenharmony_ci    {
478bf80f4bSopenharmony_ci        std::unique_lock lock(mutex_);
488bf80f4bSopenharmony_ci        if (!IsCompatible(object) || !CheckLoop(object)) {
498bf80f4bSopenharmony_ci            return false;
508bf80f4bSopenharmony_ci        }
518bf80f4bSopenharmony_ci        for (const auto& child : children_) {
528bf80f4bSopenharmony_ci            if (child == object) {
538bf80f4bSopenharmony_ci                return true; // Already a child of ours
548bf80f4bSopenharmony_ci            }
558bf80f4bSopenharmony_ci        }
568bf80f4bSopenharmony_ci        index = children_.size();
578bf80f4bSopenharmony_ci        if (direct) {
588bf80f4bSopenharmony_ci            children_.push_back(object);
598bf80f4bSopenharmony_ci        }
608bf80f4bSopenharmony_ci    }
618bf80f4bSopenharmony_ci    // Calling external interface methods outside of our internal lock
628bf80f4bSopenharmony_ci    bool success = true;
638bf80f4bSopenharmony_ci    ChildChangedInfo info { object, index, parent_ };
648bf80f4bSopenharmony_ci    if (!direct) {
658bf80f4bSopenharmony_ci        Invoke<IOnChildChanging>(OnAdding(), info, success);
668bf80f4bSopenharmony_ci        if (success) {
678bf80f4bSopenharmony_ci            std::unique_lock lock(mutex_);
688bf80f4bSopenharmony_ci            children_.push_back(object);
698bf80f4bSopenharmony_ci        }
708bf80f4bSopenharmony_ci    }
718bf80f4bSopenharmony_ci    if (success) {
728bf80f4bSopenharmony_ci        SetObjectParent(object, interface_pointer_cast<IObject>(parent_));
738bf80f4bSopenharmony_ci        Invoke<IOnChildChanged>(OnAdded(), info);
748bf80f4bSopenharmony_ci    }
758bf80f4bSopenharmony_ci    return success;
768bf80f4bSopenharmony_ci}
778bf80f4bSopenharmony_ci
788bf80f4bSopenharmony_cibool Container::Insert(SizeType index, const IObject::Ptr& object)
798bf80f4bSopenharmony_ci{
808bf80f4bSopenharmony_ci    if (!object) {
818bf80f4bSopenharmony_ci        return false;
828bf80f4bSopenharmony_ci    }
838bf80f4bSopenharmony_ci    const auto direct = !OnAdding()->HasHandlers();
848bf80f4bSopenharmony_ci    {
858bf80f4bSopenharmony_ci        std::unique_lock lock(mutex_);
868bf80f4bSopenharmony_ci        if (!IsCompatible(object) || !CheckLoop(object)) {
878bf80f4bSopenharmony_ci            return false;
888bf80f4bSopenharmony_ci        }
898bf80f4bSopenharmony_ci        for (auto it = children_.begin(); it != children_.end(); ++it) {
908bf80f4bSopenharmony_ci            if (*it == object) {
918bf80f4bSopenharmony_ci                // Already in the container, remove from current position
928bf80f4bSopenharmony_ci                children_.erase(it);
938bf80f4bSopenharmony_ci                break;
948bf80f4bSopenharmony_ci            }
958bf80f4bSopenharmony_ci        }
968bf80f4bSopenharmony_ci        index = BASE_NS::Math::min(index, children_.size());
978bf80f4bSopenharmony_ci        if (direct) {
988bf80f4bSopenharmony_ci            children_.insert(children_.begin() + index, object);
998bf80f4bSopenharmony_ci        }
1008bf80f4bSopenharmony_ci    }
1018bf80f4bSopenharmony_ci    // Calling external interface methods outside of our internal lock
1028bf80f4bSopenharmony_ci    bool success = true;
1038bf80f4bSopenharmony_ci    ChildChangedInfo info { object, index, parent_ };
1048bf80f4bSopenharmony_ci    if (!direct) {
1058bf80f4bSopenharmony_ci        Invoke<IOnChildChanging>(OnAdding(), info, success);
1068bf80f4bSopenharmony_ci        if (success) {
1078bf80f4bSopenharmony_ci            std::unique_lock lock(mutex_);
1088bf80f4bSopenharmony_ci            children_.insert(children_.begin() + index, object);
1098bf80f4bSopenharmony_ci        }
1108bf80f4bSopenharmony_ci    }
1118bf80f4bSopenharmony_ci    if (success) {
1128bf80f4bSopenharmony_ci        SetObjectParent(object, interface_pointer_cast<IObject>(parent_));
1138bf80f4bSopenharmony_ci        Invoke<IOnChildChanged>(OnAdded(), info);
1148bf80f4bSopenharmony_ci    }
1158bf80f4bSopenharmony_ci    return success;
1168bf80f4bSopenharmony_ci}
1178bf80f4bSopenharmony_ci
1188bf80f4bSopenharmony_cibool Container::Replace(const META_NS::IObject::Ptr& child, const META_NS::IObject::Ptr& replaceWith, bool addAlways)
1198bf80f4bSopenharmony_ci{
1208bf80f4bSopenharmony_ci    IObject::Ptr removed;
1218bf80f4bSopenharmony_ci    IObject::Ptr added;
1228bf80f4bSopenharmony_ci    IObject::Ptr moved;
1238bf80f4bSopenharmony_ci    IContainer::SizeType fromIndex = 0;
1248bf80f4bSopenharmony_ci    IContainer::SizeType toIndex = 0;
1258bf80f4bSopenharmony_ci    bool changed = false; // True if any changes were made
1268bf80f4bSopenharmony_ci    {
1278bf80f4bSopenharmony_ci        std::unique_lock lock(mutex_);
1288bf80f4bSopenharmony_ci        if (replaceWith && (!IsCompatible(replaceWith) || !CheckLoop(replaceWith))) {
1298bf80f4bSopenharmony_ci            return false;
1308bf80f4bSopenharmony_ci        }
1318bf80f4bSopenharmony_ci        auto removedIt = children_.end();
1328bf80f4bSopenharmony_ci        auto movedIt = children_.end();
1338bf80f4bSopenharmony_ci        SizeType index = 0;
1348bf80f4bSopenharmony_ci        // Check if 'child' and 'replaceWith' can already be found from the container
1358bf80f4bSopenharmony_ci        for (auto it = children_.begin(); it != children_.end(); ++it, ++index) {
1368bf80f4bSopenharmony_ci            if (*it == child) {
1378bf80f4bSopenharmony_ci                removedIt = it;
1388bf80f4bSopenharmony_ci                removed = *it;
1398bf80f4bSopenharmony_ci                toIndex = index;
1408bf80f4bSopenharmony_ci            }
1418bf80f4bSopenharmony_ci            if (*it == replaceWith) {
1428bf80f4bSopenharmony_ci                movedIt = it;
1438bf80f4bSopenharmony_ci                moved = *it;
1448bf80f4bSopenharmony_ci                fromIndex = index;
1458bf80f4bSopenharmony_ci            }
1468bf80f4bSopenharmony_ci            if (removed && moved) {
1478bf80f4bSopenharmony_ci                break;
1488bf80f4bSopenharmony_ci            }
1498bf80f4bSopenharmony_ci        }
1508bf80f4bSopenharmony_ci        if (removed && removed == moved) {
1518bf80f4bSopenharmony_ci            // 'child' and 'replaceWith' are the same item (which is already in the container)
1528bf80f4bSopenharmony_ci            return true;
1538bf80f4bSopenharmony_ci        }
1548bf80f4bSopenharmony_ci        if (removed) {
1558bf80f4bSopenharmony_ci            // 'child' was found
1568bf80f4bSopenharmony_ci            if (replaceWith) {
1578bf80f4bSopenharmony_ci                *removedIt = replaceWith;
1588bf80f4bSopenharmony_ci                if (moved) {
1598bf80f4bSopenharmony_ci                    // 'replaceWith' was already in the container, remove it from its previous position
1608bf80f4bSopenharmony_ci                    children_.erase(movedIt);
1618bf80f4bSopenharmony_ci                } else {
1628bf80f4bSopenharmony_ci                    // 'replaceWith' was added
1638bf80f4bSopenharmony_ci                    added = replaceWith;
1648bf80f4bSopenharmony_ci                }
1658bf80f4bSopenharmony_ci            } else {
1668bf80f4bSopenharmony_ci                // 'replaceWith' == null, remove 'child'
1678bf80f4bSopenharmony_ci                children_.erase(removedIt);
1688bf80f4bSopenharmony_ci            }
1698bf80f4bSopenharmony_ci            changed = true;
1708bf80f4bSopenharmony_ci        } else {
1718bf80f4bSopenharmony_ci            moved.reset();
1728bf80f4bSopenharmony_ci        }
1738bf80f4bSopenharmony_ci        if (!changed && addAlways && replaceWith && movedIt == children_.end()) {
1748bf80f4bSopenharmony_ci            // 'child' was not found in container but addAlways is specified with a valid new item which
1758bf80f4bSopenharmony_ci            // was not previously in the container, add it
1768bf80f4bSopenharmony_ci            toIndex = children_.size();
1778bf80f4bSopenharmony_ci            children_.push_back(replaceWith);
1788bf80f4bSopenharmony_ci            added = replaceWith;
1798bf80f4bSopenharmony_ci            changed = true;
1808bf80f4bSopenharmony_ci        }
1818bf80f4bSopenharmony_ci    }
1828bf80f4bSopenharmony_ci    if (changed) {
1838bf80f4bSopenharmony_ci        // We did some changes to the container
1848bf80f4bSopenharmony_ci        ChildChangedInfo addedInfo { added, toIndex, parent_ };
1858bf80f4bSopenharmony_ci        ChildChangedInfo removedInfo { removed, toIndex, parent_ };
1868bf80f4bSopenharmony_ci        bool success = true;
1878bf80f4bSopenharmony_ci        // Replace operation does not support
1888bf80f4bSopenharmony_ci        if (removed) {
1898bf80f4bSopenharmony_ci            Invoke<IOnChildChanging>(OnRemoving(), removedInfo, success);
1908bf80f4bSopenharmony_ci            if (!success) {
1918bf80f4bSopenharmony_ci                CORE_LOG_E("Failing a remove transaction during replace operation is not supported");
1928bf80f4bSopenharmony_ci                success = true;
1938bf80f4bSopenharmony_ci            }
1948bf80f4bSopenharmony_ci        }
1958bf80f4bSopenharmony_ci        if (added) {
1968bf80f4bSopenharmony_ci            Invoke<IOnChildChanging>(OnAdding(), addedInfo, success);
1978bf80f4bSopenharmony_ci            if (!success) {
1988bf80f4bSopenharmony_ci                CORE_LOG_E("Failing an add transaction during replace operation is not supported");
1998bf80f4bSopenharmony_ci            }
2008bf80f4bSopenharmony_ci        }
2018bf80f4bSopenharmony_ci        SetObjectParent(removed, nullptr);
2028bf80f4bSopenharmony_ci        SetObjectParent(added, interface_pointer_cast<IObject>(parent_));
2038bf80f4bSopenharmony_ci        if (removed) {
2048bf80f4bSopenharmony_ci            Invoke<IOnChildChanged>(OnRemoved(), removedInfo);
2058bf80f4bSopenharmony_ci        }
2068bf80f4bSopenharmony_ci        if (added) {
2078bf80f4bSopenharmony_ci            Invoke<IOnChildChanged>(OnAdded(), addedInfo);
2088bf80f4bSopenharmony_ci        }
2098bf80f4bSopenharmony_ci        if (moved) {
2108bf80f4bSopenharmony_ci            Invoke<IOnChildMoved>(OnMoved(), ChildMovedInfo { moved, fromIndex, toIndex, parent_ });
2118bf80f4bSopenharmony_ci        }
2128bf80f4bSopenharmony_ci    }
2138bf80f4bSopenharmony_ci    return changed;
2148bf80f4bSopenharmony_ci}
2158bf80f4bSopenharmony_ci
2168bf80f4bSopenharmony_civoid Container::SetObjectParent(const IObject::Ptr& object, const IObject::Ptr& parent) const
2178bf80f4bSopenharmony_ci{
2188bf80f4bSopenharmony_ci    const auto set = interface_cast<IMutableContainable>(object);
2198bf80f4bSopenharmony_ci    if (!set) {
2208bf80f4bSopenharmony_ci        // Object does not support setting a parent
2218bf80f4bSopenharmony_ci        return;
2228bf80f4bSopenharmony_ci    }
2238bf80f4bSopenharmony_ci    if (const auto cont = interface_cast<IContainable>(object)) {
2248bf80f4bSopenharmony_ci        // Remove from old parent (if any)
2258bf80f4bSopenharmony_ci        if (const auto old = interface_pointer_cast<IContainer>(cont->GetParent())) {
2268bf80f4bSopenharmony_ci            if (old == interface_pointer_cast<IContainer>(parent)) {
2278bf80f4bSopenharmony_ci                // The object is already a child of the new parent container
2288bf80f4bSopenharmony_ci                return;
2298bf80f4bSopenharmony_ci            }
2308bf80f4bSopenharmony_ci            old->Remove(object);
2318bf80f4bSopenharmony_ci        }
2328bf80f4bSopenharmony_ci    }
2338bf80f4bSopenharmony_ci    set->SetParent(parent);
2348bf80f4bSopenharmony_ci}
2358bf80f4bSopenharmony_ci
2368bf80f4bSopenharmony_cibool Container::CheckLoop(const IObject::Ptr& object) const
2378bf80f4bSopenharmony_ci{
2388bf80f4bSopenharmony_ci    // Check if adding object to "this" would lead to a loop in the hierarchy.
2398bf80f4bSopenharmony_ci    // This can only happen if object itself is a container which happens to be
2408bf80f4bSopenharmony_ci    // an ancestor of ours.
2418bf80f4bSopenharmony_ci    if (const auto cc = interface_cast<const IContainer>(object)) {
2428bf80f4bSopenharmony_ci        if (const auto me = interface_cast<IObjectInstance>(impl_)) {
2438bf80f4bSopenharmony_ci            if (cc->IsAncestorOf(me->GetSelf())) {
2448bf80f4bSopenharmony_ci                CORE_LOG_E("Adding '%s' to '%s' would lead to a loop in the container", object->GetName().c_str(),
2458bf80f4bSopenharmony_ci                    me->GetName().c_str());
2468bf80f4bSopenharmony_ci                return false;
2478bf80f4bSopenharmony_ci            }
2488bf80f4bSopenharmony_ci        }
2498bf80f4bSopenharmony_ci    }
2508bf80f4bSopenharmony_ci    return true;
2518bf80f4bSopenharmony_ci}
2528bf80f4bSopenharmony_ci
2538bf80f4bSopenharmony_ciMETA_END_NAMESPACE()
254