
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>

#include "swis.h"
#include "Global/RISCOS.h"
#include "Global/Keyboard.h"


#include "debugrep.h"
#include "usbjoystick.h"
#include "errors.h"
#include "joyhelp.h"
#include "joyswis.h"
#include "mouse.h"
#include "adc.h"
#include "device.h"

#include "cmdshow.h"


_kernel_oserror *command_read(const char *args, int32_t argc)
{
  if (argc != 1) {
    debug_printf("command_read: Bad arguments, argc isn't 1 (it is %d)\n", argc);
    return geterror(Error_BadNoParms);
  }

  _kernel_oserror *error = NULL;
  uint32_t slot;
  uint32_t ret = sscanf(args, "%d", &slot);
  if (ret != 1) {
    debug_printf("command_read: Bad arguments, didn't read 1 arg (read %d)\n", ret);
    return geterror(Error_BadNoParms);
  }

  if (slot >= JOY_MAX) {
    debug_printf("command_read: Bad arguments, slot (%d) is out of range\n", slot);
    return geterror(Error_BadNoParms);
  }

  if (!joy_data[slot].in_use) {
    debug_printf("command_read: Joystick slot (%d) isn't active\n", slot);
    return geterror(Error_JoyNotActive);
  }

  if (!joy_data[slot].open) {
    debug_printf("command_read: Joystick slot (%d) isn't open\n", slot);
    return geterror(Error_JoyNotOpen);
  }

  debug_printf("command_read: slot %u\n", slot);

  printf("Joystick slot %u (%s - %s)\n", slot, joy_data[slot].manufacturer, joy_data[slot].product);

  for (uint32_t a=0; a<joy_data[slot].num_axes; a++) {
    printf("Axis %02d %6s : ", a, joy_data[slot].axes[a].name);
    printf("Val %8d  ", joy_data[slot].axes[a].val);
    printf("Min %8d  ", joy_data[slot].axes[a].min);
    printf("Mid %8d  ", joy_data[slot].axes[a].mid);
    printf("Max %8d  ", joy_data[slot].axes[a].max);
    printf("Invert=");
    if (joy_data[slot].axes[a].flip)
      printf("on");
    else
      printf("off");

    printf("\n");
  }

  printf("Buttons: ");
  for (uint32_t b=0; b<joy_data[slot].num_buttons; b++) {
    printf("%u=%u ", b, joy_data[slot].buttons[b]);
  }
  printf("\n");

  IGNORE(error);

  return NULL;
}




_kernel_oserror *command_debug(const char *args, int32_t argc)
{
  if (argc >= 1) {
    int32_t desired_slot = -1;
    uint32_t ret = sscanf(args, "%d", &desired_slot);
    if (ret != 1) {
      debug_printf("Debug: Bad arguments, didn't read 1 args (read %d)\n", ret);
      return geterror(Error_BadNoParms);
    }

    if (desired_slot < 0 || desired_slot >= JOY_MAX) {
      debug_printf("Debug: Bad arguments, slot (%d) is too big\n", desired_slot);
      return geterror(Error_BadNoParms);
    }

    if (!joy_data[desired_slot].in_use) {
      debug_printf("Debug: Joystick slot (%d) isn't active\n", desired_slot);
      return geterror(Error_JoyNotActive);
    }

    if (!joy_data[desired_slot].open) {
      debug_printf("Debug: Joystick slot (%d) isn't open\n", desired_slot);
      return geterror(Error_JoyNotOpen);
    }

    debug_printf("Debug: Printing out single stick slot %d\n", desired_slot);
    debug_joystick(desired_slot);
  }
  else {
    int any = FALSE;

    for (uint32_t slot=0; slot<JOY_MAX; slot++) {
      if (joy_data[slot].in_use == TRUE) {
        debug_printf("Debug: Printing out all active sticks, currently on stick slot %d\n", slot);
        debug_joystick(slot);
        any = TRUE;
      }
    }

    if (any == FALSE) {
      printf("No active joysticks.\n");
    }
  }

  return NULL;
}




_kernel_oserror *command_list(const char *args, int32_t argc)
{
  if (argc >= 1) {
    int32_t desired_slot = -1;
    uint32_t ret = sscanf(args, "%d", &desired_slot);
    if (ret != 1) {
      debug_printf("command_list: Bad arguments, didn't read 1 args (read %d)\n", ret);
      return geterror(Error_BadNoParms);
    }

    if (desired_slot < 0 || desired_slot >= JOY_MAX) {
      debug_printf("command_list: Bad arguments, slot (%d) is too big\n", desired_slot);
      return geterror(Error_BadNoParms);
    }

    if (!joy_data[desired_slot].in_use) {
      debug_printf("command_list: Joystick slot (%d) isn't active\n", desired_slot);
      return geterror(Error_JoyNotActive);
    }

    if (!joy_data[desired_slot].open) {
      debug_printf("command_list: Joystick slot (%d) isn't open\n", desired_slot);
      return geterror(Error_JoyNotOpen);
    }

    debug_printf("command_list: Printing out single stick slot %d\n", desired_slot);
    print_joystick(desired_slot);
  }
  else {
    int any = FALSE;

    for (uint32_t slot=0; slot<JOY_MAX; slot++) {
      if (joy_data[slot].in_use == TRUE) {
        debug_printf("command_list: Printing out all active sticks, currently on stick slot %d\n", slot);
        print_joystick(slot);
        any = TRUE;
      }
    }

    if (any == FALSE) {
      printf("No active joysticks.\n");
    }
  }

  return NULL;
}








void print_joystick(uint32_t slot)
{
  printf("Joystick slot %u (%s - %s)\n", slot, joy_data[slot].manufacturer, joy_data[slot].product);

  printf("  Local USB device name            : %s\n", joy_data[slot].device_name);
  printf("  Interface                        : %d\n", joy_data[slot].interface);
  printf("  Endpoint                         : %d\n", joy_data[slot].endpoint);
  printf("  Device manufacturer              : %s\n", joy_data[slot].manufacturer);
  printf("  Device product name              : %s\n", joy_data[slot].product);
  printf("  Device serial number             : %s\n", joy_data[slot].serial);
  printf("  Driver                           : ");
  if (joy_data[slot].device)
    printf("%s\n", joy_data[slot].device->name);
  else
    printf("N/A\n");

  printf("  Number of axes                   : %d\n", joy_data[slot].num_axes);
  printf("  Number of buttons                : %d\n", joy_data[slot].num_buttons);

  printf("  HAT switch                       : ");
  if (joy_data[slot].hat_item)
    printf("Yes\n");
  else
    printf("No\n");

  printf("  DPAD                             : ");
  if (joy_data[slot].has_dpad)
    printf("Yes\n");
  else
    printf("No\n");

  /* The mouse/keyboard mapping state is not summarised here - the binding
     table is the source of truth; *USBJoystick_Mappings shows it in full. */
}








void debug_joystick(uint32_t slot)
{
  printf("Joystick slot %u (%s - %s)\n", slot, joy_data[slot].manufacturer, joy_data[slot].product);

  printf("  Path                    : %s\n", joy_data[slot].usb_path);
  printf("  File handle             : %u\n", joy_data[slot].fp);

  printf("  Data stream open        : ");
  if (joy_data[slot].open)
    printf("Yes\n");
  else
    printf("No (is something else using it?)\n");

  printf("  Local USB device name   : %s\n", joy_data[slot].device_name);
  printf("  Interface               : %d\n", joy_data[slot].interface);
  printf("  Endpoint                : %d\n", joy_data[slot].endpoint);
  printf("  Device manufacturer     : %s\n", joy_data[slot].manufacturer);
  printf("  Device product name     : %s\n", joy_data[slot].product);
  printf("  Device serial number    : %s\n", joy_data[slot].serial);
  printf("  Driver                  : ");
  if (joy_data[slot].device)
    printf("%s\n", joy_data[slot].device->name);
  else
    printf("N/A\n");

  printf("  USB vendor id           : 0x%04x\n", joy_data[slot].vendor_id);
  printf("  USB product id          : 0x%04x\n", joy_data[slot].product_id);
  printf("  USB device id           : 0x%04x\n", joy_data[slot].device_id);

  printf("  Buffer handle           : %u\n", (uint32_t)(joy_data[slot].buffer_handle));
  printf("  Buffer internal id      : %u\n", (uint32_t)(joy_data[slot].buffer_internal_id));
  printf("  Buffer service routine  : 0x%08x\n", (uint32_t)(joy_data[slot].buffer_service_routine));
  printf("  Buffer workspace        : 0x%08x\n", (uint32_t)(joy_data[slot].buffer_workspace));

  printf("  DeviceFS handle         : 0x%08x\n", joy_data[slot].devicefs_handle);
  printf("  Report data length      : %u\n", joy_data[slot].report_length);

  printf("  Upcalls                 : %u (delta: %u)\n", joy_data[slot].upcalls, joy_data[slot].upcalls_delta);
  joy_data[slot].upcalls_delta = 0;

  printf("  Good reads              : %u (delta: %u)\n", joy_data[slot].good_reads, joy_data[slot].good_reads_delta);
  joy_data[slot].good_reads_delta = 0;

  printf("  Bad reads               : %u (delta: %u)\n", joy_data[slot].bad_reads, joy_data[slot].bad_reads_delta);
  joy_data[slot].bad_reads_delta = 0;

  printf("  Raw report data         : ");
  for (int32_t b=0; b<joy_data[slot].report_length; b++) {
    printf("%02x ", joy_data[slot].data_buf[b]);
  }
  printf("\n");

  printf("  Number of axes          : %d\n", joy_data[slot].num_axes);
  printf("  Number of buttons       : %d\n", joy_data[slot].num_buttons);

  printf("  HAT switch              : ");
  if (joy_data[slot].hat_item)
    printf("Yes\n");
  else
    printf("No\n");

  printf("  DPAD                    : ");
  if (joy_data[slot].has_dpad)
    printf("Yes\n");
  else
    printf("No\n");

  printf("  Axes:\n");

  for (int32_t a=0; a<joy_data[slot].num_axes; a++) {
    printf("  Axis %02d %5s : ", a, joy_data[slot].axes[a].name);
    printf("Slope 8 = %4u ", joy_data[slot].axes[a].acorn_slope_8);
    if (joy_data[slot].axes[a].acorn_slope_div_8)
      printf("(div), ");
    else
      printf("(mul), ");

    printf("Slope 16 = %4u ", joy_data[slot].axes[a].acorn_slope_16);
    if (joy_data[slot].axes[a].acorn_slope_div_16)
      printf("(div), ");
    else
      printf("(mul), ");

    printf("Mouse factor = %4u, ", joy_data[slot].axes[a].mouse_factor);

    printf("SP = %6d:%6d, ", joy_data[slot].axes[a].serial_port_lower_bound, joy_data[slot].axes[a].serial_port_upper_bound);

    printf("Invert = ");
    if (joy_data[slot].axes[a].flip)
      printf(" on, ");
    else
      printf("off, ");

    struct hid_item *item = get_axis_item_by_type(slot, joy_data[slot].axes[a].type);
    if (item)
      printf("ReportId = %d", item->report_ID);
    else
      printf("ReportId = (none)");

    printf("\n");
  }

  printf("  Button ReportIds : ");
  for (int32_t a=0; a<JOY_BUTTONS; a++) {
    if (joy_data[slot].button_items[a])
      printf("%02d=%d ", a, joy_data[slot].button_items[a]->report_ID);
  }
  printf("\n");
}
