// 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_transfer.h"

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

#include <libusb.h>

namespace mist {

UsbTransfer::UsbTransfer()
    : transfer_(nullptr), buffer_length_(0), state_(kIdle) {}

UsbTransfer::~UsbTransfer() {
  Free();
}

bool UsbTransfer::Submit(const CompletionCallback& completion_callback) {
  if (!VerifyAllocated())
    return false;

  if (state_ != kIdle) {
    error_.set_type(UsbError::kErrorTransferAlreadySubmitted);
    return false;
  }

  completion_callback_ = completion_callback;

  VLOG(1) << "Submit USB transfer: " << *this;
  int result = libusb_submit_transfer(transfer_);
  if (error_.SetFromLibUsbError(static_cast<libusb_error>(result))) {
    state_ = kInProgress;
    return true;
  }
  return false;
}

bool UsbTransfer::Cancel() {
  if (state_ == kIdle) {
    error_.set_type(UsbError::kErrorTransferNotSubmitted);
    return false;
  }

  if (state_ == kCancelling) {
    error_.set_type(UsbError::kErrorTransferBeingCancelled);
    return false;
  }

  int result = libusb_cancel_transfer(transfer_);
  if (error_.SetFromLibUsbError(static_cast<libusb_error>(result))) {
    state_ = kCancelling;
    return true;
  }
  return false;
}

uint8_t UsbTransfer::GetEndpointAddress() const {
  return transfer_ ? transfer_->endpoint : 0;
}

UsbTransferType UsbTransfer::GetType() const {
  if (!transfer_)
    return kUsbTransferTypeUnknown;

  switch (transfer_->type) {
    case LIBUSB_TRANSFER_TYPE_CONTROL:
      return kUsbTransferTypeControl;
    case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
      return kUsbTransferTypeIsochronous;
    case LIBUSB_TRANSFER_TYPE_BULK:
      return kUsbTransferTypeBulk;
    case LIBUSB_TRANSFER_TYPE_INTERRUPT:
      return kUsbTransferTypeInterrupt;
  }
  return kUsbTransferTypeUnknown;
}

UsbTransferStatus UsbTransfer::GetStatus() const {
  if (!transfer_)
    return kUsbTransferStatusUnknown;

  switch (transfer_->status) {
    case LIBUSB_TRANSFER_COMPLETED:
      return kUsbTransferStatusCompleted;
    case LIBUSB_TRANSFER_ERROR:
      return kUsbTransferStatusError;
    case LIBUSB_TRANSFER_TIMED_OUT:
      return kUsbTransferStatusTimedOut;
    case LIBUSB_TRANSFER_CANCELLED:
      return kUsbTransferStatusCancelled;
    case LIBUSB_TRANSFER_STALL:
      return kUsbTransferStatusStall;
    case LIBUSB_TRANSFER_NO_DEVICE:
      return kUsbTransferStatusNoDevice;
    case LIBUSB_TRANSFER_OVERFLOW:
      return kUsbTransferStatusOverflow;
  }
  return kUsbTransferStatusUnknown;
}

int UsbTransfer::GetLength() const {
  return transfer_ ? transfer_->length : 0;
}

int UsbTransfer::GetActualLength() const {
  return transfer_ ? transfer_->actual_length : 0;
}

bool UsbTransfer::IsCompletedWithExpectedLength(int expected_length) const {
  return GetStatus() == kUsbTransferStatusCompleted &&
         GetActualLength() == expected_length;
}

std::string UsbTransfer::ToString() const {
  if (!transfer_)
    return "Transfer (not allocated)";

  return base::StringPrintf(
      "Transfer %p (Type=%s, "
      "Flags=0x%08x, "
      "DeviceHandle=%p, "
      "EndpointAddress=%u, "
      "NumIsoPackets=%d, "
      "Buffer=%p, "
      "Length=%d, "
      "Transferred=%d, "
      "Timeout=%u, "
      "Status=%s)",
      transfer_, UsbTransferTypeToString(GetType()), transfer_->flags,
      transfer_->dev_handle, transfer_->endpoint, transfer_->num_iso_packets,
      transfer_->buffer, transfer_->length, transfer_->actual_length,
      transfer_->timeout, UsbTransferStatusToString(GetStatus()));
}

bool UsbTransfer::VerifyAllocated() {
  if (transfer_)
    return true;

  LOG(ERROR) << "USB transfer is not allocated.";
  error_.set_type(UsbError::kErrorTransferNotAllocated);
  return false;
}

bool UsbTransfer::Allocate(int num_iso_packets) {
  if (transfer_) {
    LOG(ERROR) << "USB transfer already allocated.";
    error_.set_type(UsbError::kErrorTransferAlreadyAllocated);
    return false;
  }

  transfer_ = libusb_alloc_transfer(num_iso_packets);
  if (!transfer_) {
    LOG(ERROR) << "Could not allocate USB transfer.";
    error_.set_type(UsbError::kErrorNoMemory);
    return false;
  }

  VLOG(2) << base::StringPrintf("Allocated USB transfer %p.", transfer_);
  error_.Clear();
  return true;
}

void UsbTransfer::Free() {
  // It is not ok to free a transfer while it is still in progress or being
  // cancelled.
  CHECK_EQ(kIdle, state_);

  if (transfer_) {
    libusb_free_transfer(transfer_);
    VLOG(2) << base::StringPrintf("Freed USB transfer %p.", transfer_);
    transfer_ = nullptr;
  }
}

bool UsbTransfer::AllocateBuffer(int length) {
  if (state_ != kIdle) {
    error_.set_type(UsbError::kErrorTransferAlreadySubmitted);
    return false;
  }

  buffer_.reset(new uint8_t[length]);
  if (buffer_) {
    buffer_length_ = length;
    VLOG(2) << base::StringPrintf(
        "Allocated data buffer %p for USB transfer %p.", buffer_.get(),
        transfer_);
    return true;
  }

  buffer_length_ = 0;
  LOG(ERROR) << base::StringPrintf(
      "Could not allocate data buffer for USB transfer %p.", transfer_);
  error_.set_type(UsbError::kErrorNoMemory);
  return false;
}

void UsbTransfer::OnCompleted(libusb_transfer* transfer) {
  CHECK(transfer);
  UsbTransfer* usb_transfer =
      reinterpret_cast<UsbTransfer*>(transfer->user_data);
  CHECK(usb_transfer);
  CHECK_EQ(transfer, usb_transfer->transfer_);

  VLOG(1) << base::StringPrintf("USB transfer %p completed.", usb_transfer);
  usb_transfer->Complete();
}

void UsbTransfer::Complete() {
  // Change the state to idle before calling the completion callback as this
  // object may be destructed in the completion callback and Free(), which is
  // called in the destructor of this object, expects the state to be idle.
  state_ = kIdle;
  if (!completion_callback_.is_null()) {
    VLOG(2) << base::StringPrintf(
        "Invoke completion callback for USB transfer %p.", transfer_);
    completion_callback_.Run(this);
  }
}

}  // namespace mist

std::ostream& operator<<(std::ostream& stream,
                         const mist::UsbTransfer& transfer) {
  stream << transfer.ToString();
  return stream;
}
