
#ifndef _H_USB_DEBUG
#define _H_USB_DEBUG

#include "debug.h"

const char* usb_device_status(unsigned long status)
{
    if (status == UsbDevice) {
        return "USB Device is connected to your computer.";
    } else if (status == UsbDeviceUnknown) {
        return "USB Device is connected but no driver is installed.";
    } else if (status == UsbDeviceInit) {
        return "USB device is in initialization sharing state.";
    } else if (status == UsbDeviceAvailable) {
        return "USB Device is shared and available for connection.";
    } else if (status == UsbDeviceBusy) {
        return "Connected USB Device is shared and is connected to a client.";
    } else if (status == UsbDeviceNotPlugged) {
        return "USB Device is shared but is not plugged to the computer at the moment.";
    } else if (status == UsbDeviceConnected) {
        return "Remote USB Device is connected to your computer.";
    } else if (status == UsbDeviceDisconnected) {
        return "Remote USB Device is disconnected from your computer.";
    } else if (status == UsbDeviceNotAvailable) {
        return "Remote USB Device is not available for connection at the moment.";
    } else if (status == UsbDeviceInactive) {
        return "USB Device is inactive.";
    }

    return "USB status is unknown.";
}

const char* usb_device_class(unsigned char usbclass)
{
    if (usbclass == 0x00) {
        return "Device";
    } else if (usbclass == 0x01) {
        return "Audio";
    } else if (usbclass == 0x02) {
        return "Comm";
    } else if (usbclass == 0x03) {
        return "HID";
    } else if (usbclass == 0x05) {
        return "Physical";
    } else if (usbclass == 0x06) {
        return "Imaging";
    } else if (usbclass == 0x07) {
        return "Printer";
    } else if (usbclass == 0x08) {
        return "Storage";
    } else if (usbclass == 0x09) {
        return "Hub";
    } else if (usbclass == 0x0A) {
        return "CDC";
    } else if (usbclass == 0x0B) {
        return "Smart card";
    } else if (usbclass == 0x0D) {
        return "Security";
    } else if (usbclass == 0x0E) {
        return "Video";
    } else if (usbclass == 0x0F) {
        return "Health";
    } else if (usbclass == 0xDC) {
        return "Diagnostic";
    } else if (usbclass == 0xE0) {
        return "Wireless";
    } else if (usbclass == 0xEF) {
        return "Misc";
    } else if (usbclass == 0xFE) {
        return "Application";
    } else if (usbclass == 0xFF) {
        return "Vendor";
    }

    return "Unknown";
}

const char* usb_device_properties(unsigned long prop)
{
    static std::string str;
    str.clear();

    if (prop == 0) {
        str = "Standard USB Device.";
    } else {
        if ((prop & AutoPlugDevice) == AutoPlugDevice) {
            str += "AUTO ";
        }
        if ((prop & ExcludeDevice) == ExcludeDevice) {
            str += "EXCL ";
        }
        if ((prop & UseInactiveTimeout) == UseInactiveTimeout) {
            str += "TIMEOUT ";
        }
        if ((prop & SharedDevice) == SharedDevice) {
            str += "SHARED ";
        }
        if ((prop & SerialNumberPresent) == SerialNumberPresent) {
            str += "SERIAL ";
        }
        if ((prop & NickNamePresent) == NickNamePresent) {
            str += "NICK ";
        }
    }

    return str.c_str();
}

void usb_device_descriptor(const DEVICE_DESCRIPTOR& desc)
{
    std::ostringstream dev;

    dev << (fmt("0x%08p") % desc.hDevice) << ", ";

    dev << "USB Device: " << desc.cLocationInformation << " - "
       << desc.cDeviceDescription << ", ";

    if (desc.ulDeviceProperties & SerialNumberPresent) {
        dev << "Serial number: "<< desc.cInstanceId << ", ";
    } else {
        dev << "USB port: " << desc.cInstanceId << ", ";
    }

    if (desc.ulDeviceProperties & NickNamePresent) {
        dev << "Nick: " << desc.cNickName << ", ";
    }

    dev << (fmt("Class: 0x%02x (%s) VendoreID: 0x%04x Product ID: 0x%04x Revision: 0x%04x")
        % static_cast<int>(desc.zero_iface.DeviceClass) % usb_device_class(desc.zero_iface.DeviceClass)
        % desc.hwid.VendorId % desc.hwid.ProductId % desc.hwid.Revision)
        << ", ";

    dev << (fmt("Status: 0x%04x (%s)") % desc.ulDeviceStatus %
        usb_device_status(desc.ulDeviceStatus)) << ", ";

    dev << (fmt("Properties: 0x%04x (%s)") % desc.ulDeviceProperties %
        usb_device_properties(desc.ulDeviceProperties)) << ", ";

    dev << "Timeout: " << desc.ulInactiveTimeout;

    if (desc.ulIpClient != 0) {
        in_addr addr;
        addr.s_addr = desc.ulIpClient;
        dev << ", Connected to client " << inet_ntoa(addr);
    }

    LOG_TRACE(dev.str());
}

void log_usb_error(const char* str)
{
    unsigned long arg;
    unsigned long err = GetUSBRedirectorLastError(&arg);
    LOG_ERROR(str << " err = " << err << " arg = " << arg);
}

#endif // _H_USB_DEBUG
