/*
 * sdl_joystick.c - SDL joystick handling
 *
 * Copyright (C) 1999-2005  Id Software, Inc.
 * Copyright (C) 2005       Damien Thebault <damien.thebault@laposte.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "../client/client.h"
#include "sdl_local.h"

#include "SDL.h"

// from sdl_glimp.c
extern cvar_t *  in_joythreshold;


/**********************************************/
/* Joystick routines.                         */
/**********************************************/

int in_jnum=0; // number of joysticks
SDL_Joystick **in_joysticks=NULL; // array of SDL_Joystick*

void IN_StartupJoystick( void )
{
	int i;
	
	if( SDL_Init( SDL_INIT_JOYSTICK ) != 0 )
	{
		fprintf( stderr, "Joystick init error : %s\n", SDL_GetError() );
		return;
	}
	
	in_jnum = SDL_NumJoysticks();
	
	if( in_jnum > 0 )
		in_joysticks = (SDL_Joystick **)malloc(in_jnum * sizeof(SDL_Joystick *));
	
	if( in_joysticks == NULL )
		in_jnum = 0;
	
	if( in_jnum == 0 )
	{
		Com_Printf("No joystick found\n", in_jnum );
	}
	else
	{
		Com_Printf("Found %d joystick%s :\n", in_jnum, in_jnum>1?"s":"" );
		
		for(i=0 ; i<in_jnum ; i++)
		{
			Com_Printf("- %s\n", SDL_JoystickName(i) );
			in_joysticks[i] = SDL_JoystickOpen(i);
		}
		
		// Enable joystick events
		SDL_JoystickEventState( SDL_ENABLE );
	}
}

/*you can turn on some debugging and verbose of the joystick code with #define JOY_DBG*/
//#define JOY_DBG

void IN_JoyEvent( SDL_Event jevent )
{
	float jval;
	int jbutton;
	int i;
	switch( jevent.type )
	{
		case SDL_JOYAXISMOTION:
			
			if( jevent.jaxis.which >= in_jnum ) // joystick out of the array
				return;
			
			// compute axis button number because quake handle buttons only
			//   axis offset : jevent.jaxis.axis*2 because each axis has 2 "axis buttons"
			//   joystick button offset : SDL_JoystickNumButtons(in_joysticks[jevent.jaxis.which])
			//   each joystick has his own buttons
			//          For example :
			//          Joy 0 with 4 buttons 2 axis : Buttons 0->3 Axis  4->7
			//          Joy 1 with 2 buttons 3 axis : Buttons 8->9 Axis 10->15
			
			jbutton = 0;
			for( i=0 ; i<jevent.jaxis.which ; i++ ) //for each jostick before the triggered one
			{
				jbutton += SDL_JoystickNumButtons(in_joysticks[i]);  // joystick #i buttons
				jbutton += 2 * SDL_JoystickNumAxes(in_joysticks[i]); // joystick #i axis
			}
			
			jbutton += SDL_JoystickNumButtons(in_joysticks[jevent.jaxis.which]); // current joystick buttons
			jbutton += 2 * jevent.jaxis.axis;                                    // current joystick axis
			
			jval = jevent.jaxis.value/32767.0; // -1.0 <= jval <= 1.0
			if( jval < -in_joythreshold->value || jval > in_joythreshold->value )
			{
				// if jval>0 : "axis button" #1
				// else, "axis button" #0
				if( jval>0 ) jbutton ++;
				Sys_QueEvent( 0, SE_KEY, K_JOY1 + jbutton , qtrue, 0, NULL );
#ifdef JOY_DBG
	printf( "Joystick %d axis %d : %f (button #%d down)\n", jevent.jaxis.which, jevent.jaxis.axis, jval, jbutton );
#endif
			}
			else
			{
				// the two "axis buttons" are set to false
				Sys_QueEvent( 0, SE_KEY, K_JOY1 + jbutton , qfalse, 0, NULL );
				Sys_QueEvent( 0, SE_KEY, K_JOY1 + jbutton + 1 , qfalse, 0, NULL );
#ifdef JOY_DBG
	printf( "Joystick %d axis %d : %f (buttons #%d and #%d up)\n",
		jevent.jaxis.which, jevent.jaxis.axis, jval, jbutton, jbutton+1 );
#endif
			}
		break;

		case SDL_JOYBUTTONDOWN:
		case SDL_JOYBUTTONUP:
			jbutton = 0;
			for( i=0 ; i<jevent.jaxis.which ; i++ ) //for each jostick before the triggered one
			{
				jbutton += SDL_JoystickNumButtons(in_joysticks[i]);  // joystick #i buttons
				jbutton += 2 * SDL_JoystickNumAxes(in_joysticks[i]); // joystick #i axis
			}
			
			jbutton += jevent.jbutton.button; // current joystick button
			
			Sys_QueEvent( 0, SE_KEY, K_JOY1 + jbutton, jevent.jbutton.state, 0, NULL );
#ifdef JOY_DBG
	printf( "Joystick %d button %d : %s (buttons #%d down)\n",
		jevent.jaxis.which, jevent.jbutton.button, jevent.jbutton.state==qtrue?"down":"up", jbutton );
#endif
		break;
	}
}

void IN_ShutdownJoystick()
{
	int i;
	if( in_jnum > 0 )
	{
		for( i=0 ; i<in_jnum ; i++ )
		{
			SDL_JoystickClose( in_joysticks[i] );
		}
		free( in_joysticks );
		in_joysticks = NULL;
		in_jnum = 0;
		SDL_JoystickEventState( SDL_IGNORE );
	}
}

