//
// cEventBox
//
// This class contains an array of handles m_events[], which are
// set-up as Windows events (using the CreateEvent() API call)
//
// The object automatically creates/destroys the events, when
// the object's constructor or destructor is called.  This relieves the
// user from having to manually call CreateEvent() and CloseHandle().
//
// The purpose of this box is to facilitate communication between
// different threads.  Note that the box does not have any "intelligence"
// of its own.  It's up to the programmer to synchronize handshaking 
// using the box as a common-link between different threads.
//
// MPEG2AVI
// --------
//  v0.16B34  initial release
//
 
// DO NOT CHANGE THE ORDER OF THESE EVENTS!!!
// the threadhandler is hard-coded to the shown ordering!

//event ID for COMMANDs (user-issued commands issued to handler,)
#define EVID_CMD_READ 0  // request a buffer fill on the FORWARD buffer
#define EVID_CMD_EXIT  1 // instruct thread to shutdown
#define EVID_CMD_PAUSE 2 // ReadAheadThread() : allow indefinite waiting
#define EVID_CMD_REALT 3 // ReadAheadThread() : timeout after xx seconds

//#define EVID_CMD_CLOSE 2
//#define EVID_CMD_OPEN 3
//#define EVID_CMD_SEEK 3

//event ID for STATUS signals (set by handler, to notify user)
#define EVID_RDY_READ 4 // forward-buffer is ready for consumption
#define EVID_INIT_OK  5 // thread initialization complete
#define EVID_EXIT_OK  6 // thread exit sequence complete
#define EVID_RDY_CMD 7	// thread handler is ready for new command

//#define EVID_RDY_CLOSE 5
//#define EVID_RDY_OPEN 6
//#define EVID_RDY_SEEK 7

// event ID for "commands acknowledge" signals
// these events are set by the handler, to notify user that 
// it's request has been been processed
//#define EVID_CMDRCVD_READ 0 // not necessary to guarantee correct async operation
//#define EVID_CMDRCVD_CLOSE 5
//#define EVID_CMDRCVD_OPEN 6
//#define EVID_CMDRCVD_SEEK 7


#define MAX_EVENT_COUNT 8

class cEventBox
{
public :
	// these variables are *PUBLIC*, which is dangerous, but
	// direct access by external functions is desirable for performance reasons

	HANDLE m_events[MAX_EVENT_COUNT]; // array of events
	BOOL m_fInitOk;	// did initialization succeed?
	int m_evCount;	// number of events defined, starting from #0

public:
	// constructor and destructor
	
	BOOL IsValid( void )	// indicates whether EventBox is valid
		{ return m_fInitOk; };

	BOOL ResetAll( void );	// reset all events
	// the constructor requires an array of strings *event_names[]
	cEventBox( int evCount ); 
	~cEventBox( );

/*
	HANDLE CreateEvent(
  LPSECURITY_ATTRIBUTES lpEventAttributes,
                      // pointer to security attributes
  BOOL bManualReset,  // flag for manual-reset event
  BOOL bInitialState, // flag for initial state
  LPCTSTR lpName      // pointer to event-object name
);
*/
};


// constructor
cEventBox::cEventBox(  int evCount )
{
	m_fInitOk = TRUE;
	int i;
	char text[ 256];

	// 1) set the event_handles to NULL
	for ( i = 0; i < MAX_EVENT_COUNT; ++i )
		m_events[ i ] = NULL;

//	if ( event_names == NULL )
//	{
//		fprintf( stderr, "\ncEventbox::cEventbox() : event_names == NULL!");
//		m_fInitOk = FALSE;
//	}

	if ( evCount > MAX_EVENT_COUNT )
	{
		fprintf( stderr, "\ncEventbox::cEventbox() : evCount(%d) > MAX_EVENT_COUNT(%d)!",
			evCount, MAX_EVENT_COUNT );
		m_fInitOk = FALSE;
	}

	for ( i = 0; i < evCount; ++i)
	{
		sprintf( text, "Event#%d", i );
		// create events, MANUAL-RESET, non initially signaled
		m_events[i] = CreateEvent( NULL, TRUE, FALSE, text );
		if ( m_events[ i ] == NULL )	// check for failure
		{
			m_fInitOk = FALSE;
			fprintf( stderr, "\ncEventbox::cEventbox() : failed to create event#%d.",
				i );
		}
	} // end for( i ... )

	ResetAll();

	m_evCount = evCount;	// set # events
} // cEventBox::cEventBox()


cEventBox::~cEventBox( )
{
	int i;
	BOOL brc; // boolean return code

	if ( m_fInitOk == TRUE )
	{
		for ( i = 0; i < m_evCount; ++i )
		{
			if ( m_events[ i ] != NULL )
				brc = CloseHandle( m_events[ i ] );
			if ( !brc )
				fprintf( stderr, "\ncEventBox::~cEventBox() event#%d could not be destroyed.",
					i );
		}
	}
	else
		fprintf( stderr, "\ncEventBox::~cEventBox() : m_fInitOk == FALSE, nothing to do." );

} // cEventBox::~cEventBox()


BOOL 
cEventBox::ResetAll( void )
{
	int i;
	BOOL brc; // boolean return code
	BOOL fFail = FALSE;
	if ( m_fInitOk == TRUE )
	{
		for ( i=0; i < m_evCount; ++i )
		{
			brc = ResetEvent( m_events[ i ] );
			if ( brc == 0 )
				fFail = TRUE;	// failed to reset an event
		}
	}
	
	if ( fFail )
		fprintf( stderr, "\ncEventBox::ResetAll() : failed to reset 1 or more events.");

	return fFail;
}

