// Copyright 2019 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 "usb-virtual-bus.h"

#include <fcntl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/devmgr-integration-test/fixture.h>
#include <lib/fdio/directory.h>
#include <lib/fdio/fd.h>
#include <lib/fdio/fdio.h>
#include <lib/fdio/namespace.h>
#include <lib/fdio/spawn.h>
#include <lib/fdio/unsafe.h>
#include <lib/fdio/watcher.h>
#include <lib/fidl-async/cpp/bind.h>
#include <sys/stat.h>
#include <unistd.h>
#include <zircon/device/vfs.h>
#include <zircon/hw/usb.h>
#include <zircon/processargs.h>
#include <zircon/syscalls.h>

#include <gtest/gtest.h>

namespace usb_virtual_bus {

USBVirtualBusBase::USBVirtualBusBase(std::string pkg_url, std::string svc_name) {
  // create a IsolatedDevmgr through test component
  auto ctx = sys::ComponentContext::CreateAndServeOutgoingDirectory();
  fidl::InterfacePtr<fuchsia::sys::Launcher> launcher;
  ctx->svc()->Connect(launcher.NewRequest());

  zx::channel req;
  services_ = sys::ServiceDirectory::CreateWithRequest(&req);

  fuchsia::sys::LaunchInfo info;
  info.directory_request = std::move(req);
  info.url = pkg_url;
  launcher->CreateComponent(std::move(info), ctlr_.NewRequest());
  ctlr_.set_error_handler([](zx_status_t err) { FAIL() << "Controller shouldn't exit"; });

  zx::channel devfs_server_end, devfs_client_end;
  zx::channel::create(0, &devfs_server_end, &devfs_client_end);
  services_->Connect(svc_name, std::move(devfs_server_end));
  int fd_devfs;
  fdio_fd_create(devfs_client_end.release(), &fd_devfs);
  devfs_.reset(fd_devfs);
}

void USBVirtualBusBase::InitPeripheral() {
  fbl::unique_fd fd;
  devmgr_integration_test::RecursiveWaitForFile(devfs_root(),
                                                "sys/platform/11:03:0/usb-virtual-bus", &fd);
  ASSERT_EQ(fd.is_valid(), true);
  zx::channel virtual_bus;
  ASSERT_EQ(fdio_get_service_handle(fd.release(), virtual_bus.reset_and_get_address()), ZX_OK);
  virtual_bus_.emplace(std::move(virtual_bus));

  auto enable_result = virtual_bus_->Enable();
  ASSERT_EQ(enable_result.status(), ZX_OK);
  ASSERT_EQ(enable_result.value().status, ZX_OK);

  char peripheral_str[] = "usb-peripheral";
  fd.reset(openat(devfs_root().get(), "class", O_RDONLY));
  while (fdio_watch_directory(fd.get(), usb_virtual_bus_helper::WaitForFile, ZX_TIME_INFINITE,
                              &peripheral_str) != ZX_ERR_STOP)
    continue;

  fd.reset(openat(devfs_root().get(), "class/usb-peripheral", O_RDONLY));
  fbl::String devpath;
  while (fdio_watch_directory(fd.get(), usb_virtual_bus_helper::WaitForAnyFile, ZX_TIME_INFINITE,
                              &devpath) != ZX_ERR_STOP)
    continue;

  devpath = fbl::String::Concat({fbl::String("class/usb-peripheral/"), fbl::String(devpath)});
  fd.reset(openat(devfs_root().get(), devpath.c_str(), O_RDWR));

  zx::channel peripheral;
  ASSERT_EQ(fdio_get_service_handle(fd.release(), peripheral.reset_and_get_address()), ZX_OK);
  peripheral_.emplace(std::move(peripheral));

  ASSERT_NO_FATAL_FAILURE(ClearPeripheralDeviceFunctions());
}

int USBVirtualBusBase::GetRootFd() { return devfs_root().get(); }

class EventWatcher : public ::llcpp::fuchsia::hardware::usb::peripheral::Events::Interface {
 public:
  explicit EventWatcher(async::Loop* loop, zx::channel svc, size_t functions)
      : loop_(loop), functions_(functions) {
    fidl::BindSingleInFlightOnly(loop->dispatcher(), std::move(svc), this);
  }

  void FunctionRegistered(FunctionRegisteredCompleter::Sync& completer);
  void FunctionsCleared(FunctionsClearedCompleter::Sync& completer);

  bool all_functions_registered() { return functions_registered_ == functions_; }
  bool all_functions_cleared() { return all_functions_cleared_; }

 private:
  async::Loop* loop_;
  const size_t functions_;
  size_t functions_registered_ = 0;

  bool all_functions_cleared_ = false;
};

void EventWatcher::FunctionRegistered(FunctionRegisteredCompleter::Sync& completer) {
  functions_registered_++;
  if (all_functions_registered()) {
    loop_->Quit();
    completer.Close(ZX_ERR_CANCELED);
  } else {
    completer.Reply();
  }
}

void EventWatcher::FunctionsCleared(FunctionsClearedCompleter::Sync& completer) {
  all_functions_cleared_ = true;
  loop_->Quit();
  completer.Close(ZX_ERR_CANCELED);
}

void USBVirtualBusBase::SetupPeripheralDevice(DeviceDescriptor&& device_desc,
                                              std::vector<FunctionDescriptor> function_descs) {
  using ConfigurationDescriptor =
      ::fidl::VectorView<::llcpp::fuchsia::hardware::usb::peripheral::FunctionDescriptor>;
  zx::channel state_change_sender, state_change_receiver;
  ASSERT_EQ(zx::channel::create(0, &state_change_sender, &state_change_receiver), ZX_OK);
  auto set_result = peripheral_->SetStateChangeListener(std::move(state_change_receiver));
  ASSERT_EQ(set_result.status(), ZX_OK);
  std::vector<ConfigurationDescriptor> config_descs;
  config_descs.emplace_back(fidl::unowned_vec(function_descs));
  auto set_config =
      peripheral_->SetConfiguration(std::move(device_desc), ::fidl::unowned_vec(config_descs));
  ASSERT_EQ(set_config.status(), ZX_OK);
  ASSERT_FALSE(set_config->result.is_err());

  async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread);
  EventWatcher watcher(&loop, std::move(state_change_sender), function_descs.size());
  loop.Run();
  ASSERT_TRUE(watcher.all_functions_registered());

  auto connect_result = virtual_bus_->Connect();
  ASSERT_EQ(connect_result.status(), ZX_OK);
  ASSERT_EQ(connect_result.value().status, ZX_OK);
}

void USBVirtualBusBase::ClearPeripheralDeviceFunctions() {
  zx::channel handles[2];
  ASSERT_EQ(zx::channel::create(0, handles, handles + 1), ZX_OK);
  auto set_result = peripheral_->SetStateChangeListener(std::move(handles[1]));
  ASSERT_EQ(set_result.status(), ZX_OK);

  auto clear_functions = peripheral_->ClearFunctions();
  ASSERT_EQ(clear_functions.status(), ZX_OK);

  async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread);
  EventWatcher watcher(&loop, std::move(handles[0]), 0);
  loop.Run();
  ASSERT_TRUE(watcher.all_functions_cleared());
}

}  // namespace usb_virtual_bus
