/*****************************************************************************
 * $Id: input_queue.hh,v 1.16 2006/10/10 04:14:55 devel Exp $
 * @file
 * @author	Jim E. Brooks  http://www.jimbrooks.org
 * @brief	Input event queue.
 *//*
 * LEGAL:	COPYRIGHT (C) 2004 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE (GPL).
 *****************************************************************************/

#ifndef GFXINPUT_INPUT_QUEUE_HH
#define GFXINPUT_INPUT_QUEUE_HH 1

#include <queue>

#include "joystick.hh"

// -----------------------------------------------------------------------------
namespace gfxInput {

/// Keyboard event.  (JoyEvent is declared at joystick.h)
class KeyEvent
{
public:
			KeyEvent( void ) { }
			KeyEvent( int key, bool special, bool press, bool shift, bool ctrl, bool alt )
			: mKey(key), mSpecial(special), mPress(press), mShift(shift), mCtrl(ctrl), mAlt(alt) { }
	int		mKey;			// which key (one of eGfxKey_*)
	bool	mSpecial;		// true if a special key such as F1, HOME, etc
    bool    mPress;         // true if key was pressed, else key was released
	bool	mShift;			// true if Shift was down
	bool	mCtrl;			// true if Ctrl was down
	bool	mAlt;			// true if Alt was down
};

////////////////////////////////////////////////////////////////////////////////
/// @brief Input event queue class.
/// @verbatim
///
/// Rationale:
/// ----------
/// Input events should be put into a queue and processed synchronously at
/// an appropriate time, rather than asynchronously.  The reason is that an
/// input event shouldn't be processed in the middle of rendering a view,
/// or worse, while processing an inappropriate view (such as an enemy view
/// which would affect the enemy rather than the player).
///
/// How to use this class:
/// ----------------------
/// o Construct only one InputQueue object (it can be static).
/// o Call Enable() after the gfxsys (eg OpenGL/GLUT) is ready.
/// o The application's timer handler must periodically call InputQueue::Tick()
///   which polls the input devices and enqueues events.
/// o The application can call InputQueue::*Events() to query
///   the amount of events in a single queue.
/// o Keyboard and joystick events can be pulled out of separate queues
///   by calling GetKey() and GetJoy().  Typically, the application
///   would call them prior to rendering a frame.
/// o Any application is liable to render too slowly.  So all applications
///   should inspect the queue size and begin discarding events if the queue
///   starts growing more and more after every frame.  Whether the older
///   or newer events are processed or discarded is the application's policy.
///   Either way, it can be done way by the application calling Get*() repeatedly.
///   until the queue is emptied.
///
/// Queues and queue sizes:
/// -----------------------
/// Each input device has its own queue.  This helps in the situation
/// where the application is able to keep pace with one input device but
/// another is generating too many events.  The application can process
/// events in one queue while dropping events in another queue.
///
/// @endverbatim
class InputQueue
{
PREVENT_COPYING(InputQueue)
public:
				InputQueue( void );
    static SafePtr<InputQueue> GetInstance( void );
	void		Enable( SafePtr<Joystick> joy );		// activate input queue
	bool		GetKeyEvent( KeyEvent* event/*OUT*/ );	// dequeue next keyboard event
	bool		GetJoyEvent( JoyEvent* event/*OUT*/ );	// dequeue next joystick event
	void		PutKeyEvent( int key, bool special, bool press, bool shift, bool ctrl, bool alt );
	int			KeyEvents( void );						// amount of keyboard events enqueued
	int			JoyEvents( void );						// amount of joystick events enqueued
	void		Tick( int milsec );						// this feeds the input queue

private:
	queue<KeyEvent>		mKeyQueue;
	queue<JoyEvent>		mJoyQueue;
	SafePtr<Joystick>	mJoy;

    // Support for default ctor that makes a dummy interim queue during program startup.
    static SafePtr<InputQueue> msInputQueue;         // pointer
    static InputQueue       msDummyInputQueue;      // actual object by default ctor
    static Joystick         msDummyJoystick;
    static int              msInstanceCnt;
};

} // namespace gfxInput
// -----------------------------------------------------------------------------

#endif // GFXINPUT_INPUT_QUEUE_HH
