/*         ______   ___    ___ 
 *        /\  _  \ /\_ \  /\_ \ 
 *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___ 
 *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
 *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
 *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
 *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
 *                                           /\____/
 *                                           \_/__/
 *
 *      Windows joystick high-level helper functions.
 *
 *      By Eric Botcazou.
 *
 *      Based on code by Stefan Schimanski.
 *
 *      See readme.txt for copyright information.
 */


#include "allegro.h"
#include "allegro/internal/aintern.h"
#include "allegro/platform/aintwin.h"

#ifndef SCAN_DEPEND
   #ifdef ALLEGRO_MINGW32
      #undef MAKEFOURCC
   #endif

   #include <mmsystem.h>
#endif

#ifndef ALLEGRO_WINDOWS
   #error something is wrong with the makefile
#endif


static char name_x[] = "X";
static char name_y[] = "Y";
static char name_stick[] = "stick";
static char name_throttle[] = "throttle";
static char name_rudder[] = "rudder";
static char name_slider[] = "slider";
static char name_hat[] = "hat";
static char *name_b[MAX_JOYSTICK_BUTTONS] = {
   "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8",
   "B9", "B10", "B11", "B12", "B13", "B14", "B15", "B16",
   "B17", "B18", "B19", "B20", "B21", "B22", "B23", "B24",
   "B25", "B26", "B27", "B28", "B29", "B30", "B31", "B32"
};

#define JOY_POVFORWARD_WRAP  36000



/* win_update_joystick_status:
 *  Updates the specified joystick info structure by translating
 *  Windows joystick status into Allegro joystick status.
 */
int win_update_joystick_status(int n, WINDOWS_JOYSTICK_INFO *win_joy)
{
   int n_stick, n_axis, n_but, max_stick, win_axis, p;

   if (n >= num_joysticks)
      return -1;

   /* sticks */
   n_stick = 0;
   win_axis = 0;

   /* skip hat at this point, it will be handled later */
   if (win_joy->caps & JOYCAPS_HASPOV)
      max_stick = joy[n].num_sticks - 1;
   else
      max_stick = joy[n].num_sticks;

   for (n_stick = 0; n_stick < max_stick; n_stick++) {
      for (n_axis = 0; n_axis < joy[n].stick[n_stick].num_axis; n_axis++) {
         p = win_joy->axis[win_axis];

         /* set pos of analog stick */
         if (joy[n].stick[n_stick].flags & JOYFLAG_ANALOGUE) {
            if (joy[n].stick[n_stick].flags & JOYFLAG_SIGNED)
               joy[n].stick[n_stick].axis[n_axis].pos = p - 128;
            else
               joy[n].stick[n_stick].axis[n_axis].pos = p;
         }

         /* set pos of digital stick */
         if (joy[n].stick[n_stick].flags & JOYFLAG_DIGITAL) {
            if (p < 64)
               joy[n].stick[n_stick].axis[n_axis].d1 = TRUE;
            else
               joy[n].stick[n_stick].axis[n_axis].d1 = FALSE;

            if (p > 192)
               joy[n].stick[n_stick].axis[n_axis].d2 = TRUE;
            else
               joy[n].stick[n_stick].axis[n_axis].d2 = FALSE;
         }

         win_axis++;
      }
   }

   /* hat */
   if (win_joy->caps & JOYCAPS_HASPOV) {
      /* emulate analog joystick */
      joy[n].stick[n_stick].axis[0].pos = 0;
      joy[n].stick[n_stick].axis[1].pos = 0;

      /* left */
      if ((win_joy->hat > JOY_POVBACKWARD) && (win_joy->hat < JOY_POVFORWARD_WRAP)) {
         joy[n].stick[n_stick].axis[0].d1 = TRUE;
         joy[n].stick[n_stick].axis[0].pos = -128;
      }
      else {
         joy[n].stick[n_stick].axis[0].d1 = FALSE;
      }

      /* right */
      if ((win_joy->hat > JOY_POVFORWARD) && (win_joy->hat < JOY_POVBACKWARD)) {
         joy[n].stick[n_stick].axis[0].d2 = TRUE;
         joy[n].stick[n_stick].axis[0].pos = +128;
      }
      else {
         joy[n].stick[n_stick].axis[0].d2 = FALSE;
      }

      /* forward */
      if (((win_joy->hat > JOY_POVLEFT) && (win_joy->hat <= JOY_POVFORWARD_WRAP)) ||
          ((win_joy->hat >= JOY_POVFORWARD) && (win_joy->hat < JOY_POVRIGHT))) {
         joy[n].stick[n_stick].axis[1].d1 = TRUE;
         joy[n].stick[n_stick].axis[1].pos = -128;
      }
      else {
         joy[n].stick[n_stick].axis[1].d1 = FALSE;
      }

      /* backward */
      if ((win_joy->hat > JOY_POVRIGHT) && (win_joy->hat < JOY_POVLEFT)) {
         joy[n].stick[n_stick].axis[1].d2 = TRUE;
         joy[n].stick[n_stick].axis[1].pos = +128;
      }
      else {
         joy[n].stick[n_stick].axis[1].d2 = FALSE;
      }
   }

   /* buttons */
   for (n_but = 0; n_but < win_joy->num_buttons; n_but++)
      joy[n].button[n_but].b = win_joy->button[n_but];

   return 0;
}



/* win_add_joystick:
 *  Adds a new joystick (fills in a new joystick info structure).
 */
int win_add_joystick(WINDOWS_JOYSTICK_INFO *win_joy)
{
   int n_stick, n_but, max_stick, win_axis;

   if (num_joysticks == MAX_JOYSTICKS-1)
      return -1;

   joy[num_joysticks].flags = JOYFLAG_ANALOGUE | JOYFLAG_DIGITAL;

   /* how many sticks ? */
   n_stick = 0;

   if (win_joy->num_axes > 0) {
      win_axis = 0;

      /* main analogue stick */
      if (win_joy->num_axes > 1) {
         joy[num_joysticks].stick[n_stick].flags = JOYFLAG_DIGITAL | JOYFLAG_ANALOGUE | JOYFLAG_SIGNED;
         joy[num_joysticks].stick[n_stick].axis[0].name = (win_joy->axis_name[0] ? win_joy->axis_name[0] : name_x);
         joy[num_joysticks].stick[n_stick].axis[1].name = (win_joy->axis_name[1] ? win_joy->axis_name[1] : name_y);
         joy[num_joysticks].stick[n_stick].name = name_stick;

         /* Z-axis: throttle */
         if (win_joy->caps & JOYCAPS_HASZ) {
            joy[num_joysticks].stick[n_stick].num_axis = 3;
            joy[num_joysticks].stick[n_stick].axis[2].name = (win_joy->axis_name[2] ? win_joy->axis_name[2] : name_throttle);
            win_axis += 3;
         }
         else {
            joy[num_joysticks].stick[n_stick].num_axis = 2;
            win_axis += 2;
         }

         n_stick++;
      }

      /* first 1-axis stick: rudder */
      if (win_joy->caps & JOYCAPS_HASR) {
         joy[num_joysticks].stick[n_stick].flags = JOYFLAG_DIGITAL | JOYFLAG_ANALOGUE | JOYFLAG_UNSIGNED;
         joy[num_joysticks].stick[n_stick].num_axis = 1;
         joy[num_joysticks].stick[n_stick].axis[0].name = "";
         joy[num_joysticks].stick[n_stick].name = (win_joy->axis_name[win_axis] ? win_joy->axis_name[win_axis] : name_rudder);
         win_axis++;
         n_stick++;
      }

      max_stick = (win_joy->caps & JOYCAPS_HASPOV ? MAX_JOYSTICK_STICKS-1 : MAX_JOYSTICK_STICKS);

      /* other 1-axis sticks: sliders */
      while ((win_axis < win_joy->num_axes) && (n_stick < max_stick)) {
         joy[num_joysticks].stick[n_stick].flags = JOYFLAG_DIGITAL | JOYFLAG_ANALOGUE | JOYFLAG_UNSIGNED;
         joy[num_joysticks].stick[n_stick].num_axis = 1;
         joy[num_joysticks].stick[n_stick].axis[0].name = "";
         joy[num_joysticks].stick[n_stick].name = (win_joy->axis_name[win_axis] ? win_joy->axis_name[win_axis] : name_slider);
         win_axis++;
         n_stick++;
      }

      /* hat */
      if (win_joy->caps & JOYCAPS_HASPOV) {
         joy[num_joysticks].stick[n_stick].flags = JOYFLAG_DIGITAL | JOYFLAG_SIGNED;
         joy[num_joysticks].stick[n_stick].num_axis = 2;
         joy[num_joysticks].stick[n_stick].axis[0].name = "left/right";
         joy[num_joysticks].stick[n_stick].axis[1].name = "up/down";
         joy[num_joysticks].stick[n_stick].name = (win_joy->hat_name ? win_joy->hat_name : name_hat);
         n_stick++;
      }
   }

   joy[num_joysticks].num_sticks = n_stick;

   /* how many buttons ? */
   joy[num_joysticks].num_buttons = win_joy->num_buttons;

   /* fill in the button names */
   for (n_but = 0; n_but < joy[num_joysticks].num_buttons; n_but++)
      joy[num_joysticks].button[n_but].name = (win_joy->button_name[n_but] ? win_joy->button_name[n_but] : name_b[n_but]);

   num_joysticks++;

   return 0;
}



/* win_remove_all_joysticks:
 *  Removes all registered joysticks.
 */
void win_remove_all_joysticks(void)
{
   num_joysticks = 0;
}
