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#include "attachment_container.h"
168bf80f4bSopenharmony_ci
178bf80f4bSopenharmony_ci#include <meta/api/make_callback.h>
188bf80f4bSopenharmony_ci#include <meta/api/util.h>
198bf80f4bSopenharmony_ci
208bf80f4bSopenharmony_ciMETA_BEGIN_NAMESPACE()
218bf80f4bSopenharmony_ci
228bf80f4bSopenharmony_ciAttachmentContainer::AttachmentContainer() = default;
238bf80f4bSopenharmony_ci
248bf80f4bSopenharmony_ciAttachmentContainer::~AttachmentContainer()
258bf80f4bSopenharmony_ci{
268bf80f4bSopenharmony_ci    RemoveAllAttachments();
278bf80f4bSopenharmony_ci}
288bf80f4bSopenharmony_ci
298bf80f4bSopenharmony_civoid AttachmentContainer::SetSuperInstance(const IObject::Ptr& aggr, const IObject::Ptr& super)
308bf80f4bSopenharmony_ci{
318bf80f4bSopenharmony_ci    Super::SetSuperInstance(aggr, super);
328bf80f4bSopenharmony_ci    transaction_ = interface_cast<IContainerPreTransaction>(super);
338bf80f4bSopenharmony_ci    CORE_ASSERT(transaction_);
348bf80f4bSopenharmony_ci}
358bf80f4bSopenharmony_ci
368bf80f4bSopenharmony_cibool AttachmentContainer::Build(const IMetadata::Ptr& data)
378bf80f4bSopenharmony_ci{
388bf80f4bSopenharmony_ci    // Always set null as the parent of all our attachments
398bf80f4bSopenharmony_ci    ObjectContainerFwd::SetProxyParent({});
408bf80f4bSopenharmony_ci
418bf80f4bSopenharmony_ci    OnRemoved()->AddHandler(MakeCallback<IOnChildChanged>(this, &AttachmentContainer::RemovedFromContainer));
428bf80f4bSopenharmony_ci    OnAdding()->AddHandler(MakeCallback<IOnChildChanging>(this, &AttachmentContainer::AddingToContainer));
438bf80f4bSopenharmony_ci    return true;
448bf80f4bSopenharmony_ci}
458bf80f4bSopenharmony_ci
468bf80f4bSopenharmony_cibool AttachmentContainer::Add(const IObject::Ptr& object)
478bf80f4bSopenharmony_ci{
488bf80f4bSopenharmony_ci    return Attach(N_POS, object, {});
498bf80f4bSopenharmony_ci}
508bf80f4bSopenharmony_ci
518bf80f4bSopenharmony_cibool AttachmentContainer::Insert(IContainer::SizeType index, const IObject::Ptr& object)
528bf80f4bSopenharmony_ci{
538bf80f4bSopenharmony_ci    return Attach(index, object, {});
548bf80f4bSopenharmony_ci}
558bf80f4bSopenharmony_ci
568bf80f4bSopenharmony_cibool AttachmentContainer::Remove(IContainer::SizeType index)
578bf80f4bSopenharmony_ci{
588bf80f4bSopenharmony_ci    return Remove(GetAt(index));
598bf80f4bSopenharmony_ci}
608bf80f4bSopenharmony_ci
618bf80f4bSopenharmony_cibool AttachmentContainer::Remove(const IObject::Ptr& child)
628bf80f4bSopenharmony_ci{
638bf80f4bSopenharmony_ci    return Detach(child);
648bf80f4bSopenharmony_ci}
658bf80f4bSopenharmony_ci
668bf80f4bSopenharmony_cibool AttachmentContainer::Replace(const IObject::Ptr& child, const IObject::Ptr& replaceWith, bool addAlways)
678bf80f4bSopenharmony_ci{
688bf80f4bSopenharmony_ci    const auto owner = owner_.lock();
698bf80f4bSopenharmony_ci    if (child && AlreadyAttached(replaceWith)) {
708bf80f4bSopenharmony_ci        return true;
718bf80f4bSopenharmony_ci    }
728bf80f4bSopenharmony_ci    return ObjectContainerFwd::Replace(child, replaceWith, addAlways);
738bf80f4bSopenharmony_ci}
748bf80f4bSopenharmony_ci
758bf80f4bSopenharmony_civoid AttachmentContainer::RemoveAll()
768bf80f4bSopenharmony_ci{
778bf80f4bSopenharmony_ci    RemoveAllAttachments();
788bf80f4bSopenharmony_ci}
798bf80f4bSopenharmony_ci
808bf80f4bSopenharmony_cibool AttachmentContainer::SetRequiredInterfaces(const BASE_NS::vector<TypeId>& interfaces)
818bf80f4bSopenharmony_ci{
828bf80f4bSopenharmony_ci    CORE_LOG_E("Setting the required interfaces of an attachment container is not allowed.");
838bf80f4bSopenharmony_ci    return false;
848bf80f4bSopenharmony_ci}
858bf80f4bSopenharmony_ci
868bf80f4bSopenharmony_cibool AttachmentContainer::Initialize(const META_NS::IAttach::Ptr& owner)
878bf80f4bSopenharmony_ci{
888bf80f4bSopenharmony_ci    if (!owner) {
898bf80f4bSopenharmony_ci        return false;
908bf80f4bSopenharmony_ci    }
918bf80f4bSopenharmony_ci    owner_ = owner;
928bf80f4bSopenharmony_ci    return true;
938bf80f4bSopenharmony_ci}
948bf80f4bSopenharmony_ci
958bf80f4bSopenharmony_cibool AttachmentContainer::Attach(const IObject::Ptr& attachment, const IObject::Ptr& dataContext)
968bf80f4bSopenharmony_ci{
978bf80f4bSopenharmony_ci    return Attach(N_POS, attachment, dataContext);
988bf80f4bSopenharmony_ci}
998bf80f4bSopenharmony_ci
1008bf80f4bSopenharmony_cibool AttachmentContainer::Attach(
1018bf80f4bSopenharmony_ci    IContainer::SizeType pos, const IObject::Ptr& attachment, const IObject::Ptr& dataContext)
1028bf80f4bSopenharmony_ci{
1038bf80f4bSopenharmony_ci    const auto object = interface_pointer_cast<IObject>(attachment);
1048bf80f4bSopenharmony_ci    if (!object) {
1058bf80f4bSopenharmony_ci        return false;
1068bf80f4bSopenharmony_ci    }
1078bf80f4bSopenharmony_ci    bool result = false;
1088bf80f4bSopenharmony_ci    if (const auto owner = owner_.lock()) {
1098bf80f4bSopenharmony_ci        // If attachment is attached to something, detach it
1108bf80f4bSopenharmony_ci        if (const auto att = interface_cast<IAttachment>(attachment)) {
1118bf80f4bSopenharmony_ci            if (const auto current = GetValue(att->AttachedTo()).lock()) {
1128bf80f4bSopenharmony_ci                if (current == owner) {
1138bf80f4bSopenharmony_ci                    // Already attached to this
1148bf80f4bSopenharmony_ci                    return true;
1158bf80f4bSopenharmony_ci                }
1168bf80f4bSopenharmony_ci                if (!current->Detach(attachment)) {
1178bf80f4bSopenharmony_ci                    return false;
1188bf80f4bSopenharmony_ci                }
1198bf80f4bSopenharmony_ci            }
1208bf80f4bSopenharmony_ci        }
1218bf80f4bSopenharmony_ci        // If no data context given, use this as the data context
1228bf80f4bSopenharmony_ci        const auto context = dataContext ? dataContext : interface_pointer_cast<IObject>(owner);
1238bf80f4bSopenharmony_ci        addingContexts_.emplace_back(BASE_NS::pair<IObject*, IObject::WeakPtr> { attachment.get(), context });
1248bf80f4bSopenharmony_ci        result = ObjectContainerFwd::Insert(pos, object);
1258bf80f4bSopenharmony_ci        if (!result) {
1268bf80f4bSopenharmony_ci            addingContexts_.pop_back();
1278bf80f4bSopenharmony_ci        }
1288bf80f4bSopenharmony_ci    }
1298bf80f4bSopenharmony_ci    return result;
1308bf80f4bSopenharmony_ci}
1318bf80f4bSopenharmony_ci
1328bf80f4bSopenharmony_cibool AttachmentContainer::Detach(const IObject::Ptr& attachment)
1338bf80f4bSopenharmony_ci{
1348bf80f4bSopenharmony_ci    if (!attachment) {
1358bf80f4bSopenharmony_ci        return false;
1368bf80f4bSopenharmony_ci    }
1378bf80f4bSopenharmony_ci    if (const auto owner = owner_.lock()) {
1388bf80f4bSopenharmony_ci        if (const auto att = interface_cast<IAttachment>(attachment)) {
1398bf80f4bSopenharmony_ci            const auto current = GetValue(att->AttachedTo()).lock();
1408bf80f4bSopenharmony_ci            if (current != owner) {
1418bf80f4bSopenharmony_ci                return false;
1428bf80f4bSopenharmony_ci            }
1438bf80f4bSopenharmony_ci        }
1448bf80f4bSopenharmony_ci        return ObjectContainerFwd::Remove(attachment);
1458bf80f4bSopenharmony_ci    }
1468bf80f4bSopenharmony_ci    return false;
1478bf80f4bSopenharmony_ci}
1488bf80f4bSopenharmony_ci
1498bf80f4bSopenharmony_civoid AttachmentContainer::AddingToContainer(const ChildChangedInfo& info, bool& success)
1508bf80f4bSopenharmony_ci{
1518bf80f4bSopenharmony_ci    if (const auto owner = owner_.lock()) {
1528bf80f4bSopenharmony_ci        if (auto object = info.object) {
1538bf80f4bSopenharmony_ci            IObject::Ptr context;
1548bf80f4bSopenharmony_ci            for (auto it = addingContexts_.begin(); it != addingContexts_.end(); it++) {
1558bf80f4bSopenharmony_ci                if (it->first == object.get()) {
1568bf80f4bSopenharmony_ci                    context = it->second.lock();
1578bf80f4bSopenharmony_ci                    addingContexts_.erase(it);
1588bf80f4bSopenharmony_ci                    break;
1598bf80f4bSopenharmony_ci                }
1608bf80f4bSopenharmony_ci            }
1618bf80f4bSopenharmony_ci            if (auto attachment = interface_pointer_cast<IAttachment>(info.object)) {
1628bf80f4bSopenharmony_ci                if (GetValue(attachment->AttachedTo()).lock() == owner) {
1638bf80f4bSopenharmony_ci                    // Already attached to this
1648bf80f4bSopenharmony_ci                    return;
1658bf80f4bSopenharmony_ci                }
1668bf80f4bSopenharmony_ci                if (!attachment->Attaching(owner, context)) {
1678bf80f4bSopenharmony_ci                    success = false;
1688bf80f4bSopenharmony_ci                }
1698bf80f4bSopenharmony_ci            } else {
1708bf80f4bSopenharmony_ci                success = true;
1718bf80f4bSopenharmony_ci            }
1728bf80f4bSopenharmony_ci        }
1738bf80f4bSopenharmony_ci    }
1748bf80f4bSopenharmony_ci}
1758bf80f4bSopenharmony_civoid AttachmentContainer::RemovedFromContainer(const ChildChangedInfo& info)
1768bf80f4bSopenharmony_ci{
1778bf80f4bSopenharmony_ci    if (const auto owner = owner_.lock()) {
1788bf80f4bSopenharmony_ci        if (auto attachment = interface_pointer_cast<IAttachment>(info.object)) {
1798bf80f4bSopenharmony_ci            attachment->Detaching(owner);
1808bf80f4bSopenharmony_ci        }
1818bf80f4bSopenharmony_ci    }
1828bf80f4bSopenharmony_ci}
1838bf80f4bSopenharmony_ci
1848bf80f4bSopenharmony_ciBASE_NS::vector<IObject::Ptr> AttachmentContainer::GetAttachments(const BASE_NS::vector<TypeId>& uids, bool strict)
1858bf80f4bSopenharmony_ci{
1868bf80f4bSopenharmony_ci    return ObjectContainerFwd::FindAll({ "", TraversalType::NO_HIERARCHY, uids, strict });
1878bf80f4bSopenharmony_ci}
1888bf80f4bSopenharmony_ci
1898bf80f4bSopenharmony_civoid AttachmentContainer::RemoveAllAttachments()
1908bf80f4bSopenharmony_ci{
1918bf80f4bSopenharmony_ci    const auto owner = owner_.lock();
1928bf80f4bSopenharmony_ci    const auto all = ObjectContainerFwd::GetAll();
1938bf80f4bSopenharmony_ci    for (const auto& object : all) {
1948bf80f4bSopenharmony_ci        if (auto att = interface_cast<IAttachment>(object)) {
1958bf80f4bSopenharmony_ci            // Ignore result
1968bf80f4bSopenharmony_ci            att->Detaching(owner);
1978bf80f4bSopenharmony_ci        }
1988bf80f4bSopenharmony_ci    }
1998bf80f4bSopenharmony_ci    ObjectContainerFwd::RemoveAll();
2008bf80f4bSopenharmony_ci}
2018bf80f4bSopenharmony_ci
2028bf80f4bSopenharmony_ciIObject::Ptr AttachmentContainer::FindByName(const BASE_NS::string& name) const
2038bf80f4bSopenharmony_ci{
2048bf80f4bSopenharmony_ci    return ObjectContainerFwd::FindByName(name);
2058bf80f4bSopenharmony_ci}
2068bf80f4bSopenharmony_ci
2078bf80f4bSopenharmony_cibool AttachmentContainer::AlreadyAttached(const IObject::Ptr& object)
2088bf80f4bSopenharmony_ci{
2098bf80f4bSopenharmony_ci    if (const auto attachment = interface_pointer_cast<IAttachment>(object)) {
2108bf80f4bSopenharmony_ci        if (const auto owner = owner_.lock(); attachment && owner) {
2118bf80f4bSopenharmony_ci            if (const auto current = GetValue(attachment->AttachedTo()).lock()) {
2128bf80f4bSopenharmony_ci                if (current == owner) {
2138bf80f4bSopenharmony_ci                    // Already attached to this
2148bf80f4bSopenharmony_ci                    return true;
2158bf80f4bSopenharmony_ci                }
2168bf80f4bSopenharmony_ci            }
2178bf80f4bSopenharmony_ci        }
2188bf80f4bSopenharmony_ci    } else {
2198bf80f4bSopenharmony_ci        return META_NS::ContainsObject(GetSelf<IContainer>(), object);
2208bf80f4bSopenharmony_ci    }
2218bf80f4bSopenharmony_ci    return false;
2228bf80f4bSopenharmony_ci}
2238bf80f4bSopenharmony_ci
2248bf80f4bSopenharmony_ciMETA_END_NAMESPACE()
225