// 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 "managed_environment.h"

#include <fuchsia/logger/cpp/fidl.h>
#include <src/lib/fxl/strings/string_printf.h>

#include <random>

namespace netemul {

// Start the Log and LogSink service (the same component publishses both
// services))
static const char* kLogSinkServiceURL =
    "fuchsia-pkg://fuchsia.com/logger#meta/logger.cmx";
static const char* kLogServiceURL =
    "fuchsia-pkg://fuchsia.com/logger#meta/logger.cmx";

using sys::testing::EnclosingEnvironment;
using sys::testing::EnvironmentServices;

ManagedEnvironment::Ptr ManagedEnvironment::CreateRoot(
    const fuchsia::sys::EnvironmentPtr& parent,
    const SandboxEnv::Ptr& sandbox_env, Options options) {
  auto ret = ManagedEnvironment::Ptr(new ManagedEnvironment(sandbox_env));
  ret->Create(parent, std::move(options));
  return ret;
}

ManagedEnvironment::ManagedEnvironment(const SandboxEnv::Ptr& sandbox_env)
    : sandbox_env_(sandbox_env), ready_(false) {}

sys::testing::EnclosingEnvironment& ManagedEnvironment::environment() {
  return *env_;
}

void ManagedEnvironment::GetLauncher(
    ::fidl::InterfaceRequest<::fuchsia::sys::Launcher> launcher) {
  launcher_->Bind(std::move(launcher));
}

void ManagedEnvironment::CreateChildEnvironment(
    fidl::InterfaceRequest<FManagedEnvironment> me, Options options) {
  ManagedEnvironment::Ptr np(new ManagedEnvironment(sandbox_env_));
  fuchsia::sys::EnvironmentPtr env;
  env_->ConnectToService(env.NewRequest());
  np->Create(env, std::move(options), this);
  np->bindings_.AddBinding(np.get(), std::move(me));

  children_.emplace_back(std::move(np));
}

void ManagedEnvironment::Create(const fuchsia::sys::EnvironmentPtr& parent,
                                ManagedEnvironment::Options options,
                                const ManagedEnvironment* managed_parent) {
  auto services = EnvironmentServices::Create(parent);

  // Nested environments without a name are not allowed, if empty name is
  // provided, replace it with a default *randomized* value.
  // Randomness there is necessary due to appmgr rules for environments with
  // same name.
  if (!options.has_name() || options.name().empty()) {
    std::random_device rnd;
    options.set_name(fxl::StringPrintf("netemul-env-%08x", rnd()));
  }

  loggers_ = std::make_unique<ManagedLoggerCollection>(options.name());

  // add network context service:
  services->AddService(sandbox_env_->network_context().GetHandler());

  // add Bus service:
  services->AddService(sandbox_env_->sync_manager().GetHandler());

  // add managed environment itself as a handler
  services->AddService(bindings_.GetHandler(this));

  // Inject LogSink service
  services->AddServiceWithLaunchInfo(
      kLogSinkServiceURL,
      [this]() {
        fuchsia::sys::LaunchInfo linfo;
        linfo.url = kLogSinkServiceURL;
        linfo.out = loggers_->CreateLogger(kLogSinkServiceURL, false);
        linfo.err = loggers_->CreateLogger(kLogSinkServiceURL, true);
        loggers_->IncrementCounter();
        return linfo;
      },
      fuchsia::logger::LogSink::Name_);

  // Inject Log service
  services->AddServiceWithLaunchInfo(
      kLogServiceURL,
      [this]() {
        fuchsia::sys::LaunchInfo linfo;
        linfo.url = kLogServiceURL;
        linfo.out = loggers_->CreateLogger(kLogServiceURL, false);
        linfo.err = loggers_->CreateLogger(kLogServiceURL, true);
        loggers_->IncrementCounter();
        return linfo;
      },
      fuchsia::logger::Log::Name_);

  // prepare service configurations:
  service_config_.clear();
  if (options.has_inherit_parent_launch_services() &&
      options.inherit_parent_launch_services() && managed_parent != nullptr) {
    for (const auto& a : managed_parent->service_config_) {
      LaunchService clone;
      a.Clone(&clone);
      service_config_.push_back(std::move(clone));
    }
  }

  if (options.has_services()) {
    std::move(options.mutable_services()->begin(),
              options.mutable_services()->end(),
              std::back_inserter(service_config_));
  }

  // push all the allowable launch services:
  for (const auto& svc : service_config_) {
    LaunchService copy;
    ZX_ASSERT(svc.Clone(&copy) == ZX_OK);
    services->AddServiceWithLaunchInfo(
        svc.url,
        [this, svc = std::move(copy)]() {
          fuchsia::sys::LaunchInfo linfo;
          linfo.url = svc.url;
          linfo.arguments->insert(linfo.arguments->begin(),
                                  svc.arguments->begin(), svc.arguments->end());
          linfo.out = loggers_->CreateLogger(svc.url, false);
          linfo.err = loggers_->CreateLogger(svc.url, true);
          loggers_->IncrementCounter();
          return linfo;
        },
        svc.name);
  }

  if (options.has_devices()) {
    // save all handles for virtual devices
    for (auto& dev : *options.mutable_devices()) {
      virtual_devices_.AddEntry(dev.path, dev.device.Bind());
    }
  }

  fuchsia::sys::EnvironmentOptions sub_options = {
      .kill_on_oom = true,
      .allow_parent_runners = false,
      .inherit_parent_services = false};

  env_ = EnclosingEnvironment::Create(options.name(), parent,
                                      std::move(services), sub_options);

  env_->SetRunningChangedCallback([this](bool running) {
    ready_ = true;
    if (running) {
      for (auto& r : pending_requests_) {
        Bind(std::move(r));
      }
      pending_requests_.clear();
      if (running_callback_) {
        running_callback_();
      }
    } else {
      FXL_LOG(ERROR) << "Underlying enclosed Environment stopped running";
      running_callback_ = nullptr;
      children_.clear();
      pending_requests_.clear();
      env_ = nullptr;
      launcher_ = nullptr;
      bindings_.CloseAll();
    }
  });

  launcher_ = std::make_unique<ManagedLauncher>(this);

  // Start LogListener for this environment
  log_listener_ =
      LogListener::Create(this, options.logger_options(), options.name(), NULL);
}

zx::channel ManagedEnvironment::OpenVdevDirectory() {
  return virtual_devices_.OpenAsDirectory();
}

zx::channel ManagedEnvironment::OpenVdataDirectory() {
  if (!virtual_data_) {
    virtual_data_ = std::make_unique<VirtualData>();
  }
  return virtual_data_->GetDirectory();
}

void ManagedEnvironment::Bind(
    fidl::InterfaceRequest<ManagedEnvironment::FManagedEnvironment> req) {
  if (ready_) {
    bindings_.AddBinding(this, std::move(req));
  } else if (env_) {
    pending_requests_.push_back(std::move(req));
  } else {
    req.Close(ZX_ERR_INTERNAL);
  }
}

ManagedLoggerCollection& ManagedEnvironment::loggers() {
  ZX_ASSERT(loggers_);
  return *loggers_;
}

void ManagedEnvironment::ConnectToService(std::string name, zx::channel req) {
  env_->ConnectToService(name, std::move(req));
}

void ManagedEnvironment::AddDevice(
    fuchsia::netemul::environment::VirtualDevice device) {
  virtual_devices_.AddEntry(device.path, device.device.Bind());
}

void ManagedEnvironment::RemoveDevice(::std::string path) {
  virtual_devices_.RemoveEntry(path);
}

}  // namespace netemul
