#include <cdevReactor.h>
#include <cdevSocketAcceptor.h>
#include <cdevBufferedSocket.cc>
#include "TestNode.h"

TestNode * TestNode::freeList = NULL;

#ifndef TRUE
	#define TRUE  1
	#define FALSE 0
#endif

cdevReactor GlobalReactor;

class ClientHandler : public cdevEventHandler, public cdevNodeFactory
{	
friend class Acceptor;

private:
	cdevBufferedSocket stream;
	int inboundCount;
	int count;

public:
	ClientHandler ( void ) : count(0), inboundCount(0), stream(0, 1, this) {}
	
	int open ( void ) 
		{
		return GlobalReactor.registerHandler(this, READ_MASK);
		}
		
	int getHandle ( void ) const
		{
		return stream.getHandle();
		}

	void setHandle ( int handle ) 
		{
		stream.setHandle(handle); 
		}	

	cdevStreamNode * newNode ( ssize_t size )
		{
		TestNode * node = new TestNode;
		node->setLen(size);
		return node;
		}
		
	int  handleInput ( void )
		{
		int      retval        = 0;
		cdevStreamNode * node  = NULL;
		
		if((retval = stream.receive())>0)
			{
			while((node=stream.dequeueInbound())!=NULL)
				{
				if(((inboundCount++)%1000)==0) fprintf(stdout, "SERVER: I received \"%s\"\n", node->getBuf());
				delete node;
				}
			}
		
		if(!stream.inboundReady())
			{
			for(int i=0; i<1000; i++)
				{
				TestNode * node = new TestNode;
				node->setLen(sprintf(node->getBuf(), "Server Packet %i", count++)+1);
				stream.enqueueOutbound(node);
				}
			setMask(READ_MASK|WRITE_MASK);
			}

		if(retval<0) setMask(DONT_CALL);
		
		return retval>=0?0:-1;
		}

	int handleOutput ( void )
		{
		int      retval = 0;
				
		retval=stream.transmit();
		if(retval<0) setMask(DONT_CALL);
		else if(!stream.outboundReady()) setMask(READ_MASK);

		return retval>=0?0:-1;
		}
		
	int  handleClose ( void )
		{
		fprintf(stdout, "Closing connection to host\n");
		stream.close();
		return 0;
		}
};
	

class Acceptor : public cdevEventHandler
{
public:
	Acceptor ( const cdevAddr &addr )
		{
		open(addr);
		GlobalReactor.registerHandler(this, READ_MASK);
		}

	int open ( const cdevAddr &addr )
		{
		int result = -1;
		if (acceptor.open (addr, TRUE) == -1) 
			{
			fprintf(stdout, "Acceptor [ERROR]: Failed to open listening port");
			}
		else if (acceptor.setFlags (O_NONBLOCK) == -1) 
			{
			fprintf(stdout, "Acceptor [ERROR]: Could not enable non-blocking I/O");
			}	
		else result = 0;
		return result;
		}
	
	int getHandle ( void ) const 
		{
		return acceptor.getHandle();
		}
	
	void setHandle ( int handle )
		{
		acceptor.setHandle(handle);
		}
		
	int handleInput ( void )
		{
		cdevInetAddr addr;
		ClientHandler * handler = new ClientHandler;
		if(acceptor.accept(handler->stream, &addr)!=-1)
			{
			fprintf(stdout, "Received connection from host %s\n", addr.getHostName());
			handler->open();
			}
		return 0;
		}
	
	int handleClose ( void )
		{
		acceptor.close();
		return 0;
		}	

private:
	cdevSocketAcceptor acceptor;
	};
	

	
int main (int argc, char * argv[], char * envp[])
	{
	if(argc<2)
		{
		fprintf(stderr, "%s [port]\n", argv[0]);
		return -1;
		}
	
	short           port = atoi(argv[1]);
	cdevInetAddr    acceptAddr(port, (long)INADDR_ANY);
	Acceptor      * acceptor = new Acceptor(acceptAddr);

	for(int i=0; i<100; i++)
		{
		if(i%10==0) fprintf(stdout, "====> Have reached iteration %i\n", i);
		GlobalReactor.handleEvents(1.0);
		}
	
	return 0;
	}
