/*******************************************************************************
 * Copyright (c) 2005, 2006 Intel Corporation, IBM.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Vishnu K Naikawadi, Intel - Initial API and Implementation (Based on the Java
 *                                API implementation by IBM)
 *
 * $Id: TCPDataServer.h,v 1.7 2006/02/10 19:54:16 vnaikawadi Exp $
 *
 *******************************************************************************/ 




#ifndef  TCPDataServer_H
#define  TCPDataServer_H


#include "tptp/client/IDataProcessor.h"
#include "tptp/client/Constants.h"
#include "tptp/TPTPSupportTypes.h"
#include "tptp/dime.h"

#include <stdio.h> 
#include <iostream>

#include <vector>

using namespace std;

#define NUM_BUFFERS 32
#define MAX_MESSAGE_LENGTH 1024
//#define THREAD_USER_FUNC_RET_TYPE DWORD WINAPI


namespace TPTP
{
	namespace Client
	{

		class TCPDataServer
		{

			private:

				class TCPDataProcessor;
				class SingleBuffer;
				class BufferFlusher;

				SOCKET				_sock;
				TCPDataProcessor*	_server;
				BufferFlusher*		_flusher;
				int					_port;
				bool				_processing;

				/* Buffers for getting incomming data off the
				   socket reader and onto a dispatch thread
				*/
				//static short NUM_BUFFERS=32;
				SingleBuffer*	_bufferArray[NUM_BUFFERS];
				short _currentFullBuffers;

				//Vector _dataServerListeners=new Vector();

				unsigned long getLocalIPAddress();

				void connect();

				friend class TCPDataServer::TCPDataProcessor;
				friend class TCPDataServer::SingleBuffer;
				friend class TCPDataServer::BufferFlusher;

				class TCPDataProcessor
				{
					private:
						TCPDataServer* _tcpServer;
						SOCKET  _socket;
						bool _processing;
						bool _shutdown;
						short _currentFillerBuffer;
						IDataProcessor*	_processor;
						std::vector<IDataProcessor*> 	_processors;

						/* TODO - Remove later when flusher is used for flushing the data */
						DIME_HEADER_PTR_T _dimeMessageHeader;
						char _binaryForwardBuffer[MAX_MESSAGE_LENGTH];
						char _messageHeader[MAX_MESSAGE_LENGTH];
						char sendBuffer[MAX_MESSAGE_LENGTH];
						long _currentBufferSize;						
						int _currentHeaderOffset;
						int	_bytesWritten;

					public:
						TCPDataProcessor()
						{
							_currentFillerBuffer = 0;
							_currentHeaderOffset = 0;
							_currentBufferSize = 0;
							_bytesWritten = 0;
							_processing = true;
							_shutdown = false;
						};
						TCPDataProcessor(TCPDataServer* tcpServer):_tcpServer(tcpServer)
						{
							_currentFillerBuffer = 0;
							_currentHeaderOffset = 0;
							_currentBufferSize = 0;
							_bytesWritten = 0;
							_processing=true;
							_shutdown = false;
						};
						~TCPDataProcessor()
						{
							_processors.clear();
						};

						void setSocket(SOCKET sock);
						void resumeProcessing();
						void pauseProcessing();
						bool isProcessing();
						void shutdown();
						void run();
						void setDataProcessor(IDataProcessor* processor);
						void addDataProcessor(IDataProcessor* processor);

						void removeDataProcessor(IDataProcessor* processor);


						static THREAD_USER_FUNC_RET_TYPE startThread(void* args);

						int loadMessageHeader(char data[], int offset, int limit);
						int loadMessageHeaderDetails(char data[], int offset, int limit);
						long getMessageLength();												
						int processData(char data[], int offset, int limit);
				};



				class SingleBuffer
				{
					public :
						char* addr;
						int length;
						int size;
						char  data[MAX_MESSAGE_LENGTH];

						SingleBuffer(){length=0;size=MAX_MESSAGE_LENGTH;};
						~SingleBuffer();
				};


				class BufferFlusher
				{
					private:
						TCPDataServer* _tcpServer;
						IDataProcessor*	_processor;
						char _binaryForwardBuffer[MAX_MESSAGE_LENGTH];
						char _stringForwardBuffer[MAX_MESSAGE_LENGTH];
						char _messageHeader[MAX_MESSAGE_LENGTH];
						long _currentBufferSize;
						short _currentFlusherBuffer;
						int _currentHeaderOffset;
						int	_bytesWritten;


					public:
						BufferFlusher()
						{
							_currentFlusherBuffer=0;
							_currentBufferSize=0;
							_currentHeaderOffset=0;
							_bytesWritten=0;
						};
						BufferFlusher(TCPDataServer* tcpServer):_tcpServer(tcpServer)
						{
							_currentFlusherBuffer=0;
							_currentBufferSize=0;
							_currentHeaderOffset=0;
							_bytesWritten=0;
						};
						void setProcessor(IDataProcessor* processor);
						int loadMessageHeader(char data[], int offset, int limit);
						long getMessageLength();
						int getMessageType();
						bool checkMessageMagic();
						int processData(char data[], int offset, int limit, char* addr);
						void run();
						static THREAD_USER_FUNC_RET_TYPE startThread(void* args);
				};


			public:
				TCPDataServer();
				~TCPDataServer();

				/* Different types of data */
				static const int BINARY_DATA;
				static const int UTF8_STRING_DATA;
				static const int UNICODE_STRING_DATA;

				char* getServerAddress();

				int getPort();

				void startServer(IDataProcessor* processor, int sockid);

				void startServer(int sockid);

				void addDataProcessor(IDataProcessor* processor);

				void removeDataProcessor(IDataProcessor* processor);

				bool isProcessing();

				void stopServer();

				void resumeServer();

				void resumeServer(IDataProcessor* processor);

				void shutdownServer();

		};

	}

}



#endif

