// 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, std::move(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, std::move(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
