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_observer.h"
178bf80f4bSopenharmony_ci
188bf80f4bSopenharmony_ci#include <algorithm>
198bf80f4bSopenharmony_ci
208bf80f4bSopenharmony_ci#include <meta/api/make_callback.h>
218bf80f4bSopenharmony_ci#include <meta/base/interface_utils.h>
228bf80f4bSopenharmony_ci#include <meta/interface/intf_containable.h>
238bf80f4bSopenharmony_ci
248bf80f4bSopenharmony_ciMETA_BEGIN_NAMESPACE()
258bf80f4bSopenharmony_ci
268bf80f4bSopenharmony_ci// ContainerChangeListener
278bf80f4bSopenharmony_ci
288bf80f4bSopenharmony_ciContainerChangeListener::ContainerChangeListener(const IContainer::Ptr& container)
298bf80f4bSopenharmony_ci    : added_ { 0, {} }, removed_ { 0, {} }, moved_ { 0, {} }, container_(container)
308bf80f4bSopenharmony_ci{}
318bf80f4bSopenharmony_ci
328bf80f4bSopenharmony_ciContainerChangeListener::~ContainerChangeListener()
338bf80f4bSopenharmony_ci{
348bf80f4bSopenharmony_ci    Unsubscribe();
358bf80f4bSopenharmony_ci}
368bf80f4bSopenharmony_ci
378bf80f4bSopenharmony_ciContainerChangeListener::ContainerChangeListener(ContainerChangeListener&& other) = default;
388bf80f4bSopenharmony_ci
398bf80f4bSopenharmony_ciContainerChangeListener& ContainerChangeListener::operator=(ContainerChangeListener&& other)
408bf80f4bSopenharmony_ci{
418bf80f4bSopenharmony_ci    if (&other == this) {
428bf80f4bSopenharmony_ci        return *this;
438bf80f4bSopenharmony_ci    }
448bf80f4bSopenharmony_ci    Unsubscribe();
458bf80f4bSopenharmony_ci
468bf80f4bSopenharmony_ci    container_ = BASE_NS::move(container_);
478bf80f4bSopenharmony_ci    added_ = BASE_NS::move(added_);
488bf80f4bSopenharmony_ci    removed_ = BASE_NS::move(removed_);
498bf80f4bSopenharmony_ci    moved_ = BASE_NS::move(moved_);
508bf80f4bSopenharmony_ci
518bf80f4bSopenharmony_ci    return *this;
528bf80f4bSopenharmony_ci}
538bf80f4bSopenharmony_ci
548bf80f4bSopenharmony_cibool ContainerChangeListener::operator==(const ContainerChangeListener& other) const noexcept
558bf80f4bSopenharmony_ci{
568bf80f4bSopenharmony_ci    return other.added_.first == added_.first && other.removed_.first == removed_.first &&
578bf80f4bSopenharmony_ci           other.moved_.first == moved_.first;
588bf80f4bSopenharmony_ci}
598bf80f4bSopenharmony_ci
608bf80f4bSopenharmony_cibool ContainerChangeListener::Subscribe(const IOnChildChanged::InterfaceTypePtr& onAdded,
618bf80f4bSopenharmony_ci    const IOnChildChanged::InterfaceTypePtr& onRemoved, const IOnChildMoved::InterfaceTypePtr& onMoved)
628bf80f4bSopenharmony_ci{
638bf80f4bSopenharmony_ci    Unsubscribe();
648bf80f4bSopenharmony_ci    if (const auto container = container_.lock()) {
658bf80f4bSopenharmony_ci        added_ = { container->OnAdded()->AddHandler(onAdded), onAdded };
668bf80f4bSopenharmony_ci        removed_ = { container->OnRemoved()->AddHandler(onRemoved), onRemoved };
678bf80f4bSopenharmony_ci        moved_ = { container->OnMoved()->AddHandler(onMoved), onMoved };
688bf80f4bSopenharmony_ci        return added_.first && removed_.first && moved_.first;
698bf80f4bSopenharmony_ci    }
708bf80f4bSopenharmony_ci    return false;
718bf80f4bSopenharmony_ci}
728bf80f4bSopenharmony_ci
738bf80f4bSopenharmony_civoid ContainerChangeListener::Unsubscribe()
748bf80f4bSopenharmony_ci{
758bf80f4bSopenharmony_ci    if (const auto container = container_.lock()) {
768bf80f4bSopenharmony_ci        if (added_.first) {
778bf80f4bSopenharmony_ci            container->OnAdded()->RemoveHandler(added_.first);
788bf80f4bSopenharmony_ci        }
798bf80f4bSopenharmony_ci        if (removed_.first) {
808bf80f4bSopenharmony_ci            container->OnRemoved()->RemoveHandler(removed_.first);
818bf80f4bSopenharmony_ci        }
828bf80f4bSopenharmony_ci        if (moved_.first) {
838bf80f4bSopenharmony_ci            container->OnMoved()->RemoveHandler(moved_.first);
848bf80f4bSopenharmony_ci        }
858bf80f4bSopenharmony_ci    }
868bf80f4bSopenharmony_ci    added_ = {};
878bf80f4bSopenharmony_ci    removed_ = {};
888bf80f4bSopenharmony_ci    moved_ = {};
898bf80f4bSopenharmony_ci}
908bf80f4bSopenharmony_ci
918bf80f4bSopenharmony_ci// ContainerObserver
928bf80f4bSopenharmony_ci
938bf80f4bSopenharmony_cibool ContainerObserver::Build(const IMetadata::Ptr& p)
948bf80f4bSopenharmony_ci{
958bf80f4bSopenharmony_ci    bool ret = Super::Build(p);
968bf80f4bSopenharmony_ci    if (ret) {
978bf80f4bSopenharmony_ci        addedCallable_ = MakeCallback<IOnChildChanged>(this, &ContainerObserver::InvokeAdded);
988bf80f4bSopenharmony_ci        removedCallable_ = MakeCallback<IOnChildChanged>(this, &ContainerObserver::InvokeRemoved);
998bf80f4bSopenharmony_ci        movedCallable_ = MakeCallback<IOnChildMoved>(this, &ContainerObserver::InvokeMoved);
1008bf80f4bSopenharmony_ci    }
1018bf80f4bSopenharmony_ci    return ret;
1028bf80f4bSopenharmony_ci}
1038bf80f4bSopenharmony_ci
1048bf80f4bSopenharmony_civoid ContainerObserver::SetContainer(const IContainer::Ptr& container)
1058bf80f4bSopenharmony_ci{
1068bf80f4bSopenharmony_ci    subscriptions_.clear();
1078bf80f4bSopenharmony_ci    container_ = container;
1088bf80f4bSopenharmony_ci    Subscribe(container_);
1098bf80f4bSopenharmony_ci}
1108bf80f4bSopenharmony_ci
1118bf80f4bSopenharmony_civoid ContainerObserver::InvokeAdded(const ChildChangedInfo& info)
1128bf80f4bSopenharmony_ci{
1138bf80f4bSopenharmony_ci    META_ACCESS_EVENT(OnDescendantAdded)->Invoke(info);
1148bf80f4bSopenharmony_ci    Subscribe(interface_pointer_cast<IContainer>(info.object));
1158bf80f4bSopenharmony_ci}
1168bf80f4bSopenharmony_ci
1178bf80f4bSopenharmony_civoid ContainerObserver::InvokeRemoved(const ChildChangedInfo& info)
1188bf80f4bSopenharmony_ci{
1198bf80f4bSopenharmony_ci    META_ACCESS_EVENT(OnDescendantRemoved)->Invoke(info);
1208bf80f4bSopenharmony_ci    Unsubscribe(interface_pointer_cast<IContainer>(info.object));
1218bf80f4bSopenharmony_ci}
1228bf80f4bSopenharmony_ci
1238bf80f4bSopenharmony_civoid ContainerObserver::InvokeMoved(const ChildMovedInfo& info)
1248bf80f4bSopenharmony_ci{
1258bf80f4bSopenharmony_ci    META_ACCESS_EVENT(OnDescendantMoved)->Invoke(info);
1268bf80f4bSopenharmony_ci}
1278bf80f4bSopenharmony_ci
1288bf80f4bSopenharmony_civoid ContainerObserver::Subscribe(const IContainer::Ptr& base)
1298bf80f4bSopenharmony_ci{
1308bf80f4bSopenharmony_ci    if (!base) {
1318bf80f4bSopenharmony_ci        return;
1328bf80f4bSopenharmony_ci    }
1338bf80f4bSopenharmony_ci    auto listener = ContainerChangeListener(base);
1348bf80f4bSopenharmony_ci    listener.Subscribe(addedCallable_, removedCallable_, movedCallable_);
1358bf80f4bSopenharmony_ci
1368bf80f4bSopenharmony_ci    subscriptions_.emplace_back(base, BASE_NS::move(listener));
1378bf80f4bSopenharmony_ci
1388bf80f4bSopenharmony_ci    for (const auto& child : base->GetAll<IContainer>()) {
1398bf80f4bSopenharmony_ci        Subscribe(child);
1408bf80f4bSopenharmony_ci    }
1418bf80f4bSopenharmony_ci}
1428bf80f4bSopenharmony_ci
1438bf80f4bSopenharmony_civoid ContainerObserver::Unsubscribe(const IContainer::Ptr& base)
1448bf80f4bSopenharmony_ci{
1458bf80f4bSopenharmony_ci    if (!base) {
1468bf80f4bSopenharmony_ci        return;
1478bf80f4bSopenharmony_ci    }
1488bf80f4bSopenharmony_ci    auto it = subscriptions_.begin();
1498bf80f4bSopenharmony_ci    while (it != subscriptions_.end()) {
1508bf80f4bSopenharmony_ci        const auto& sub = *it;
1518bf80f4bSopenharmony_ci        if (const auto c = sub.container.lock()) {
1528bf80f4bSopenharmony_ci            const auto object = interface_pointer_cast<const IObject>(c);
1538bf80f4bSopenharmony_ci            if (base == c || base->IsAncestorOf(object)) {
1548bf80f4bSopenharmony_ci                it = subscriptions_.erase(it);
1558bf80f4bSopenharmony_ci                continue;
1568bf80f4bSopenharmony_ci            }
1578bf80f4bSopenharmony_ci        }
1588bf80f4bSopenharmony_ci        ++it;
1598bf80f4bSopenharmony_ci    }
1608bf80f4bSopenharmony_ci}
1618bf80f4bSopenharmony_ci
1628bf80f4bSopenharmony_ciMETA_END_NAMESPACE()
163