// Copyright (c) 2013 The Chromium OS 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 "mist/usb_manager.h"

#include <libusb.h>
#include <poll.h>

#include <memory>

#include <base/logging.h>
#include <base/strings/stringprintf.h>

#include "mist/event_dispatcher.h"
#include "mist/usb_device.h"
#include "mist/usb_device_descriptor.h"

using base::MessageLoopForIO;
using base::StringPrintf;
using std::unique_ptr;

namespace mist {

namespace {

MessageLoopForIO::Mode ConvertEventFlagsToWatchMode(short events) {  // NOLINT
  if ((events & POLLIN) && (events & POLLOUT))
    return MessageLoopForIO::WATCH_READ_WRITE;

  if (events & POLLIN)
    return MessageLoopForIO::WATCH_READ;

  if (events & POLLOUT)
    return MessageLoopForIO::WATCH_WRITE;

  return MessageLoopForIO::WATCH_READ_WRITE;
}

}  // namespace

UsbManager::UsbManager(EventDispatcher* dispatcher)
    : dispatcher_(dispatcher),
      context_(nullptr) {}

UsbManager::~UsbManager() {
  if (context_) {
    libusb_exit(context_);
    context_ = nullptr;
  }
}

bool UsbManager::Initialize() {
  CHECK(!context_);

  int result = libusb_init(&context_);
  if (!error_.SetFromLibUsbError(static_cast<libusb_error>(result))) {
    LOG(ERROR) << "Could not initialize libusb: " << error_;
    return false;
  }

  if (!StartWatchingPollFileDescriptors()) {
    error_.set_type(UsbError::kErrorNotSupported);
    return false;
  }

  return true;
}

void UsbManager::SetDebugLevel(int level) {
  CHECK(context_);

  libusb_set_debug(context_, level);
}

UsbDevice* UsbManager::GetDevice(uint8_t bus_number,
                                 uint8_t device_address,
                                 uint16_t vendor_id,
                                 uint16_t product_id) {
  ScopedVector<UsbDevice> devices;
  if (!GetDevices(&devices))
    return nullptr;

  for (ScopedVector<UsbDevice>::iterator it = devices.begin();
       it != devices.end();
       ++it) {
    UsbDevice* device = *it;
    if (device->GetBusNumber() != bus_number ||
        device->GetDeviceAddress() != device_address)
      continue;

    unique_ptr<UsbDeviceDescriptor> device_descriptor(
        (*it)->GetDeviceDescriptor());
    VLOG(2) << *device_descriptor;
    if (device_descriptor->GetVendorId() == vendor_id &&
        device_descriptor->GetProductId() == product_id) {
      devices.weak_erase(it);
      return device;
    }
  }

  error_.set_type(UsbError::kErrorNotFound);
  return nullptr;
}

bool UsbManager::GetDevices(ScopedVector<UsbDevice>* devices) {
  CHECK(context_);
  CHECK(devices);

  devices->clear();

  libusb_device** device_list = nullptr;
  ssize_t result = libusb_get_device_list(context_, &device_list);
  if (result < 0)
    return error_.SetFromLibUsbError(static_cast<libusb_error>(result));

  for (ssize_t i = 0; i < result; ++i) {
    devices->push_back(new UsbDevice(device_list[i]));
  }

  // UsbDevice holds a reference count of a libusb_device struct. Thus,
  // decrement the reference count of the libusb_device struct in the list by
  // one when freeing the list.
  libusb_free_device_list(device_list, 1);
  return true;
}

void UsbManager::OnPollFileDescriptorAdded(int file_descriptor,
                                           short events,  // NOLINT
                                           void* user_data) {
  CHECK(user_data);

  VLOG(2) << StringPrintf("Poll file descriptor %d on events 0x%016x added.",
                          file_descriptor,
                          events);
  UsbManager* manager = reinterpret_cast<UsbManager*>(user_data);
  manager->dispatcher_->StartWatchingFileDescriptor(
      file_descriptor, ConvertEventFlagsToWatchMode(events), manager);
}

void UsbManager::OnPollFileDescriptorRemoved(int file_descriptor,
                                             void* user_data) {
  CHECK(user_data);

  VLOG(2) << StringPrintf("Poll file descriptor %d removed.", file_descriptor);
  UsbManager* manager = reinterpret_cast<UsbManager*>(user_data);
  manager->dispatcher_->StopWatchingFileDescriptor(file_descriptor);
}

bool UsbManager::StartWatchingPollFileDescriptors() {
  CHECK(context_);

  libusb_set_pollfd_notifiers(
      context_, &OnPollFileDescriptorAdded, &OnPollFileDescriptorRemoved, this);

  unique_ptr<const libusb_pollfd*, base::FreeDeleter> pollfd_list(
      libusb_get_pollfds(context_));
  if (!pollfd_list) {
    LOG(ERROR) << "Could not get file descriptors for monitoring USB events.";
    return false;
  }

  for (const libusb_pollfd** fd_ptr = pollfd_list.get(); *fd_ptr; ++fd_ptr) {
    const libusb_pollfd& pollfd = *(*fd_ptr);
    VLOG(2) << StringPrintf("Poll file descriptor %d for events 0x%016x added.",
                            pollfd.fd,
                            pollfd.events);
    if (!dispatcher_->StartWatchingFileDescriptor(
            pollfd.fd, ConvertEventFlagsToWatchMode(pollfd.events), this)) {
      return false;
    }
  }
  return true;
}

void UsbManager::HandleEventsNonBlocking() {
  CHECK(context_);

  timeval zero_tv = {0};
  int result =
      libusb_handle_events_timeout_completed(context_, &zero_tv, nullptr);
  UsbError error(static_cast<libusb_error>(result));
  LOG_IF(ERROR, !error.IsSuccess()) << "Could not handle USB events: " << error;
}

void UsbManager::OnFileCanReadWithoutBlocking(int file_descriptor) {
  VLOG(3) << StringPrintf("File descriptor %d available for read.",
                          file_descriptor);
  HandleEventsNonBlocking();
}

void UsbManager::OnFileCanWriteWithoutBlocking(int file_descriptor) {
  VLOG(3) << StringPrintf("File descriptor %d available for write.",
                          file_descriptor);
  HandleEventsNonBlocking();
}

}  // namespace mist
