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

#include "debugrep.h"
#include "usbjoystick.h"
#include "adc.h"

#include "joyhelp.h"

//extern const uint32_t supported_axes_usage[];

// supported usb hid axes codes (not including HAT or DPAD)
// also note mapping to our own type codes
const uint32_t supported_axes_usage[] = {
  [HUG_X] = AXIS_X,
  [HUG_Y] = AXIS_Y,
  [HUG_Z] = AXIS_Z,
  [HUG_RX] = AXIS_RX,
  [HUG_RY] = AXIS_RY,
  [HUG_RZ] = AXIS_RZ,
  [HUG_SLIDER] = AXIS_SLIDER,
};

//IGNORE(supported_axes_usage);

const char *axes_names[] = {
  [AXIS_HATX] = "HATX",
  [AXIS_HATY] = "HATY",
  [AXIS_DPADX] = "DPADX",
  [AXIS_DPADY] = "DPADY",
  [AXIS_X] = "X",
  [AXIS_Y] = "Y",
  [AXIS_Z] = "Z",
  [AXIS_RX] = "RX",
  [AXIS_RY] = "RY",
  [AXIS_RZ] = "RZ",
  [AXIS_SLIDER] = "S",
};

//IGNORE(axes_names);



struct hid_item *get_axis_item_by_type(uint32_t i, uint32_t type) {
  switch (type)
  {
    case AXIS_HATX:
    case AXIS_HATY:
      return joy_data[i].hat_item;

    case AXIS_DPADX:
      return joy_data[i].dpad_left_item;

    case AXIS_DPADY:
      return joy_data[i].dpad_up_item;

    default:
    {
      for (uint32_t a=0; a<JOY_USAGE_AXES; a++) {
        if (joy_data[i].axes_items[a]) {
          uint32_t a_usage = HID_USAGE(joy_data[i].axes_items[a]->usage);
          uint32_t a_type = supported_axes_usage[a_usage];
          if (a_type == type)
            return joy_data[i].axes_items[a];
        }
      }
      return NULL;
    }
  }
}





osbool stick_has_axis_type(struct joydata_struct *j, uint32_t type)
{
  for (uint32_t a=0; a<j->num_axes; a++) {
    if (j->axes[a].type == type)
      return TRUE;
  }
  return FALSE;
}


struct axisdata_struct *get_stick_axis(struct joydata_struct *j, uint32_t type)
{
  for (uint32_t a=0; a<j->num_axes; a++) {
    if (j->axes[a].type == type)
      return &(j->axes[a]);
  }
  return NULL;
}





struct joydata_struct *get_stick(uint32_t id)
{
  for (uint32_t i=0; i<JOY_MAX; i++) {
    if (joy_data[i].mapped_number == id) {
      return &joy_data[i];
    }
  }
  return NULL;
}












struct hid_item *itemdup(struct hid_item *s)
{
  struct hid_item *t;

  t = malloc(sizeof(*t));
  if (t == NULL)
  {
    debug_printf("itemdup: Error: Not enough memory for joystick\n");
    return NULL;
  }

  memcpy(t, s, sizeof(*t));

  return t;
}




uint32_t next_available_joystick_index(void)
{
  for (uint32_t i=0; i<JOY_MAX; i++)
  {
    if (joy_data[i].in_use == FALSE)
      return i;
  }
  return NONE_AVAILABLE;
}




void clean_joystick_data(void)
{
  for (uint32_t i=0; i<JOY_MAX; i++)
    clean_joystick_data_item(i);

  for (uint32_t c=0; c<ADC_CHANNELS; c++) {
    adc_map.channels[c].joy_id = NOT_MAPPED;
    adc_map.channels[c].axis = NOT_MAPPED;
    adc_map.channels[c].start = 0;
    adc_map.channels[c].end = 0;
    adc_map.channels[c].slope = 1;
    adc_map.channels[c].flip = FALSE;
    adc_map.channels[c].slope_div = FALSE;
    adc_data.channel_values[c] = 0;
  }

  for (uint32_t b=0; b<ADC_BUTTONS; b++) {
    adc_map.buttons[b].joy_id = NOT_MAPPED;
    adc_map.buttons[b].button = NOT_MAPPED;
    adc_data.button_values[b] = 0;
  }

  adc_data.channels_to_be_sampled = ADC_CHANNELS;
  adc_data.current_channel = 1;   // todo: is this a sensible initial state???
}





void clean_joystick_data_item(uint32_t i)
{
  uint32_t j;

  joy_data[i].report_length = 0;

  joy_data[i].has_report_id = FALSE;

  joy_data[i].device = NULL;

  free(joy_data[i].data_buf);
  joy_data[i].data_buf = NULL;

  for (j=0; j<JOY_AXES; j++) {
    free(joy_data[i].axes_items[j]);
    joy_data[i].axes_items[j] = NULL;
  }

  for (j=0; j<JOY_BUTTONS; j++) {
    free(joy_data[i].button_items[j]);
    joy_data[i].button_items[j] = NULL;
  }

  free(joy_data[i].hat_item);
  free(joy_data[i].dpad_up_item);
  free(joy_data[i].dpad_down_item);
  free(joy_data[i].dpad_left_item);
  free(joy_data[i].dpad_right_item);
  joy_data[i].hat_item = NULL;
  joy_data[i].dpad_up_item = NULL;
  joy_data[i].dpad_down_item = NULL;
  joy_data[i].dpad_left_item = NULL;
  joy_data[i].dpad_right_item = NULL;

  // these will only be valid if we actually have a HAT/DPAD
  joy_data[i].hat_axis = 0;
  joy_data[i].dpad_axis = 0;

  joy_data[i].has_dpad = FALSE;
  joy_data[i].has_hat = FALSE;

  joy_data[i].num_axes = 0;
  joy_data[i].num_buttons = 0;

  for (j=0; j<JOY_AXES; j++) {
    joy_data[i].axes[j].val = 0;
    joy_data[i].axes[j].min = 0;
    joy_data[i].axes[j].mid = 0;
    joy_data[i].axes[j].max = 0;
    joy_data[i].axes[j].acorn_slope_8 = 1;
    joy_data[i].axes[j].acorn_slope_div_8 = FALSE;
    joy_data[i].axes[j].acorn_slope_16 = 1;
    joy_data[i].axes[j].acorn_slope_div_16 = FALSE;
    joy_data[i].axes[j].pc_slope = 1;
    joy_data[i].axes[j].pc_slope_div = FALSE;
    joy_data[i].axes[j].mouse_factor = 1;
    joy_data[i].axes[j].mouse_sensitivity = 1;
    joy_data[i].axes[j].serial_port_upper_bound = 0;
    joy_data[i].axes[j].serial_port_lower_bound = 0;
    joy_data[i].axes[j].is_digital = FALSE;
    joy_data[i].axes[j].name = NULL;
    joy_data[i].axes[j].flip = FALSE;
  }

  for (j=0; j<JOY_BUTTONS; j++)
    joy_data[i].buttons[j] = 0;

  joy_data[i].in_use = FALSE;

  joy_data[i].open = FALSE;

  for (j=0; j<USB_DEVICE_NAME_LENGTH; j++)
    joy_data[i].device_name[j] = NULL;

  joy_data[i].interface = 0;
  joy_data[i].endpoint = 0;

  for (j=0; j<USB_DEVICEFS_PATH_MAX_LENGTH; j++)
    joy_data[i].usb_path[j] = NULL;

  joy_data[i].fp = NULL;
  joy_data[i].devicefs_handle = NULL;
  joy_data[i].buffer_handle = NULL;
  joy_data[i].buffer_internal_id = NULL;
  joy_data[i].buffer_service_routine = NULL;
  joy_data[i].buffer_workspace = NULL;

  joy_data[i].upcalls = 0;
  joy_data[i].upcalls_delta = 0;

  for (j=0; j<USB_MAX_STRING_LEN; j++) {
    joy_data[i].manufacturer[j] = NULL;
    joy_data[i].product[j] = NULL;
    joy_data[i].serial[j] = NULL;
  }

  joy_data[i].vendor_id = 0;
  joy_data[i].product_id = 0;
  joy_data[i].device_id = 0;

  joy_data[i].good_reads = 0;
  joy_data[i].good_reads_delta = 0;

  joy_data[i].bad_reads = 0;
  joy_data[i].bad_reads_delta = 0;

  joy_data[i].mapped_number = NOT_MAPPED;

  joy_data[i].mapped_x_8 = NOT_MAPPED;
  joy_data[i].mapped_y_8 = NOT_MAPPED;
  joy_data[i].mapped_x_16 = NOT_MAPPED;
  joy_data[i].mapped_y_16 = NOT_MAPPED;

  joy_data[i].mapped_mouse_x = NOT_MAPPED;
  joy_data[i].mapped_mouse_y = NOT_MAPPED;
  joy_data[i].mapped_mouse_select = NOT_MAPPED;
  joy_data[i].mapped_mouse_menu = NOT_MAPPED;
  joy_data[i].mapped_mouse_adjust = NOT_MAPPED;

  joy_data[i].key_up = NOT_MAPPED;
  joy_data[i].key_down = NOT_MAPPED;
  joy_data[i].key_left = NOT_MAPPED;
  joy_data[i].key_right = NOT_MAPPED;

  for (j=0; j<JOY_BUTTONS; j++) {
    joy_data[i].key_buttons[j] = NOT_MAPPED;
    joy_data[i].mapped_buttons[j] = NOT_MAPPED;
  }

}





int32_t round_up_down(float n)
{
  int32_t i = (int)(n < 0 ? (n - 0.5) : (n + 0.5));
  return i;
}



