/*****************************************************************************
 * $LastChangedDate: 2011-04-23 21:07:07 -0400 (Sat, 23 Apr 2011) $
 * @file
 * @author  Jim E. Brooks  http://www.palomino3d.org
 * @brief   Joystick device class (SDL).
 *//*
 * LEGAL:   COPYRIGHT (C) 2009 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE VERSION 2 (GPL 2).
 *****************************************************************************/

#if COMPILE_SDL

#define INPUT_DEVICE_JOYSTICK_SDL_CC 1
#if VERBOSE
#define JOYSTICK_VERBOSE 1
#endif
#include "base/module.hh"
#include "base/conf.hh"
#include "base/stream.hh"
using namespace base;
#include "glue/module.hh"
#include "glue/sdl_queue.hh"
using namespace glue;
#include "input/module.hh"
#include "input/conf.hh"
#include "input/device_joystick.hh"
#include "input/device_joystick_sdl.hh"

namespace input {

////////////////////////////////////////////////////////////////////////////////
/////////////////////////  JoystickDeviceSDL  //////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/*****************************************************************************
 * ctor/dtor.
 *****************************************************************************/
JoystickDeviceSDL::JoystickDeviceSDL( void )
:   mJoystickNum(INPUT_CONF.mJoystickNum),
    mJoystickSDL(NULL)  // SDL might return NULL
{
    // NOP
}

JoystickDeviceSDL::~JoystickDeviceSDL()
{
    // NOP
}

/*****************************************************************************
 * Open SDL joystick device.
 *****************************************************************************/
bool
JoystickDeviceSDL::Open( void )
{
ASSERT( mJoystickNum < 20 );

    if ( mJoystickSDL == NULL )
    {
        // Try to open joystick device.
        mJoystickSDL = SDL_JoystickOpen( mJoystickNum );  // might return NULL

        // Enable joystick events.
        SDL_JoystickEventState( (mJoystickSDL != NULL) ? SDL_ENABLE : SDL_IGNORE );
    }

    return mJoystickSDL != NULL;
}

/*****************************************************************************
 * Close SDL joystick device.
 *****************************************************************************/
void
JoystickDeviceSDL::Close( void )
{
    if ( mJoystickSDL != NULL )
    {
        SDL_JoystickEventState( SDL_IGNORE );
        SDL_JoystickClose( mJoystickSDL.PTR() );
        mJoystickSDL = NULL;  // remember it was closed
    }
}

/*****************************************************************************
 * Dequeue one event from SDL driver and enqueue.
 * @return False if no more events.
 *****************************************************************************/
bool
JoystickDeviceSDL::PollJoystickDevice( JoystickEvent& event /*OUT*/ )
{
    // Base Joystick ensures this isn't recursed (busy flag).

    // Clear caller's Event in case false no more events.
    event.Clear();

    // Careful.
    if ( mJoystickSDL == NULL )
        return false;

    // Try to dequeue next joystick event from the higher-level queue of SDL events.
    SDL_Event eventSDL; 
    if ( not GET_SDL_QUEUE().DequeueJoystickEvent( eventSDL ) )
        return false;

    // Which kind of joystick event?
    switch ( eventSDL.type )
    {
        case SDL_JOYAXISMOTION:
        {
            // Is this the joystick being used?
            if ( eventSDL.jaxis.which == mJoystickNum )
            {
                // Convert event struct.
                event.mAxis    = eventSDL.jaxis.axis;
                event.mAxisVal = eventSDL.jaxis.value;

                // Clamp axis range.  SDL can return 0x8000 which is one too many.
                if ( event.mAxisVal <= -0x8000 )
                    event.mAxisVal = -0x7fff;
                else if (event.mAxisVal >= 0x8000 )
                    event.mAxisVal = 0x7fff;

                #if JOYSTICK_VERBOSE
                CLOG << "SDL joystick axis=" << event.mAxis << " axisVal=" << event.mAxisVal << std::endl;
                #endif

                return true;
            }
        }
        break;

        case SDL_JOYBUTTONUP:
        case SDL_JOYBUTTONDOWN:
        {
            // Is this the joystick being used?
            if ( eventSDL.jbutton.which == mJoystickNum )
            {
                // Convert event struct.
                event.mButton    = eventSDL.jbutton.button;
                event.mButtonVal = (eventSDL.jbutton.state == SDL_PRESSED);

                #if JOYSTICK_VERBOSE
                CLOG << "SDL joystick button=" << event.mButton << " buttonVal=" << event.mButtonVal << std::endl;
                #endif

                return true;
            }
        }
        break;

        default: // NOP
        break;
    }

    // No joystick event.
    return false;
}

/*****************************************************************************
 * Print status of joystick.
 *****************************************************************************/
void
JoystickDeviceSDL::PrintStatus( void )
{
    if ( not BASE_CONF.mQuiet )
    {
        if ( IfEnabled() )
        {
            const char* joystickName = SDL_JoystickName( mJoystickNum );
            if ( joystickName != NULL )
                CLOG << "Enabled SDL joystick " << mJoystickNum << " '" << joystickName << "'." << std::endl;
            else
                CLOG << "Enabled SDL joystick " << mJoystickNum;
        }
        else
        {
            CLOG << "SDL joystick " << mJoystickNum << " not detected." << std::endl;
        }
    }
}

} // namespace input

#endif // COMPILE_SDL
