// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "libusb.hpp"

#include <stdplus/util/cexec.hpp>

#include <system_error>
#include <utility>

namespace google
{
namespace hoth
{
namespace libusb
{

int toErrno(int error)
{
    switch (error)
    {
        case LIBUSB_SUCCESS:
            return 0;
        case LIBUSB_ERROR_IO:
            return EIO;
        case LIBUSB_ERROR_INVALID_PARAM:
            return EINVAL;
        case LIBUSB_ERROR_ACCESS:
            return EACCES;
        case LIBUSB_ERROR_NO_DEVICE:
            return ENODEV;
        case LIBUSB_ERROR_NOT_FOUND:
            return ENOENT;
        case LIBUSB_ERROR_BUSY:
            return EBUSY;
        case LIBUSB_ERROR_TIMEOUT:
            return ETIMEDOUT;
        case LIBUSB_ERROR_OVERFLOW:
            return EOVERFLOW;
        case LIBUSB_ERROR_PIPE:
            return EPIPE;
        case LIBUSB_ERROR_INTERRUPTED:
            return EINTR;
        case LIBUSB_ERROR_NO_MEM:
            return ENOMEM;
        case LIBUSB_ERROR_NOT_SUPPORTED:
            return ENOTSUP;
        default:
            return ENOSYS;
    }
}

inline auto makeError(int error, const char* msg)
{
    return std::system_error(toErrno(-error), std::generic_category(), msg);
}

template <typename... Args>
inline auto callCheck(const char* msg, Args&&... args)
{
    return stdplus::util::callCheckRet<makeError, Args...>(
        msg, std::forward<Args>(args)...);
}

InterfaceClaim::InterfaceClaim(LibusbIntf* libusb, libusb_device_handle* handle,
                               int interface) :
    libusb(libusb),
    handle(init(handle, interface), interface, libusb)
{}

void InterfaceClaim::drop(libusb_device_handle*&& handle, int& interface,
                          LibusbIntf*& libusb)
{
    libusb->release_interface(handle, interface);
}

libusb_device_handle* InterfaceClaim::init(libusb_device_handle* handle,
                                           int interface)
{
    callCheck("claim_interface", &LibusbIntf::claim_interface, libusb, handle,
              interface);
    return handle;
}

InterfaceClaim DeviceHandle::claim_interface(int interface)
{
    return InterfaceClaim(libusb, *handle, interface);
}

unsigned DeviceHandle::bulk_transfer(const libusb_endpoint_descriptor& ep,
                                     uint8_t* data, size_t size,
                                     std::chrono::milliseconds timeout)
{
    int ret;
    callCheck("bulk_transfer", &LibusbIntf::bulk_transfer, libusb, *handle,
              ep.bEndpointAddress, data, size, &ret, timeout.count());
    return ret;
}

void DeviceHandle::drop(libusb_device_handle*&& handle, LibusbIntf*& libusb)
{
    libusb->close(handle);
}

libusb_config_descriptor& Device::get_active_config_descriptor()
{
    libusb_config_descriptor* ret;
    callCheck("get_active_config_descriptor",
              &LibusbIntf::get_active_config_descriptor, libusb, *dev, &ret);
    return *ret;
}

uint8_t Device::get_bus_number()
{
    return libusb->get_bus_number(*dev);
}

std::vector<uint8_t> Device::get_port_numbers()
{
    // 7 is the maximum depth per the usb spec
    std::vector<uint8_t> ret(7);
    int r = callCheck("get_port_numbers", &LibusbIntf::get_port_numbers, libusb,
                      *dev, ret.data(), ret.size());
    ret.resize(r);
    return ret;
}

DeviceHandle Device::open()
{
    libusb_device_handle* handle;
    callCheck("open", &LibusbIntf::open, libusb, *dev, &handle);
    return DeviceHandle(libusb, handle);
}

void Device::drop(libusb_device*&& dev, LibusbIntf*& libusb)
{
    libusb->unref_device(dev);
}

std::vector<Device> Context::get_device_list()
{
    libusb_device** devs;
    callCheck("get_device_list", &LibusbIntf::get_device_list, libusb, *ctx,
              &devs);
    std::vector<Device> ret;
    for (size_t i = 0; devs[i] != nullptr; ++i)
    {
        ret.push_back(Device(libusb, devs[i]));
    }
    libusb->free_device_list(devs, 0);
    return ret;
}

void Context::drop(libusb_context*&& ctx, LibusbIntf*& libusb)
{
    libusb->exit(ctx);
}

libusb_context* Context::init()
{
    libusb_context* ctx = nullptr;
    callCheck("init", &LibusbIntf::init, libusb, &ctx);
    return ctx;
}

} // namespace libusb
} // namespace hoth
} // namespace google
