#ifndef _FD_TRIGGER_H_
#define _FD_TRIGGER_H_ 1

#include <cdevPlatforms.h>

// *****************************************************************************
// * FD_Trigger :
// *	This class provides a method for triggering events based on file 
// *	descriptor activity.
// *****************************************************************************
class FD_Trigger 
{
private:
	enum {READ=0, WRITE=1};
	int  sockPair[2];

#ifndef _WIN32
	char cbuf[100];
#endif
		
public:
	FD_Trigger     ( void );
	~FD_Trigger    ( void );
	int  insertEvent ( int numEvents = 1 );
	int  removeEvent ( int numEvents = 1 );
	void purge       ( void );
	int  writefd     ( void ) const;
	int  readfd      ( void ) const;
};


// *****************************************************************************
// * FD_Trigger::FD_Trigger :
// *	Constructor for the FD_Trigger class.
// *****************************************************************************
inline FD_Trigger::FD_Trigger ( void )
	{
	if(pipe(sockPair)!=0)
		{
		sockPair[READ]  = -1;
		sockPair[WRITE] = -1;
		}
	#ifndef _WIN32
	else
		{
		int val;

		val = ::fcntl(sockPair[READ], F_GETFL, 0);
		if(val>0) ::fcntl(sockPair[READ],  F_SETFL, val|O_NONBLOCK);

		val = ::fcntl(sockPair[WRITE], F_GETFL, 0);
		if(val>0) ::fcntl(sockPair[WRITE], F_SETFL, val|O_NONBLOCK);
		
		memset(cbuf, '1', 100);
		}
	#endif
	}



// *****************************************************************************
// * FD_Trigger::~FD_Trigger :
// *	Destructor for the FD_Trigger class.
// *****************************************************************************
inline FD_Trigger::~FD_Trigger ( void )
	{
	if(sockPair[READ] != -1) close(sockPair[READ]);
	if(sockPair[WRITE] != -1) close(sockPair[WRITE]);
	}



// *****************************************************************************
// * FD_Trigger::insertEvent :
// *	Adds one or more bytes (indicating events) to the pipe
// *****************************************************************************
inline int FD_Trigger::insertEvent ( int numEvents )
	{
	if(sockPair[WRITE]>0)
		{
		int count = 0;
		
		#ifdef _WIN32
			char cptr  = 1;
			
			while(count++<numEvents) send(sockPair[WRITE], &cptr, 1, 0);
		#else
			count = numEvents;
			while(count>0)
				{
				write(sockPair[WRITE], cbuf, min(100, count));
				count-=100;
				}
		#endif
		}  
	return (sockPair[WRITE]>0)?0:-1;
	}
		


// *****************************************************************************
// * FD_Trigger::removeEvent :
// *	Removes one or more bytes (indicating events) from the pipe.
// *****************************************************************************
inline int FD_Trigger::removeEvent ( int numEvents )
	{
	int retval = 0;
	
	if(sockPair[READ]>0)
		{
		int count = 0;
		
		#ifdef _WIN32
			char cptr = 0;
			
			while(count<numEvents && 
			     (recv(sockPair[READ], &cptr, 1, 0)>0 || 
			      WSAGetLastError()==WSAEMSGSIZE))
				{
				count++;
				}
			if(count==0) retval = -1;
			
		#else	
			if(ioctl(sockPair[READ], FIONREAD, &count)<0 || count==0)
				{
				retval = -1;
				}
			else
				{
				if(numEvents>count) numEvents = count;
				while(numEvents>0)
					{
					read(sockPair[READ], cbuf, min(100, numEvents));
					numEvents-=100;
					} 
				}
		#endif
		}
	else retval = -1;
	
	return retval;
	}



// *****************************************************************************
// * FD_Trigger::purge :
// *	This function removes all bytes from the pipe.
// *****************************************************************************
inline void FD_Trigger::purge ( void ) 
	{
	if(sockPair[READ]>0)
		{
		#ifdef _WIN32
			char     cptr = 0;
			while(recv(sockPair[READ], &cptr, 1, 0)>0 || WSAGetLastError()==WSAEMSGSIZE);
		#else
			int    count = 0;
			ioctl(sockPair[READ], FIONREAD, &count);	
			while(count>0)
				{
				read(sockPair[READ], cbuf, min(100, count));
				count-=100;
				}
		#endif
		}
	}



// *****************************************************************************
// * FD_Trigger::writefd
// *	Returns the write file descriptor associated with the pipe.
// *****************************************************************************
inline int FD_Trigger::writefd ( void ) const
	{
	return sockPair[WRITE];
	}
	


// *****************************************************************************
// * FD_Trigger::readfd
// *	Returns the read file descriptor associated with the pipe.
// *****************************************************************************
inline int FD_Trigger::readfd  ( void ) const
	{
	return sockPair[READ];
	}

#endif /* _FD_TRIGGER_H_ */
