#ifndef _CDEV_BUFFERED_SOCKET_H_
#define _CDEV_BUFFERED_SOCKET_H_

#include "cdevSocketConnector.h"
#include "cdevStreamQueue.h"

class cdevBufferedSocket : public cdevSocketConnector, public cdevNodeFactory
{
private:
	cdevNodeFactory * nodeFactory;
	
	int               magicNumber;
	int               deleteFlag;

	cdevStreamQueue   activeOut;
	cdevStreamQueue   waitingOut;
	int               outboundHeader[3];
	size_t            headerXfrLen;
	size_t            dataXfrLen;
	
	cdevStreamQueue   waitingIn;
	cdevStreamNode *  rcvNode;
	int               inboundHeader[3];
	size_t            headerRcvLen;
	size_t            dataRcvLen;
	size_t            subPacketLen;
	
	static void sigPipeHandler (int);

public:
	enum {RETRYCNT = 1000 };
	
	inline cdevBufferedSocket ( int MagicNumber=0, int deleteNodes = 1, cdevNodeFactory * factory=NULL );

	inline int              outboundReady   ( void );
	inline int              inboundReady    ( void );
	inline void             enqueueOutbound ( cdevStreamNode * node );
	inline cdevStreamNode * dequeueInbound  ( void );

	cdevStreamNode * newNode  ( ssize_t size );
	ssize_t          transmit ( void ); 
	ssize_t          receive  ( void );
	
	int              getBlockingSemantics ( void ) const;
	int              getRcvBufferSize     ( void ) const;
	int              getSndBufferSize     ( void ) const;
};


// *****************************************************************************
// * cdevBufferedSocket::cdevBufferedSocket :
// *	This is the constructor for the cdevBufferedSocket, it will initialize
// *	all internal variables and sub-classes.
// *****************************************************************************
inline cdevBufferedSocket::cdevBufferedSocket ( int MagicNumber, int deleteNodes, cdevNodeFactory * factory )
	: nodeFactory(factory),
	  magicNumber(MagicNumber),
	  deleteFlag (deleteNodes),
	  activeOut(deleteNodes),
	  waitingOut(deleteNodes),
	  headerXfrLen(0),
	  dataXfrLen(0),
	  waitingIn(),
	  rcvNode(NULL),
	  headerRcvLen(0),
	  dataRcvLen(0),
	  subPacketLen(0)
	{
	if(nodeFactory==NULL) nodeFactory=this;
	}


// *****************************************************************************
// * cdevBufferedSocket::outboundReady :
// *	This method returns an integer value indicating that outbound data is
// *	ready for transmission.
// *****************************************************************************
inline int cdevBufferedSocket::outboundReady ( void )
	{
	return !(activeOut.isEmpty() && waitingOut.isEmpty());
	}

// *****************************************************************************
// * cdevBufferedSocket::inboundReady :
// *	This method returns a flag indicating that inbound data is ready to be
// *	dequeued and processed.
// *****************************************************************************
inline int cdevBufferedSocket::inboundReady ( void )
	{
	return !(waitingIn.isEmpty() && headerRcvLen==0);
	}
	
// *****************************************************************************
// * cdevBufferedSocket::enqueueOutbound :
// *	This method places the user defined cdevStreamNode pointer into the 
// *	waitingOut object.
// *****************************************************************************
inline void cdevBufferedSocket::enqueueOutbound ( cdevStreamNode * node )
	{
	waitingOut.enqueue(node);
	}

// *****************************************************************************
// * cdevBufferedSocket::dequeueInbound :
// *	This method dequeues the next available cdevStreamNode object from the
// *	waitingIn object.
// *****************************************************************************
inline cdevStreamNode * cdevBufferedSocket::dequeueInbound ( void )
	{
	return waitingIn.dequeue();
	}


#endif /* _CDEV_BUFFERED_SOCKET_H_ */
