// Copyright 2022 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 "acpi_multiply.h"

#include <fidl/fuchsia.hardware.acpi/cpp/wire.h>
#include <lib/async/cpp/task.h>
#include <lib/driver/component/cpp/service_client.h>

#include "multiply_server.h"

namespace acpi_multiply {

zx::result<> AcpiMultiplyDriver::Start() {
  // Connect to the ACPI protocol exposed by the parent driver.
  auto client_endpoint =
      driver::Connect<fuchsia_hardware_acpi::Service::Device>(*context().incoming());
  if (client_endpoint.is_error()) {
    FDF_SLOG(ERROR, "Failed to connect to ACPI.", KV("status", client_endpoint.status_string()));
    return client_endpoint.take_error();
  }
  auto acpi_client = fidl::WireSyncClient(std::move(*client_endpoint));

  // Initialize ACPI hardware resources
  multiplier_ = std::make_shared<AcpiMultiplier>(&logger(), dispatcher(), std::move(acpi_client));
  auto init_result = multiplier_->SetupMmioAndInterrupts();
  if (init_result.is_error()) {
    FDF_SLOG(ERROR, "Failed to initialize ACPI resources.",
             KV("status", init_result.status_string()));
    return init_result.take_error();
  }
  FDF_LOG(INFO, "Hardware resources initialized.");

  // Serve the examples.acpi.multiply/Device protocol to clients through the
  // examples.acpi.multiply/Service wrapper.
  examples_acpi_multiply::Service::InstanceHandler handler({
    .device = [this](fidl::ServerEnd<examples_acpi_multiply::Device> request) -> void {
        AcpiMultiplyServer::BindDeviceClient(&logger(), dispatcher(), multiplier_,
                                             std::move(request));
      }
  });

  auto result = context().outgoing()->AddService<examples_acpi_multiply::Service>(std::move(handler));
  if (result.is_error()) {
    FDF_SLOG(ERROR, "Failed to add service.", KV("status", result.status_string()));
    return result.take_error();
  }

  // Initialize the driver compat service context.
  compat::Context::ConnectAndCreate(
      &context(), dispatcher(),
      fit::bind_member<&AcpiMultiplyDriver::InitializeCompatService>(this));

  return zx::ok();
}

// Initialize the driver compat context and export `examples.acpi.multiply/Service` to
// devfs.
void AcpiMultiplyDriver::InitializeCompatService(
    zx::result<std::shared_ptr<compat::Context>> compat_result) {
  if (!compat_result.is_ok()) {
    FDF_SLOG(ERROR, "Failed to create compat context.",
             KV("status", compat_result.status_string()));
    node().reset();
    return;
  }
  compat_context_ = std::move(*compat_result);

  auto service_path = std::string(examples_acpi_multiply::Service::Name) + "/" +
                      component::kDefaultInstance + "/" +
                      examples_acpi_multiply::Service::Device::Name;
  auto status = compat_context_->devfs_exporter().ExportSync(
      service_path, compat_context_->TopologicalPath(name()), fuchsia_device_fs::ExportOptions());
  if (status != ZX_OK) {
    FDF_SLOG(ERROR, "Failed to export to devfs.", KV("status", zx_status_get_string(status)));
    node().reset();
    return;
  }
}

}  // namespace acpi_multiply

FUCHSIA_DRIVER_RECORD_CPP_V2(driver::Record<acpi_multiply::AcpiMultiplyDriver>);
