-- $LastChangedDate: 2011-04-23 21:07:07 -0400 (Sat, 23 Apr 2011) $
-- Macros written in Lua to expand C++ code for bindings between C++/Lua.
-- Avoid lua_/LUA_ which is reserved by Lua.
--
-- This interfaces with the higher-level control::Joystick singleton
-- which consumes events from input::JoystickDevice but
-- it side-tracks button events to listeners (this).
-- So the C++ code here has to queue button events
-- (another queue is needed the C++ code can outrun Lua).

bindTable = {

class = "Joystick",
typesig = nil,
luaCanInstantiate = false,

headers =
[[
#include <deque>
#include "base/module.hh"
#include "base/misc.hh"
using namespace base;
#include "control/module.hh"
#include "control/joystick.hh"
using namespace control;
]],

--------------------------------------------------------------------------------

moreComments = [[
 * 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.
]],

moreCode = [[

#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;

]],

-- Expanded inside of Register*().
moreCodeRegister = [[

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

--------------------------------------------------------------------------------

func_DequeueButton = {
    comments = "table|nil Joystick:DequeueButton()\n * Returns table { buttonNum=int, buttonVal=bool }",
    code = [[
        // 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
    ]]
},

func_GetAxisValue = {
    comments = "int16 Joystick:GetAxisValue( axis )",
    code = [[
        const int axis = POP_INT( L );
        const int axisVal = GET_CONTROL_JOYSTICK().GetAxisValue( axis );
        lua_pushnumber( L, axisVal );
        return 1;  // stack items to return
    ]]
},

func_GetStateAsString = {
    comments = "string Joystick:GetAxisValuesAsString() # for printing joystick values",
    code = [[
    #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
    ]]
},

}
