#include "libusb_wrapper.h"
#include <stdio.h>
#include <string.h>

#define VID 1003
#define PID 8259

int main(int argc, char *argv[]) {
  printf("Hello World :-|\n");

  libusb_context *context;
  usbinit(&context);
#ifdef DEBUG
  libusb_set_option(context, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_DEBUG);
#endif

  if (argc > 1) {
    // command mode
    if (strcmp(argv[1], "demo4.1") == 0) { // if 4.1
      printf("\e[91mDemo 4.1\e[39m\n");
      displayDevices(context);
    } else if (strcmp(argv[1], "demo4.1plus") == 0) { // if 4.1 bonus
      printf("\e[91mDemo 4.1\e[39m\n");
      displayDevicesMore(context);
    } else if (strcmp(argv[1], "demo4.2") == 0) { // if 4.2
      printf("\e[91mDemo 4.2\e[39m\n");

      if (argc > 3) {
        uint16_t vendor_id;
        uint16_t product_id;
        sscanf(argv[2], "%hu", &vendor_id);
        sscanf(argv[3], "%hu", &product_id);

        libusb_device_handle *handle;
        handle =
            libusb_open_device_with_vid_pid(context, vendor_id, product_id);
        if (handle != NULL) {
          printf("Show endpoints of VID:%hu;PID:%hu\n", vendor_id, product_id);
          displayDeviceEndpoints(handle);
        } else {
          printf("Error while getting handle of VID:%hu;PID:%hu\n", vendor_id,
                 product_id);
        }
      } else {
        printf("Error, need VID and PID\n");
      }
    } else {
      printf("Wrong command\n");
    }

  } else {
    // interactive mode
    printf("Welcome to interactive mode\n");
    printf("Compiled for VID:PID => %d:%d\n", VID, PID);

    // Find the device
    printf("Iterate list of devices, and getting the right one\n");
    libusb_device *device = NULL;
    getFirstDeviceFromID(context, VID, PID, &device);
    // code
    if (device == NULL) {
      printf("Error : cannot find the device !\n");
      return 1;
    }

    // take the handle
    libusb_device_handle *device_handle = NULL;
    if (libusb_open(device, &device_handle) != 0) {
      printf("Error : cannot handle the device\n");
      return 1;
    }

    // Take the interfaces
    printf("\nSearch for interfaces\n");
    struct libusb_interface *int_hidjoy = NULL;
    struct libusb_interface *int_leds = NULL;
    struct libusb_interface *int_vibrators = NULL;
    getOurInterfaces(device, &int_hidjoy, &int_leds, &int_vibrators);

    // Claim interface
    printf("\nClaim interfaces ...\n");
    printf("-Leds\n");
    interfaceclaim(device_handle, int_leds);
    printf("-Vibrators\n");
    interfaceclaim(device_handle, int_vibrators);

    // récupération des endpoints
    printf("\nRécupération endpoints\n");
    printf("-Leds");
    int endpoint_leds =
        getOnlyEndpoint(int_leds); /* ID of endpoint (bit 8 is 0) */
    printf(" is %d\n", endpoint_leds);
    printf("-Vibrators");
    int endpoint_vibrators =
        getOnlyEndpoint(int_vibrators); /* ID of endpoint (bit 8 is 0) */
    printf(" is %d\n", endpoint_vibrators);

    /*LE CODE UTILE*/
    int i;
    for(i = 0 ; i<5 ; i++) {
      unsigned char data[2] = {0xff, 0xff}; // data to send or to receive
      int size = 2;       // size to send or maximum size to receive
      int timeout = 1000; // timeout in ms

      // OUT interrupt, from host to device
      int bytes_out;
      printf("%p %02X\n", device_handle, endpoint_leds);
      int status = libusb_interrupt_transfer(device_handle, endpoint_leds, data,
                                             size, &bytes_out, timeout);
      if (status != 0) {
        perror("libusb_interrupt_transfer");
        exit(-1);
      }

      //sleep(1); demande l'ajout de macro pour la portabilité
    }
    /*FIN DU CODE UTILE*/

    // Close
    printf("\nUnclaim interfaces ...\n");
    printf("-Leds\n");
    interfaceclose(device_handle, int_leds);
    printf("-Vibrators\n");
    interfaceclose(device_handle, int_vibrators);

    printf("Finished\n");
  }

  usbclose(context);

  return 0;
}
