/*******************************************************************************
 * Copyright (c) 2005, 2008 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: ConnectionImpl.h,v 1.17 2008/05/20 16:52:00 jkubasta Exp $
 *
 *******************************************************************************/ 



#ifndef  ConnectionImpl_H
#define  ConnectionImpl_H

#define  TPTP_CLIENT_CONTROL_CH_PARTIAL_MESSAGE  -1 /*  Read only partial message on the control channel */

#include "tptp/TPTPExport.h"

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

//#include "TPTPCommon.h"
#include "tptp/client/IConnection.h"
#include "tptp/TransportSupport.h"
#include "ContextMapper.h"
#include "tptp/TPTPSupportUtils.h"
#include "TCPDataServer.h"



#include <map>

using namespace std;



namespace TPTP
{
	namespace Client
	{

		struct DataConnection
		{
			public: 
				SOCKET dataSocket;
				TCPDataServer* dataServer;
		};

		class TPTP_CLASS_EXPORT ConnectionImpl: public IConnection
		{
			private:
				SOCKET sock;
				int _connectionId;

				INode* _node;
				int _port;

				long _contextId;
				ContextMapper* _contextMapper;
				ICommandHandler* _cmdHandler;
				std::map<int, DataConnection*> _dataConnectionMap;

				bool _isComplete;
				bool _isInitialized;
				bool _loginPending;				

				void init();
				unsigned long getLocalIPAddress();
				void getIPAddresses(char *hostname, struct sockaddr_storage *** outResult, int *outNumResults);
				unsigned long getIPAddressIPv4(char* hostname);
				int sendControlCommand(SOCKET sockconn, int commandflags);
				int sendCONNECT_DATACommand(SOCKET datasock, int direction, int commandflags);
				int processControlMessage(char buffer[], int length);
				int closeDataConnection(int dataConnID);
				
				class SocketReaderThread
				{
				private:
					ConnectionImpl* _connImpl;
					int processRecdMsgs( char* pBuffer, unsigned int bufferLength, unsigned int     bytesReadIn, unsigned int*    offset, unsigned int*    messageLenOut);
				public:
					SocketReaderThread();
					SocketReaderThread(ConnectionImpl* connImpl):_connImpl(connImpl){};
					~SocketReaderThread();
					void run();
					static THREAD_USER_FUNC_RET_TYPE startThread(void* args);						
				};

				class ConnectionHandler : public ICommandHandler
				{
					private:
						ContextMapper* _mapper;
					public:
						ConnectionHandler();
						ConnectionHandler(ContextMapper* ctx);
						virtual ~ConnectionHandler();
						void incomingCommand(INode* node, CommandElement* command);
					
				};

				friend class ConnectionImpl::SocketReaderThread;
				friend class ConnectionImpl::ConnectionHandler;
				
				SocketReaderThread* reader;

			public:

				ConnectionImpl();

				virtual ~ConnectionImpl();

				void sendMessage(ControlMessage* msg, ICommandHandler* handler);

				void sendMessage(TPTPCommand* msg, ICommandHandler* handler);

				void disconnect();

				bool isActive();

				int getPort();

				long getNextContextID();

				void addContext(long id, ICommandHandler* handler);

				int connect(class INode* node, int port);

				int connect(class INode* node, ConnectionInfo* connInfo);

				int getConnectionId();

				INode* getNode();

				int createDataConnection(int direction, int commandflags);

				/*
				 * Destroy Data Connection
				 */
				int destroyDataConnection(int dataConnID);

				int addDataListener(int dataConnectionID, IDataProcessor* dataProcessor);

				int removeDataListener(int dataConnectionID, IDataProcessor* dataProcessor);

				int sendData(int dataConnectionID, char buffer[], int bufferLength);

				ContextMapper* getContextMapper();
		};

	}


}


#endif




