//=========================================================================
// Summary  : Driver parent class for socket-based devices
// Filename : SocketDriver.h
// Author   : Marsh
// Project  : 
// Revision : 1
// Created  : 2001/01/8
// Modified : 2000/08/21
//=========================================================================
// Description :
//=========================================================================

#ifndef _SOCKETDRIVER_H
#define _SOCKETDRIVER_H

#include "Task.h"
#include "SignalTable.h"
/**
Driver based on TCP sockets.
This driver generalizes event-driven socket communication.  Subclasses may
open mulitple sockets, which are all managed by this base class.  The
subclasses may register a callback for each socket, to be triggered upon some 
event, typically the reception of data, a timeout, or on error.
*/
class SocketDriver : public Task {
public:
	/**
	Create the driver.

	@param name	Identifier for this driver
	*/
	SocketDriver( const char *name );

	/**
	Cleanup the driver.
	Cleans up any sockets in use, frees resources.
	*/
	~SocketDriver();

	/**
	Main driver loop.
	This method waits for events on any sockets opened via openSocket()
	and, depending on settings, invokes a user-supplied callback method
	when certain events take place, e.g. data received.
	*/
	virtual void run();

protected:
	typedef void (SocketDriver::*SignalCallbackMethod)( void );
	typedef SignalTable<SignalCallbackMethod> SocketSignalTable;

	struct SocketListEntry;

	/**
	Callback function definition.
	Callback functions must take this form.
	*/
	typedef void (SocketDriver::*CallbackMethod)( struct SocketListEntry *entry, Boolean isError );

	typedef enum {
	     None = 0,
	     Disconnected = -1,
	     Connected = 1,
	     Error = 2
	} SocketConnectionState;

	/**
	Class for each socket instance.
	This class manages each socket.
	*/
	class SocketListEntry {
	public:
		int socketNum;
		char *name;
		char *hostname;
		int port;
		int lastErrNo;
		CallbackMethod callback;
	
		SocketConnectionState state;
		
		int buffSize;

		SocketListEntry() { 
			socketNum = -1; 
			name = NULL;
			hostname = NULL;
			callback = NULL;
			buffSize = 0;
		};
		~SocketListEntry() { 
			clean( name );
			clean( hostname );
		}
		/**
		Set the waterline to trigger an event.
		Tell the socket driver to wait until numBytes have been
		recieved before invoking the user-defined callback.
		@param	numBytes	number of bytes to wait for.
		*/
		void setTriggerByteCount(int numBytes) { buffSize = numBytes; }
	};

	/**
	@param	name	A descriptive name
	@param	hostName	TCP hostname
	@param	port	Port number
	@param	method	Callback method triggered on specified events
	@param	bufferSize	number of bytes to wait for.
	@param  peekAtData      Should SocketDriver pre-read a bit of data first?
	@param  openImmediately  Should SocketDriver attempt to open a connection immediately? Defaults to True
	*/
	int SocketDriver::registerSocket( const char *name,
					  const char *hostname, int port,
					  CallbackMethod callback,
					  int triggerByteCount = 0,
					  Boolean openImmediately = True );

	/**
	   Open a socket you have registered.
	   @param index  Index of desired connection in socketList
	 */
	int openSocket( int socketIndex );
	int openSocket( struct SocketListEntry *listEntry );

	int closeSocket( int socketIndex );
	int closeSocket( struct SocketListEntry *listEntry );

	int getSocketFd( int index );
     
	int readSocket( struct SocketListEntry *theEntry );

	int writeSocket( int socketIndex, char *buffer, int buffSize );
     
	void dumpSocketInfo( int index );
	
	int addSignalCallback( int signo,
			       SignalCallbackMethod callback );

private:
     
	int socketListMax;
	
	DynamicArray<struct SocketListEntry *> socketList;

	SocketSignalTable _sigTable;

};


#endif
