// 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 "src/virtualization/bin/guest_manager/realm_impl.h"

#include <fuchsia/sys/cpp/fidl.h>
#include <lib/fit/function.h>
#include <lib/syslog/cpp/macros.h>

#include "src/virtualization/bin/guest_manager/guest_services.h"

RealmImpl::RealmImpl(uint32_t id, const std::string& label, sys::ComponentContext* context,
                     fidl::InterfaceRequest<fuchsia::virtualization::Realm> request)
    : id_(id),
      label_(label),
      host_vsock_endpoint_(fit::bind_member(this, &RealmImpl::GetAcceptor)) {
  // Create environment.
  fuchsia::sys::EnvironmentPtr environment;
  context->svc()->Connect(environment.NewRequest());
  environment->CreateNestedEnvironment(env_.NewRequest(), env_controller_.NewRequest(), label,
                                       /*additional_services=*/nullptr,
                                       {.inherit_parent_services = true});
  env_->GetLauncher(launcher_.NewRequest());
  zx::channel h1, h2;
  FX_CHECK(zx::channel::create(0, &h1, &h2) == ZX_OK);
  environment->GetDirectory(std::move(h1));

  AddBinding(std::move(request));
}

void RealmImpl::set_unbound_handler(fit::function<void()> handler) {
  bindings_.set_empty_set_handler(std::move(handler));
}

void RealmImpl::AddBinding(fidl::InterfaceRequest<Realm> request) {
  bindings_.AddBinding(this, std::move(request));
}

void RealmImpl::LaunchInstance(std::string url, fidl::StringPtr label,
                               fuchsia::virtualization::GuestConfig cfg,
                               fidl::InterfaceRequest<fuchsia::virtualization::Guest> controller,
                               LaunchInstanceCallback callback) {
  fuchsia::sys::ComponentControllerPtr component_controller;
  fuchsia::sys::LaunchInfo info;
  info.url = url;
  auto services = sys::ServiceDirectory::CreateWithRequest(&info.directory_request);
  auto guest_services = std::make_unique<GuestServices>(std::move(cfg));
  info.additional_services = guest_services->ServeDirectory();
  launcher_->CreateComponent(std::move(info), component_controller.NewRequest());
  services->Connect(std::move(controller));

  // Setup guest endpoint.
  const uint32_t cid = next_guest_cid_++;
  fuchsia::virtualization::GuestVsockEndpointPtr guest_endpoint;
  services->Connect(guest_endpoint.NewRequest());
  guest_endpoint.events().OnShutdown = fit::bind_member(this, &RealmImpl::OnVsockShutdown);
  auto endpoint =
      std::make_unique<GuestVsockEndpoint>(cid, std::move(guest_endpoint), &host_vsock_endpoint_);

  component_controller.set_error_handler([this, cid](zx_status_t status) { guests_.erase(cid); });
  auto component = std::make_unique<GuestComponent>(label.value_or(url), std::move(endpoint),
                                                    std::move(services), std::move(guest_services),
                                                    std::move(component_controller));

  bool inserted;
  std::tie(std::ignore, inserted) = guests_.insert({cid, std::move(component)});
  if (!inserted) {
    FX_LOGS(ERROR) << "Failed to allocate guest endpoint on CID " << cid;
    callback(0);
    return;
  }

  callback(cid);
}

void RealmImpl::OnVsockShutdown(uint32_t src_cid, uint32_t src_port, uint32_t dst_cid,
                                uint32_t dst_port) {
  if (src_cid == fuchsia::virtualization::HOST_CID) {
    host_vsock_endpoint_.OnShutdown(src_port);
  }
}

void RealmImpl::GetHostVsockEndpoint(
    fidl::InterfaceRequest<fuchsia::virtualization::HostVsockEndpoint> request) {
  host_vsock_endpoint_.AddBinding(std::move(request));
}

std::vector<fuchsia::virtualization::InstanceInfo> RealmImpl::ListGuests() {
  std::vector<fuchsia::virtualization::InstanceInfo> infos;
  for (const auto& it : guests_) {
    infos.push_back(fuchsia::virtualization::InstanceInfo{
        .cid = it.first,
        .label = it.second->label(),
    });
  }
  return infos;
}

void RealmImpl::ListInstances(ListInstancesCallback callback) { callback(ListGuests()); }

void RealmImpl::ConnectToInstance(uint32_t id,
                                  fidl::InterfaceRequest<fuchsia::virtualization::Guest> request) {
  const auto& it = guests_.find(id);
  if (it != guests_.end()) {
    it->second->ConnectToInstance(std::move(request));
  }
}

void RealmImpl::ConnectToBalloon(
    uint32_t id, fidl::InterfaceRequest<fuchsia::virtualization::BalloonController> request) {
  const auto& it = guests_.find(id);
  if (it != guests_.end()) {
    it->second->ConnectToBalloon(std::move(request));
  }
}

fuchsia::virtualization::GuestVsockAcceptor* RealmImpl::GetAcceptor(uint32_t cid) {
  const auto& it = guests_.find(cid);
  return it == guests_.end() ? nullptr : it->second->endpoint();
}
