// Copyright 2018 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 "lib/component/cpp/testing/enclosing_environment.h"

#include <fuchsia/sys/cpp/fidl.h>
#include "lib/component/cpp/testing/test_util.h"
#include "lib/fidl/cpp/clone.h"
#include "lib/fxl/logging.h"

namespace component {
namespace testing {

EnvironmentServices::EnvironmentServices(
    const fuchsia::sys::EnvironmentPtr& parent_env,
    const fbl::RefPtr<fs::Service>& loader_service,
    async_dispatcher_t* dispatcher)
    : vfs_(std::make_unique<fs::SynchronousVfs>(
          dispatcher == nullptr ? async_get_default_dispatcher() : dispatcher)),
      svc_(fbl::AdoptRef(new fs::PseudoDir())) {
  parent_env->GetServices(parent_svc_.NewRequest());
  if (loader_service) {
    AddService(loader_service, fuchsia::sys::Loader::Name_);
  } else {
    AllowParentService(fuchsia::sys::Loader::Name_);
  }
}

// static
std::unique_ptr<EnvironmentServices> EnvironmentServices::Create(
    const fuchsia::sys::EnvironmentPtr& parent_env,
    async_dispatcher_t* dispatcher) {
  return std::unique_ptr<EnvironmentServices>(
      new EnvironmentServices(parent_env, nullptr, dispatcher));
}

// static
std::unique_ptr<EnvironmentServices>
EnvironmentServices::CreateWithCustomLoader(
    const fuchsia::sys::EnvironmentPtr& parent_env,
    const fbl::RefPtr<fs::Service>& loader_service,
    async_dispatcher_t* dispatcher) {
  return std::unique_ptr<EnvironmentServices>(
      new EnvironmentServices(parent_env, loader_service, dispatcher));
}

zx_status_t EnvironmentServices::AddService(
    const fbl::RefPtr<fs::Service> service, const std::string& service_name) {
  svc_names_.push_back(service_name);
  return svc_->AddEntry(service_name.c_str(), service);
}

zx_status_t EnvironmentServices::AddServiceWithLaunchInfo(
    fuchsia::sys::LaunchInfo launch_info, const std::string& service_name) {
  return AddServiceWithLaunchInfo(
      launch_info.url,
      [launch_info = std::move(launch_info)]() {
        // clone only URL and Arguments
        fuchsia::sys::LaunchInfo dup_launch_info;
        fidl::Clone(launch_info.url, &dup_launch_info.url);
        fidl::Clone(launch_info.arguments, &dup_launch_info.arguments);
        return dup_launch_info;
      },
      service_name);
}

zx_status_t EnvironmentServices::AddServiceWithLaunchInfo(
    std::string singleton_id, fit::function<fuchsia::sys::LaunchInfo()> handler,
    const std::string& service_name) {
  auto child = fbl::AdoptRef(
      new fs::Service([this, service_name, handler = std::move(handler),
                       singleton_id = std::move(singleton_id),
                       controller = fuchsia::sys::ComponentControllerPtr()](
                          zx::channel client_handle) mutable {
        auto it = singleton_services_.find(singleton_id);
        if (it == singleton_services_.end()) {
          component::Services services;

          fuchsia::sys::LaunchInfo launch_info = handler();
          launch_info.directory_request = services.NewRequest();

          enclosing_env_->CreateComponent(std::move(launch_info),
                                          controller.NewRequest());
          controller.set_error_handler(
              [this, singleton_id, &controller](zx_status_t status) {
                // TODO: show error? where on stderr?
                controller.Unbind();  // kills the singleton application
                singleton_services_.erase(singleton_id);
              });

          std::tie(it, std::ignore) =
              singleton_services_.emplace(singleton_id, std::move(services));
        }

        it->second.ConnectToService(std::move(client_handle), service_name);
        return ZX_OK;
      }));
  svc_names_.push_back(service_name);
  return svc_->AddEntry(service_name, std::move(child));
}

zx_status_t EnvironmentServices::AllowParentService(
    const std::string& service_name) {
  svc_names_.push_back(service_name);
  return svc_->AddEntry(
      service_name.c_str(),
      fbl::AdoptRef(new fs::Service([this, service_name](zx::channel channel) {
        parent_svc_->ConnectToService(service_name, std::move(channel));
        return ZX_OK;
      })));
}

EnclosingEnvironment::EnclosingEnvironment(
    const std::string& label, const fuchsia::sys::EnvironmentPtr& parent_env,
    std::unique_ptr<EnvironmentServices> services,
    const fuchsia::sys::EnvironmentOptions& options)
    : label_(label), services_(std::move(services)) {
  services_->set_enclosing_env(this);

  // Start environment with services.
  fuchsia::sys::ServiceListPtr service_list(new fuchsia::sys::ServiceList);
  service_list->names = std::move(services_->svc_names_);
  service_list->host_directory =
      OpenAsDirectory(services_->vfs_.get(), services_->svc_);
  fuchsia::sys::EnvironmentPtr env;

  parent_env->CreateNestedEnvironment(env.NewRequest(),
                                      env_controller_.NewRequest(), label_,
                                      std::move(service_list), options);
  env_controller_.set_error_handler(
      [this](zx_status_t status) { SetRunning(false); });
  // Connect to launcher
  env->GetLauncher(launcher_.NewRequest());

  // Connect to service
  env->GetServices(service_provider_.NewRequest());

  env_controller_.events().OnCreated = [this]() { SetRunning(true); };
}

// static
std::unique_ptr<EnclosingEnvironment> EnclosingEnvironment::Create(
    const std::string& label, const fuchsia::sys::EnvironmentPtr& parent_env,
    std::unique_ptr<EnvironmentServices> services,
    const fuchsia::sys::EnvironmentOptions& options) {
  auto* env =
      new EnclosingEnvironment(label, parent_env, std::move(services), options);
  return std::unique_ptr<EnclosingEnvironment>(env);
}

EnclosingEnvironment::~EnclosingEnvironment() {
  auto channel = env_controller_.Unbind();
  if (channel) {
    fuchsia::sys::EnvironmentControllerSyncPtr controller;
    controller.Bind(std::move(channel));
    controller->Kill();
  }
}

void EnclosingEnvironment::Kill(std::function<void()> callback) {
  env_controller_->Kill([this, callback = std::move(callback)]() {
    if (callback) {
      callback();
    }
  });
}

std::unique_ptr<EnclosingEnvironment>
EnclosingEnvironment::CreateNestedEnclosingEnvironment(
    const std::string& label) {
  fuchsia::sys::EnvironmentPtr env;
  service_provider_->ConnectToService(fuchsia::sys::Environment::Name_,
                                      env.NewRequest().TakeChannel());
  return Create(label, env, EnvironmentServices::Create(env));
}

void EnclosingEnvironment::CreateComponent(
    fuchsia::sys::LaunchInfo launch_info,
    fidl::InterfaceRequest<fuchsia::sys::ComponentController> request) {
  launcher_.CreateComponent(std::move(launch_info), std::move(request));
}

fuchsia::sys::ComponentControllerPtr EnclosingEnvironment::CreateComponent(
    fuchsia::sys::LaunchInfo launch_info) {
  fuchsia::sys::ComponentControllerPtr controller;
  CreateComponent(std::move(launch_info), controller.NewRequest());
  return controller;
}

fuchsia::sys::ComponentControllerPtr
EnclosingEnvironment::CreateComponentFromUrl(std::string component_url) {
  fuchsia::sys::LaunchInfo launch_info;
  launch_info.url = component_url;

  return CreateComponent(std::move(launch_info));
}

void EnclosingEnvironment::SetRunning(bool running) {
  if (running_ != running) {
    running_ = running;
    if (running_changed_callback_) {
      running_changed_callback_(running_);
    }
  }
}

}  // namespace testing
}  // namespace component
