// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "peridot/bin/context_engine/debug.h"

#include <lib/fidl/cpp/clone.h>
#include <lib/fidl/cpp/optional.h>

#include "peridot/bin/context_engine/context_repository.h"

namespace modular {

ContextDebugImpl::ContextDebugImpl(const ContextRepository* const repository)
    : repository_(repository), weak_ptr_factory_(this) {}
ContextDebugImpl::~ContextDebugImpl() = default;

fxl::WeakPtr<ContextDebugImpl> ContextDebugImpl::GetWeakPtr() {
  return weak_ptr_factory_.GetWeakPtr();
}

void ContextDebugImpl::OnValueChanged(const std::set<Id>& parent_ids, const Id& id,
                                      const fuchsia::modular::ContextValue& value) {
  fuchsia::modular::ContextDebugValue update;
  update.parent_ids.resize(0);
  for (const auto& it : parent_ids) {
    update.parent_ids.push_back(it);
  }
  update.id = id;
  fuchsia::modular::ContextValue value_clone;
  fidl::Clone(value, &value_clone);
  update.value = fidl::MakeOptional(std::move(value_clone));
  DispatchOneValue(std::move(update));
}

void ContextDebugImpl::OnValueRemoved(const Id& id) {
  fuchsia::modular::ContextDebugValue update;
  update.id = id;
  update.parent_ids.resize(0);
  DispatchOneValue(std::move(update));
}

void ContextDebugImpl::OnSubscriptionAdded(
    const Id& id, const fuchsia::modular::ContextQuery& query,
    const fuchsia::modular::SubscriptionDebugInfo& debug_info) {
  fuchsia::modular::ContextDebugSubscription update;
  update.id = id;
  fuchsia::modular::ContextQuery query_clone;
  fidl::Clone(query, &query_clone);
  update.query = fidl::MakeOptional(std::move(query_clone));
  fuchsia::modular::SubscriptionDebugInfo debug_info_clone;
  fidl::Clone(debug_info, &debug_info_clone);
  update.debug_info = fidl::MakeOptional(std::move(debug_info_clone));
  DispatchOneSubscription(std::move(update));
}

void ContextDebugImpl::OnSubscriptionRemoved(const Id& id) {
  fuchsia::modular::ContextDebugSubscription update;
  update.id = id;
  DispatchOneSubscription(std::move(update));
}

util::IdleWaiter* ContextDebugImpl::GetIdleWaiter() { return &idle_waiter_; }

void ContextDebugImpl::Watch(
    fidl::InterfaceHandle<fuchsia::modular::ContextDebugListener> listener) {
  FXL_LOG(INFO) << "Watch(): entered";
  auto listener_ptr = listener.Bind();
  // Build a complete state snapshot and send it to |listener|.
  std::vector<fuchsia::modular::ContextDebugValue> all_values;
  for (const auto& entry : repository_->values_) {
    fuchsia::modular::ContextDebugValue update;
    update.id = entry.first;
    fuchsia::modular::ContextValue value_clone;
    fidl::Clone(entry.second.value, &value_clone);
    update.value = fidl::MakeOptional(std::move(value_clone));
    update.parent_ids.resize(0);
    for (const auto& it : repository_->graph_.GetParents(entry.first)) {
      update.parent_ids.push_back(it);
    }
    all_values.push_back(std::move(update));
  }
  listener_ptr->OnValuesChanged(std::move(all_values));
  // TODO(thatguy): Add subscriptions.

  listeners_.AddInterfacePtr(std::move(listener_ptr));
}

void ContextDebugImpl::WaitUntilIdle(WaitUntilIdleCallback callback) {
  idle_waiter_.WaitUntilIdle(std::move(callback));
}

void ContextDebugImpl::DispatchOneValue(fuchsia::modular::ContextDebugValue value) {
  std::vector<fuchsia::modular::ContextDebugValue> values;
  values.push_back(std::move(value));
  DispatchValues(std::move(values));
}

void ContextDebugImpl::DispatchValues(fidl::VectorPtr<fuchsia::modular::ContextDebugValue> values) {
  FXL_DCHECK(values.has_value());
  for (const auto& listener : listeners_.ptrs()) {
    std::vector<fuchsia::modular::ContextDebugValue> values_clone;
    fidl::Clone(values.value(), &values_clone);
    (*listener)->OnValuesChanged(std::move(values_clone));
  }
}

void ContextDebugImpl::DispatchOneSubscription(fuchsia::modular::ContextDebugSubscription value) {
  std::vector<fuchsia::modular::ContextDebugSubscription> values;
  values.push_back(std::move(value));
  DispatchSubscriptions(std::move(values));
}

void ContextDebugImpl::DispatchSubscriptions(
    fidl::VectorPtr<fuchsia::modular::ContextDebugSubscription> subscriptions) {
  FXL_DCHECK(subscriptions.has_value());
  for (const auto& listener : listeners_.ptrs()) {
    std::vector<fuchsia::modular::ContextDebugSubscription> subscriptions_clone;
    fidl::Clone(subscriptions.value(), &subscriptions_clone);
    (*listener)->OnSubscriptionsChanged(std::move(subscriptions_clone));
  }
}

}  // namespace modular
