/*****************************************************************************
 * $LastChangedDate: 2011-04-23 21:07:07 -0400 (Sat, 23 Apr 2011) $
 * @file
 * @author  Jim E. Brooks  http://www.palomino3d.org
 * @brief   Interface of C functions for Lua scripts.
 * @remarks  * sim.Joystick abstracts control::Joystick.
 * This binding is unusual in that RegisterJoystick() also registers
 * a listener for the joystick button event to propagate to Lua.
 * No "dequeue axis" method is exported to Lua since the control module
 * handles axis events.
 *
 * ----------------------------
 * -- THIS IS AUTO-GENERATED --
 * ----------------------------
 *
 *//*
 * LEGAL:   COPYRIGHT (C) 2008 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE VERSION 2 (GPL 2).
 *****************************************************************************/

#include <deque>
#include "base/module.hh"
#include "base/misc.hh"
using namespace base;
#include "control/module.hh"
#include "control/joystick.hh"
using namespace control;
#include "lua_bind/module.hh"
#include "lua_bind/bind.hh"

namespace lua {


namespace bind {

#define BIND_CLASS_NAME      "Joystick"
#define BIND_METATABLE_NAME  LUABIND_METATABLE_STRING(BIND_CLASS_NAME)

#if ! DOXYGEN
////////////////////////////////////////////////////////////////////////////////
/// @brief Joystick button handler that propagates to Lua script.
/// This queues and dequeues events.
///
class ListenerJoystickButton : public Event<input::JoystickEvent>::ListenerFunctor
{
public:
    ListenerJoystickButton( void ) : mEvents() { }

    // Get joystick event.  Caller should ignore axis event (just in case).
    input::JoystickEvent
    GetJoystickEvent( void )
    {
        input::JoystickEvent event;  // invalid
        if ( not mEvents.empty() )
        {
            event = mEvents.front();  // dequeue
            mEvents.pop_front();
        }
        return event;
    }

private:
    void operator()( input::JoystickEvent event )
    {
    ASSERT( mEvents.size() < 5000 );
        mEvents.push_back( event );  // enqueue
    }

private:
    std::deque<input::JoystickEvent> mEvents;
};
#endif // ! DOXYGEN

// The joystick button handler.
INTERN shptr<ListenerJoystickButton> sListenerJoystickButton = new ListenerJoystickButton;


//==============================================================================
// C functions called by Lua that access C++ objects.
//==============================================================================

/*****************************************************************************
 * table|nil Joystick:DequeueButton()
 * Returns table { buttonNum=int, buttonVal=bool }
 *****************************************************************************/
INTERN int 
Joystick_DequeueButton( lua_State* L ) 
{ 
   try { 

        // Despite the event struct also containing axis members, ignore them.
        // Only propagate the button members to Lua since the control module handles axis events.
        input::JoystickEvent joystickEvent = sListenerJoystickButton->GetJoystickEvent();
        if ( joystickEvent.mButton != input::JoystickEvent::eButton_NONE )
        {
            lua_newtable( L );
            SET_MEMBER_AS_INT(  L, "buttonNum", joystickEvent.mButton );
            SET_MEMBER_AS_BOOL( L, "buttonVal", joystickEvent.mButtonVal );
        }
        else
        {
            lua_pushnil( L );  // no button event
        }
        return 1;  // stack items to return
    
   } CATCH_LUA_EXCEPTION 
   return 0; 
} 

/*****************************************************************************
 * int16 Joystick:GetAxisValue( axis )
 *****************************************************************************/
INTERN int 
Joystick_GetAxisValue( lua_State* L ) 
{ 
   try { 

        const int axis = POP_INT( L );
        const int axisVal = GET_CONTROL_JOYSTICK().GetAxisValue( axis );
        lua_pushnumber( L, axisVal );
        return 1;  // stack items to return
    
   } CATCH_LUA_EXCEPTION 
   return 0; 
} 

/*****************************************************************************
 * string Joystick:GetAxisValuesAsString() # for printing joystick values
 *****************************************************************************/
INTERN int 
Joystick_GetStateAsString( lua_State* L ) 
{ 
   try { 

    #if 0
        const uint minWidth = 5;
        const eNumberFormat format = eNumberFormat( int(eNumberFormat_SHOW_PLUS)| int(eNumberFormat_PAD_ZEROS) | int(eNumberFormat_NO_SHOW_BASE) );
    #else
        const uint minWidth = 5+2;
        const eNumberFormat format = eNumberFormat( int(eNumberFormat_SHOW_PLUS)| int(eNumberFormat_PAD_ZEROS)  );
    #endif
        control::Joystick& joystick = GET_CONTROL_JOYSTICK();
        string joystickStr;
        joystickStr += SignedHexNumber2String( joystick.GetAxisValue(0), minWidth, format ); joystickStr += ' ';
        joystickStr += SignedHexNumber2String( joystick.GetAxisValue(1), minWidth, format ); joystickStr += ' ';
        joystickStr += SignedHexNumber2String( joystick.GetAxisValue(2), minWidth, format ); joystickStr += ' ';
        joystickStr += SignedHexNumber2String( joystick.GetAxisValue(3), minWidth, format );//joystickStr += ' ';
        for ( uint i = 0; i < control::Joystick::MAX_BUTTONS; ++i )
        {
            joystickStr += ' '; joystickStr += joystick.GetButtonValue(i) ? '*' : 'O';
        }
        lua_pushstring( L, joystickStr.c_str() );
        return 1;  // stack items to return
    
   } CATCH_LUA_EXCEPTION 
   return 0; 
} 

//==============================================================================
// Register binding with Lua. 
//==============================================================================

#if ! DOXYGEN 

INTERN const struct luaL_reg sMethodTable[] =
{
  // New(),__gc() omitted as Lua cannot instantiate this C++ class.
  { "DequeueButton", Joystick_DequeueButton },
  { "GetAxisValue", Joystick_GetAxisValue },
  { "GetStateAsString", Joystick_GetStateAsString },
  { NULL, NULL }
};

void
RegisterJoystick( lua_State* L )
{
    REGISTER_BINDING( L,
                      BIND_METATABLE_NAME,
                      BIND_CLASS_NAME,
                      sMethodTable );

    // Listen for joystick button events.
    GET_CONTROL_JOYSTICK().mEventButton.Listen( sListenerJoystickButton.PTR() );
}

#endif // ! DOXYGEN 

} // namespace bind 

} // namespace lua 
