#include "sysconfig.h"
#include "sysdeps.h"
#include "config.h"
#include "options.h"
#include "keyboard.h"
#include "inputdevice.h"
#include <SDL.h>


static int joyXviaCustom = 0;
static int joyYviaCustom = 0;
static int joyButXviaCustom[7] = { 0, 0, 0, 0, 0, 0, 0};
static int mouseBut1viaCustom = 0;
static int mouseBut2viaCustom = 0;


#define MAX_MOUSE_BUTTONS	2
#define MAX_MOUSE_AXES	2
#define FIRST_MOUSE_AXIS	0
#define FIRST_MOUSE_BUTTON	MAX_MOUSE_AXES


static int init_mouse (void) 
{
  return 1;
}

static void close_mouse (void) 
{
}

static int acquire_mouse (int num, int flags) 
{
  return 1;
}

static void unacquire_mouse (int num) 
{
}

static int get_mouse_num (void)
{
  return 2;
}

static TCHAR *get_mouse_friendlyname (int mouse)
{
  if(mouse == 0)
    return "Nubs as mouse";
  else
    return "dPad as mouse";
}

static TCHAR *get_mouse_uniquename (int mouse)
{
  if(mouse == 0)
    return "MOUSE0";
  else
    return "MOUSE1";
}

static int get_mouse_widget_num (int mouse)
{
  return MAX_MOUSE_AXES + MAX_MOUSE_BUTTONS;
}

static int get_mouse_widget_first (int mouse, int type)
{
  switch (type) {
  	case IDEV_WIDGET_BUTTON:
	    return FIRST_MOUSE_BUTTON;
	  case IDEV_WIDGET_AXIS:
	    return FIRST_MOUSE_AXIS;
  	case IDEV_WIDGET_BUTTONAXIS:
  	  return MAX_MOUSE_AXES + MAX_MOUSE_BUTTONS; 
  }
  return -1;
}

static int get_mouse_widget_type (int mouse, int num, TCHAR *name, uae_u32 *code)
{
  if (num >= MAX_MOUSE_AXES && num < MAX_MOUSE_AXES + MAX_MOUSE_BUTTONS) {
  	if (name)
	    sprintf (name, "Button %d", num + 1 - MAX_MOUSE_AXES);
	  return IDEV_WIDGET_BUTTON;
  } else if (num < MAX_MOUSE_AXES) {
	  if (name) {
	    if(num == 0)
	      sprintf (name, "X Axis");
	    else if (num == 1)
	      sprintf (name, "Y Axis");
	    else
	      sprintf (name, "Axis %d", num + 1);
	  }
	  return IDEV_WIDGET_AXIS;
  }
  return IDEV_WIDGET_NONE;
}

static void read_mouse (void) 
{
  if(currprefs.input_tablet > TABLET_OFF) {
    // Mousehack active
    int x, y;
    SDL_GetMouseState(&x, &y);
	  setmousestate(0, 0, x, 1);
	  setmousestate(0, 1, y, 1);
  }
  
  if(currprefs.jports[0].id == JSEM_MICE + 1 || currprefs.jports[1].id == JSEM_MICE + 1) {
    // dPad is mouse
  	Uint8 *keystate = SDL_GetKeyState(NULL);
    int mouseScale = currprefs.input_joymouse_multiplier / 4;
    
    if(keystate[VK_LEFT])
      setmousestate(1, 0, -mouseScale, 0);
    if(keystate[VK_RIGHT])
      setmousestate(1, 0, mouseScale, 0);
    if(keystate[VK_UP])
      setmousestate(1, 1, -mouseScale, 0);
    if(keystate[VK_DOWN])
      setmousestate(1, 1, mouseScale, 0);
    
    if(!mouseBut1viaCustom)
      setmousebuttonstate (1, 0, keystate[VK_A]); // A button -> left mouse
    if(!mouseBut2viaCustom)
      setmousebuttonstate (1, 1, keystate[VK_B]); // B button -> right mouse
  } 
   
  // Nubs as mouse handled in handle_msgpump()
}


static int get_mouse_flags (int num) 
{
  return 0;
}

struct inputdevice_functions inputdevicefunc_mouse = {
  init_mouse, close_mouse, acquire_mouse, unacquire_mouse, read_mouse,
  get_mouse_num, get_mouse_friendlyname, get_mouse_uniquename,
  get_mouse_widget_num, get_mouse_widget_type,
  get_mouse_widget_first,
  get_mouse_flags
};

static void setid (struct uae_input_device *uid, int i, int slot, int sub, int port, int evt, bool gp)
{
	if (gp)
		inputdevice_sparecopy (&uid[i], slot, 0);
  uid[i].eventid[slot][sub] = evt;
  uid[i].port[slot][sub] = port + 1;
}

static void setid_af (struct uae_input_device *uid, int i, int slot, int sub, int port, int evt, int af, bool gp)
{
  setid (uid, i, slot, sub, port, evt, gp);
  uid[i].flags[slot][sub] &= ~ID_FLAG_AUTOFIRE_MASK;
  if (af >= JPORT_AF_NORMAL)
    uid[i].flags[slot][sub] |= ID_FLAG_AUTOFIRE;
}

int input_get_default_mouse (struct uae_input_device *uid, int i, int port, int af, bool gp, bool wheel, bool joymouseswap)
{
  setid (uid, i, ID_AXIS_OFFSET + 0, 0, port, port ? INPUTEVENT_MOUSE2_HORIZ : INPUTEVENT_MOUSE1_HORIZ, gp);
  setid (uid, i, ID_AXIS_OFFSET + 1, 0, port, port ? INPUTEVENT_MOUSE2_VERT : INPUTEVENT_MOUSE1_VERT, gp);
  setid_af (uid, i, ID_BUTTON_OFFSET + 0, 0, port, port ? INPUTEVENT_JOY2_FIRE_BUTTON : INPUTEVENT_JOY1_FIRE_BUTTON, af, gp);
  setid (uid, i, ID_BUTTON_OFFSET + 1, 0, port, port ? INPUTEVENT_JOY2_2ND_BUTTON : INPUTEVENT_JOY1_2ND_BUTTON, gp);

  if (i == 0)
    return 1;
  return 0;
}


static int init_kb (void)
{
  return 1;
}

static void close_kb (void)
{
}

static int acquire_kb (int num, int flags)
{
  return 1;
}

static void unacquire_kb (int num)
{
}

static void read_kb (void)
{
}

static int get_kb_num (void) 
{
  return 1;
}

static TCHAR *get_kb_friendlyname (int kb) 
{
  return strdup("Default Keyboard");
}

static TCHAR *get_kb_uniquename (int kb) 
{
  return strdup("KEYBOARD0");
}

static int get_kb_widget_num (int kb) 
{
  return 255;
}

static int get_kb_widget_first (int kb, int type) 
{
  return 0;
}

static int get_kb_widget_type (int kb, int num, TCHAR *name, uae_u32 *code) 
{
  if(code)
    *code = num;
  return IDEV_WIDGET_KEY;
}

static int get_kb_flags (int num) 
{
  return 0;
}

struct inputdevice_functions inputdevicefunc_keyboard = {
	init_kb, close_kb, acquire_kb, unacquire_kb, read_kb,
	get_kb_num, get_kb_friendlyname, get_kb_uniquename,
	get_kb_widget_num, get_kb_widget_type,
	get_kb_widget_first,
	get_kb_flags
};

int input_get_default_keyboard (int num) 
{
  if (num == 0) {
    return 1;
  }
  return 0;
}


#define MAX_JOY_BUTTONS	7
#define MAX_JOY_AXES	2
#define FIRST_JOY_AXIS	0
#define FIRST_JOY_BUTTON	MAX_JOY_AXES


static int nr_joysticks = 0;
static char JoystickName[MAX_INPUT_DEVICES][80];

static char IsPS3Controller[MAX_INPUT_DEVICES];

static SDL_Joystick* Joysticktable[MAX_INPUT_DEVICES];


static int get_joystick_num (void)
{
  // Keep joystick 0 as Pandora implementation...
  return (nr_joysticks + 1);
}

static int init_joystick (void)
{
  //This function is called too many times... we can filter if number of joy is good...
  if (nr_joysticks == SDL_NumJoysticks ())
    return 1;

  nr_joysticks = SDL_NumJoysticks ();
  if (nr_joysticks > MAX_INPUT_DEVICES)
    nr_joysticks = MAX_INPUT_DEVICES;
  for (int cpt; cpt < nr_joysticks; cpt++)
  {
    Joysticktable[cpt] = SDL_JoystickOpen (cpt);
    strncpy(JoystickName[cpt],SDL_JoystickName(cpt),80);
    printf("Joystick %i : %s\n",cpt,JoystickName[cpt]);
    printf("    Buttons: %i Axis: %i Hats: %i\n",SDL_JoystickNumButtons(Joysticktable[cpt]),SDL_JoystickNumAxes(Joysticktable[cpt]),SDL_JoystickNumHats(Joysticktable[cpt]));

    if (strcmp(JoystickName[cpt],"Sony PLAYSTATION(R)3 Controller") == 0 ||
            strcmp(JoystickName[cpt],"PLAYSTATION(R)3 Controller") == 0)
    {
      printf("    Found a dualshock controller: Activating workaround.\n");
      IsPS3Controller[cpt] = 1;
    }
    else
      IsPS3Controller[cpt] = 0;
  }

  return 1;
}

static void close_joystick (void)
{
  for (int cpt; cpt < nr_joysticks; cpt++)
  {
	SDL_JoystickClose (Joysticktable[cpt]);
  }
}


static int acquire_joystick (int num, int flags)
{
  return 1;
}

static void unacquire_joystick (int num)
{
}

static TCHAR *get_joystick_friendlyname (int joy)
{
  if (joy == 0) 
    return "dPad as joystick";
  else
    return JoystickName[joy - 1];
}

static TCHAR *get_joystick_uniquename (int joy)
{
  if (joy == 0)
    return "JOY0";
  if (joy == 1)
    return "JOY1";
  if (joy == 2)
    return "JOY2";
  if (joy == 3)
    return "JOY3";
  if (joy == 4)
    return "JOY4";
  if (joy == 5)
    return "JOY5";
  if (joy == 6)
    return "JOY6";

  return "JOY7";
}


static int get_joystick_widget_num (int joy)
{
  return MAX_JOY_AXES + MAX_JOY_BUTTONS;
}

static int get_joystick_widget_first (int joy, int type)
{
  switch (type) {
  	case IDEV_WIDGET_BUTTON:
	    return FIRST_JOY_BUTTON;
	  case IDEV_WIDGET_AXIS:
	    return FIRST_JOY_AXIS;
  	case IDEV_WIDGET_BUTTONAXIS:
  	  return MAX_JOY_AXES + MAX_JOY_BUTTONS; 
  }
  return -1;
}

static int get_joystick_widget_type (int joy, int num, TCHAR *name, uae_u32 *code)
{
  if (num >= MAX_JOY_AXES && num < MAX_JOY_AXES + MAX_JOY_BUTTONS) {
  	if (name) {
	    switch(num)
	    {
	      case FIRST_JOY_BUTTON:
	        sprintf (name, "Button X/CD32 red");
	        break;
	      case FIRST_JOY_BUTTON + 1:
	        sprintf (name, "Button B/CD32 blue");
	        break;
	      case FIRST_JOY_BUTTON + 2:
	        sprintf (name, "Button A/CD32 green");
	        break;
	      case FIRST_JOY_BUTTON + 3:
	        sprintf (name, "Button Y/CD32 yellow");
	        break;
	      case FIRST_JOY_BUTTON + 4:
	        sprintf (name, "CD32 start");
	        break;
	      case FIRST_JOY_BUTTON + 5:
	        sprintf (name, "CD32 ffw");
	        break;
	      case FIRST_JOY_BUTTON + 6:
	        sprintf (name, "CD32 rwd");
	        break;
	    }
	  }
	  return IDEV_WIDGET_BUTTON;
  } else if (num < MAX_JOY_AXES) {
	  if (name) {
	    if(num == 0)
	      sprintf (name, "X Axis");
	    else if (num == 1)
	      sprintf (name, "Y Axis");
	    else
	      sprintf (name, "Axis %d", num + 1);
	  }
	  return IDEV_WIDGET_AXIS;
  }
  return IDEV_WIDGET_NONE;
}

static int get_joystick_flags (int num)
{
  return 0;
}


static void read_joystick (void)
{

  for (int joyid = 0; joyid < MAX_JPORTS ; joyid ++)
  // First handle fake joystick from pandora...
  if(currprefs.jports[joyid].id == JSEM_JOYS)
  {
  	Uint8 *keystate = SDL_GetKeyState(NULL);
    
    if(!keystate[VK_R])
    { // Right shoulder + dPad -> cursor keys
      int axis = (keystate[VK_LEFT] ? -32767 : (keystate[VK_RIGHT] ? 32767 : 0));
      if(!joyXviaCustom)
        setjoystickstate (0, 0, axis, 32767);
      axis = (keystate[VK_UP] ? -32767 : (keystate[VK_DOWN] ? 32767 : 0));
      if(!joyYviaCustom)
        setjoystickstate (0, 1, axis, 32767);
    }
    if(!joyButXviaCustom[0])
      setjoybuttonstate (0, 0, keystate[VK_X]);
    if(!joyButXviaCustom[1])
      setjoybuttonstate (0, 1, keystate[VK_B]);
    if(!joyButXviaCustom[2])
      setjoybuttonstate (0, 2, keystate[VK_A]);
    if(!joyButXviaCustom[3])
      setjoybuttonstate (0, 3, keystate[VK_Y]);

    int cd32_start = 0, cd32_ffw = 0, cd32_rwd = 0;
    if(keystate[SDLK_LALT]) { // Pandora Start button
      if(keystate[VK_L])  // Left shoulder
        cd32_rwd = 1;
      else if (keystate[VK_R]) // Right shoulder
        cd32_ffw = 1;
      else
        cd32_start = 1;
    }
    if(!joyButXviaCustom[6])
      setjoybuttonstate (0, 6, cd32_start);
    if(!joyButXviaCustom[5])
      setjoybuttonstate (0, 5, cd32_ffw);
    if(!joyButXviaCustom[4])
      setjoybuttonstate (0, 4, cd32_rwd);
  }
  else if (jsem_isjoy(joyid,&currprefs) != -1)
    {
      // Now we handle real SDL joystick...
      int hostjoyid = currprefs.jports[joyid].id - JSEM_JOYS -1;
      int hat = SDL_JoystickGetHat(Joysticktable[hostjoyid],0);
      int val = SDL_JoystickGetAxis(Joysticktable[hostjoyid], 0);

      if (hat & SDL_HAT_RIGHT)
        setjoystickstate (hostjoyid + 1, 0, 32767, 32767);
      else 
      if (hat & SDL_HAT_LEFT)
        setjoystickstate (hostjoyid + 1, 0, -32767, 32767);
      else
        setjoystickstate (hostjoyid + 1, 0, val, 32767);
      val = SDL_JoystickGetAxis(Joysticktable[hostjoyid], 1);
      if (hat & SDL_HAT_UP)
         setjoystickstate (hostjoyid + 1, 1, -32767, 32767);
      else
      if (hat & SDL_HAT_DOWN) 
         setjoystickstate (hostjoyid + 1, 1, 32767, 32767);
      else
         setjoystickstate (hostjoyid + 1, 1, val, 32767);

      setjoybuttonstate (hostjoyid + 1, 0, (SDL_JoystickGetButton(Joysticktable[hostjoyid], 0) & 1) );
      setjoybuttonstate (hostjoyid + 1, 1, (SDL_JoystickGetButton(Joysticktable[hostjoyid], 1) & 1) );
      setjoybuttonstate (hostjoyid + 1, 2, (SDL_JoystickGetButton(Joysticktable[hostjoyid], 2) & 1) );
      setjoybuttonstate (hostjoyid + 1, 3, (SDL_JoystickGetButton(Joysticktable[hostjoyid], 3) & 1) );

      // cd32 start, ffw, rwd
      setjoybuttonstate (hostjoyid + 1, 4, (SDL_JoystickGetButton(Joysticktable[hostjoyid], 4) & 1) );
      setjoybuttonstate (hostjoyid + 1, 5, (SDL_JoystickGetButton(Joysticktable[hostjoyid], 5) & 1) );
      setjoybuttonstate (hostjoyid + 1, 6, (SDL_JoystickGetButton(Joysticktable[hostjoyid], 6) & 1) );

      if (IsPS3Controller[hostjoyid])
      {
        setjoybuttonstate (hostjoyid + 1, 0, (SDL_JoystickGetButton(Joysticktable[hostjoyid], 13) & 1) );
        setjoybuttonstate (hostjoyid + 1, 1, (SDL_JoystickGetButton(Joysticktable[hostjoyid], 14) & 1) );

        // Simulate a top with button 4
        if ( SDL_JoystickGetButton(Joysticktable[hostjoyid], 4))
           setjoystickstate (hostjoyid + 1, 1, -32767, 32767);
        // Simulate a right with button 5
        if ( SDL_JoystickGetButton(Joysticktable[hostjoyid], 5))
           setjoystickstate (hostjoyid + 1, 0, 32767, 32767);
        // Simulate a bottom with button 6
        if ( SDL_JoystickGetButton(Joysticktable[hostjoyid], 6))
           setjoystickstate (hostjoyid + 1, 1, 32767, 32767);
        // Simulate a left with button 7
        if ( SDL_JoystickGetButton(Joysticktable[hostjoyid], 7))
           setjoystickstate (hostjoyid + 1, 0, -32767, 32767);
      }
    }
}

struct inputdevice_functions inputdevicefunc_joystick = {
	init_joystick, close_joystick, acquire_joystick, unacquire_joystick,
	read_joystick, get_joystick_num, get_joystick_friendlyname, get_joystick_uniquename,
	get_joystick_widget_num, get_joystick_widget_type,
	get_joystick_widget_first,
	get_joystick_flags
};

int input_get_default_joystick (struct uae_input_device *uid, int num, int port, int af, int mode, bool gp, bool joymouseswap)
{
  int h, v;

  h = port ? INPUTEVENT_JOY2_HORIZ : INPUTEVENT_JOY1_HORIZ;;
  v = port ? INPUTEVENT_JOY2_VERT : INPUTEVENT_JOY1_VERT;

  setid (uid, num, ID_AXIS_OFFSET + 0, 0, port, h, gp);
  setid (uid, num, ID_AXIS_OFFSET + 1, 0, port, v, gp);

  setid_af (uid, num, ID_BUTTON_OFFSET + 0, 0, port, port ? INPUTEVENT_JOY2_FIRE_BUTTON : INPUTEVENT_JOY1_FIRE_BUTTON, af, gp);
  setid (uid, num, ID_BUTTON_OFFSET + 1, 0, port, port ? INPUTEVENT_JOY2_2ND_BUTTON : INPUTEVENT_JOY1_2ND_BUTTON, gp);
  setid (uid, num, ID_BUTTON_OFFSET + 2, 0, port, port ? INPUTEVENT_JOY2_3RD_BUTTON : INPUTEVENT_JOY1_3RD_BUTTON, gp);

  if (mode == JSEM_MODE_JOYSTICK_CD32) {
    setid_af (uid, num, ID_BUTTON_OFFSET + 0, 0, port, port ? INPUTEVENT_JOY2_CD32_RED : INPUTEVENT_JOY1_CD32_RED, af, gp);
    setid (uid, num, ID_BUTTON_OFFSET + 1, 0, port, port ? INPUTEVENT_JOY2_CD32_BLUE : INPUTEVENT_JOY1_CD32_BLUE, gp);
    setid (uid, num, ID_BUTTON_OFFSET + 2, 0, port, port ? INPUTEVENT_JOY2_CD32_GREEN : INPUTEVENT_JOY1_CD32_GREEN, gp);
    setid (uid, num, ID_BUTTON_OFFSET + 3, 0, port, port ? INPUTEVENT_JOY2_CD32_YELLOW : INPUTEVENT_JOY1_CD32_YELLOW, gp);
    setid (uid, num, ID_BUTTON_OFFSET + 4, 0, port, port ? INPUTEVENT_JOY2_CD32_RWD : INPUTEVENT_JOY1_CD32_RWD, gp);
    setid (uid, num, ID_BUTTON_OFFSET + 5, 0, port, port ? INPUTEVENT_JOY2_CD32_FFW : INPUTEVENT_JOY1_CD32_FFW, gp);
    setid (uid, num, ID_BUTTON_OFFSET + 6, 0, port, port ? INPUTEVENT_JOY2_CD32_PLAY : INPUTEVENT_JOY1_CD32_PLAY, gp);
  }
  if (num == 0) {
    return 1;
  }
  return 0;
}

int input_get_default_joystick_analog (struct uae_input_device *uid, int num, int port, int af, bool joymouseswap) 
{
  return 0;
}


void SimulateMouseOrJoy(int code, int keypressed)
{
  switch(code) {
    case REMAP_MOUSEBUTTON_LEFT:
      mouseBut1viaCustom = keypressed;
      setmousebuttonstate (0, 0, keypressed);
      setmousebuttonstate (1, 0, keypressed);
      break;
      
    case REMAP_MOUSEBUTTON_RIGHT:
      mouseBut2viaCustom = keypressed;
      setmousebuttonstate (0, 1, keypressed);
      setmousebuttonstate (1, 1, keypressed);
      break;
      
    case REMAP_JOYBUTTON_ONE:
      joyButXviaCustom[0] = keypressed;
      setjoybuttonstate (0, 0, keypressed);
      break;
      
    case REMAP_JOYBUTTON_TWO:
      joyButXviaCustom[1] = keypressed;
      setjoybuttonstate (0, 1, keypressed);
      break;
      
    case REMAP_JOY_UP:
      joyYviaCustom = keypressed;
      setjoystickstate (0, 1, keypressed ? -32767 : 0, 32767);
      break;
      
    case REMAP_JOY_DOWN:
      joyYviaCustom = keypressed;
      setjoystickstate (0, 1, keypressed ? 32767 : 0, 32767);
      break;
      
    case REMAP_JOY_LEFT:
      joyXviaCustom = keypressed;
      setjoystickstate (0, 0, keypressed ? -32767 : 0, 32767);
      break;
      
    case REMAP_JOY_RIGHT:
      joyXviaCustom = keypressed;
      setjoystickstate (0, 0, keypressed ? 32767 : 0, 32767);
      break;

    case REMAP_CD32_GREEN:
      joyButXviaCustom[2] = keypressed;
      setjoybuttonstate (0, 2, keypressed);
      break;

    case REMAP_CD32_YELLOW:
      joyButXviaCustom[3] = keypressed;
      setjoybuttonstate (0, 3, keypressed);
      break;

    case REMAP_CD32_PLAY:
      joyButXviaCustom[6] = keypressed;
      setjoybuttonstate (0, 6, keypressed);
      break;

    case REMAP_CD32_FFW:
      joyButXviaCustom[5] = keypressed;
      setjoybuttonstate (0, 5, keypressed);
      break;

    case REMAP_CD32_RWD:
      joyButXviaCustom[4] = keypressed;
      setjoybuttonstate (0, 4, keypressed);
      break;
  }  
}
