// Copyright 2021 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/graphics/bin/vulkan_loader/loader.h"

#include <fidl/fuchsia.kernel/cpp/wire.h>
#include <lib/component/incoming/cpp/protocol.h>

fidl::ProtocolHandler<fuchsia_vulkan_loader::Loader> LoaderImpl::GetHandler(
    LoaderApp* app, async_dispatcher_t* dispatcher) {
  return [=](fidl::ServerEnd<fuchsia_vulkan_loader::Loader> server_end) {
    std::unique_ptr<LoaderImpl> impl(new LoaderImpl(app));
    auto binding = fidl::BindServer(dispatcher, std::move(server_end), std::move(impl));
  };
}

LoaderImpl::~LoaderImpl() { app_->RemoveObserver(this); }

zx::result<> LoaderImpl::Add(component::OutgoingDirectory& outgoing_dir, LoaderApp* app,
                             async_dispatcher_t* dispatcher) {
  return outgoing_dir.AddUnmanagedProtocol<fuchsia_vulkan_loader::Loader>(
      GetHandler(app, dispatcher));
}

// LoaderApp::Observer implementation.
void LoaderImpl::OnIcdListChanged(LoaderApp* app) {
  auto it = callbacks_.begin();
  while (it != callbacks_.end()) {
    std::optional<zx::vmo> vmo = app->GetMatchingIcd(it->first);
    if (!vmo) {
      ++it;
    } else {
      it->second.Reply(*std::move(vmo));
      it = callbacks_.erase(it);
    }
  }
  if (!app->HavePendingActions()) {
    for (auto& handle : connect_manifest_handles_) {
      app_->ServeManifestFs(std::move(handle));
    }
    connect_manifest_handles_.clear();
  }
  if (!waiting_for_callbacks()) {
    app_->RemoveObserver(this);
  }
}

// fuchsia::vulkan::loader::Loader impl
void LoaderImpl::Get(GetRequest& request, GetCompleter::Sync& completer) {
  AddCallback(std::move(request.name()), completer.ToAsync());
}

void LoaderImpl::ConnectToDeviceFs(ConnectToDeviceFsRequest& request,
                                   ConnectToDeviceFsCompleter::Sync& completer) {
  app_->ServeDeviceFs(fidl::ServerEnd<fuchsia_io::Directory>{std::move(request.channel())});
}

void LoaderImpl::ConnectToManifestFs(ConnectToManifestFsRequest& request,
                                     ConnectToManifestFsCompleter::Sync& completer) {
  auto server_end = fidl::ServerEnd<fuchsia_io::Directory>{std::move(request.channel())};
  if (!(request.options() & fuchsia_vulkan_loader::ConnectToManifestOptions::kWaitForIdle) ||
      !app_->HavePendingActions()) {
    app_->ServeManifestFs(std::move(server_end));
    return;
  }

  bool was_waiting_for_callbacks = waiting_for_callbacks();
  connect_manifest_handles_.push_back(std::move(server_end));
  if (waiting_for_callbacks() && !was_waiting_for_callbacks) {
    app_->AddObserver(this);
  }
}

void LoaderImpl::GetSupportedFeatures(GetSupportedFeaturesCompleter::Sync& completer) {
  constexpr fuchsia_vulkan_loader::Features kFeatures =
      fuchsia_vulkan_loader::Features::kConnectToDeviceFs |
      fuchsia_vulkan_loader::Features::kConnectToManifestFs | fuchsia_vulkan_loader::Features::kGet;
  completer.Reply(kFeatures);
}

void LoaderImpl::GetVmexResource(GetVmexResourceCompleter::Sync& completer) {
  if (!app_->allow_lavapipe_icd()) {
    FX_LOGS(ERROR) << "Lavapipe is not allowed, GetVmexResource() shouldn't be called.";
    completer.Reply(
        fit::error(fuchsia_vulkan_loader::GetVmexResourceError::kLavapipeIcdNotAllowed));
    return;
  }

  auto client_end_or = component::Connect<fuchsia_kernel::VmexResource>();
  if (client_end_or.is_error()) {
    FX_LOGS(WARNING) << "Failed to connect to fuchsia.kernel.VmexResource: "
                     << client_end_or.status_string();
    completer.Reply(
        fit::error(fuchsia_vulkan_loader::GetVmexResourceError::kFailedToObtainResource));

    return;
  }

  auto result = fidl::WireCall(*client_end_or)->Get();
  if (!result.ok()) {
    FX_LOGS(WARNING) << "fuchsia.kernel.VmexResource.Get() failed: " << result.error();
    completer.Reply(
        fit::error(fuchsia_vulkan_loader::GetVmexResourceError::kFailedToObtainResource));

    return;
  }

  completer.Reply(fit::ok(std::move(result.value().resource)));
}

void LoaderImpl::AddCallback(std::string name, GetCompleter::Async completer) {
  bool was_waiting_for_callbacks = waiting_for_callbacks();
  std::optional<zx::vmo> vmo = app_->GetMatchingIcd(name);
  if (vmo) {
    completer.Reply(*std::move(vmo));
    return;
  }
  callbacks_.emplace_back(std::move(name), std::move(completer));
  if (waiting_for_callbacks() && !was_waiting_for_callbacks) {
    app_->AddObserver(this);
  }
}
