// InputBuffer.h : Declaration of the cInputBuffer

#ifndef __INPUTBUFFER_H_
#define __INPUTBUFFER_H_

#include "resource.h"       // main symbols
#include "InjectCP.h"

typedef std::vector< INPUT > cInputVec;

/////////////////////////////////////////////////////////////////////////////
// cInputBuffer
class ATL_NO_VTABLE cInputBuffer : 
	public CComObjectRootEx<CComMultiThreadModel>,
   public IDispatchImpl<IInputNotify, &IID_IInputNotify, &LIBID_DecalPlugins>,
	public IDispatchImpl<IInputBuffer, &IID_IInputBuffer, &LIBID_DecalPlugins>,
   public IProvideClassInfo2Impl< &CLSID_InputBuffer, &DIID_IInputEvents, &LIBID_DecalPlugins >,
	public CProxyIInputEvents< cInputBuffer >,
	public IConnectionPointContainerImpl<cInputBuffer>
{
public:
	cInputBuffer()
      : m_status( eInputIdle )
	{
	}

BEGIN_COM_MAP(cInputBuffer)
   COM_INTERFACE_ENTRY(IInputNotify)
	COM_INTERFACE_ENTRY(IInputBuffer)
   COM_INTERFACE_ENTRY(IProvideClassInfo)
   COM_INTERFACE_ENTRY(IProvideClassInfo2)
	COM_INTERFACE_ENTRY2(IDispatch, IInputBuffer)
	COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer)
END_COM_MAP()

BEGIN_CONNECTION_POINT_MAP(cInputBuffer)
	CONNECTION_POINT_ENTRY(DIID_IInputEvents)
END_CONNECTION_POINT_MAP()

   // Global functions to set up the input processing
   // thread
   static HANDLE m_hThread;
   static HANDLE m_hTerm;
   static HANDLE m_hInputWaiting;

   static CRITICAL_SECTION m_csQueue;

   typedef std::deque< std::pair< cInputBuffer *, LPSTREAM > > cInputQueue;
   static cInputQueue m_queue;

   static void init();
   static void term();

   void postBuffer();

   cInputVec *getLastInput();

   // Quick and dirty class hierarchy for input operations

   class cAction
   {
   public:
      // Run the action 
      virtual void execute( IInputNotify *pib ) = 0;
   };

   enum eActionType
   {
      eActionInput,
      eActionDelay,
      eActionMouseMove
   };

   class cInput
      : public cAction
   {
   public:
      cInputVec m_input;

      virtual void execute( IInputNotify *pib );
   };

   class cDelay
      : public cAction
   {
   public:
      long m_nMillis;
      bool m_bAllowInput;

      virtual void execute( IInputNotify *pib );
   };

   class cMouseMove
      : public cAction
   {
   public:
      POINT m_ptClient;

      virtual void execute( IInputNotify *pib );
   };

   typedef std::list< std::pair< eActionType, VSBridge::auto_ptr< cAction > > > cActionList;
   cActionList m_actions;

   eInputStatus m_status;

public:
   // IInputBuffer Methods
	STDMETHOD(Run)();
	STDMETHOD(get_Status)(/*[out, retval]*/ eInputStatus *pVal);
	STDMETHOD(MouseClick)(long nX, long nY, eMouseInput eAction);
	STDMETHOD(Delay)(long nMilliseconds, VARIANT_BOOL bAllowInput);
	STDMETHOD(TypeText)(BSTR strText);
	STDMETHOD(Clear)();

   // IInputNotify Methods
	STDMETHOD(NotifyBegin)();
	STDMETHOD(NotifyEnd)();
	STDMETHOD(SetMousePos)(long nX, long nY);
	STDMETHOD(NotifyPause)();
};

#endif //__INPUTBUFFER_H_
