// 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>

using base::StringPrintf;
using std::ostream;
using std::string;

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;
}

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

  return 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) << 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) << 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) << StringPrintf("Allocated data buffer %p for USB transfer %p.",
                            buffer_.get(), transfer_);
    return true;
  }

  buffer_length_ = 0;
  LOG(ERROR) << 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) << 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) << StringPrintf("Invoke completion callback for USB transfer %p.",
                            transfer_);
    completion_callback_.Run(this);
  }
}

}  // namespace mist

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