#include "NetBridge_OVERLAPPED.h"

CNetBridge_OVERLAPPED::CNetBridge_OVERLAPPED()
{

}
//-----------------------------------------------------------------
CNetBridge_OVERLAPPED::~CNetBridge_OVERLAPPED()
{

}
//-----------------------------------------------------------------
int	CNetBridge_OVERLAPPED::Init ()
{
	int iReturn = NB_OK;
	if( ( iReturn = CNetBridge_Base::Init() ) != NB_OK )
	{
		return iReturn;
	}
	return iReturn;
}
//-----------------------------------------------------------------
DWORD WINAPI CNetBridge_OVERLAPPED::Thread_Accept( PVOID pParam )
{
	CNetSocket*	pSocket			= (CNetSocket*)pParam;
	CNetBridge_Base*	pNetBridge		= pSocket->m_pNetBridge;

	SOCKET				AcceptSocket;
	sockaddr			saClient;
	int					iClientSize		= sizeof(saClient);
	DWORD				hID;



	while(1)
	{	
		//進入等待模式, 等候新的連線
		AcceptSocket = WSAAccept( pSocket->m_tcp_socket, &saClient, &iClientSize, NULL, NULL );
		//AcceptSocket = accept( pSocket->m_tcp_socket, &saClient, &iClientSize );
		if( AcceptSocket == INVALID_SOCKET )
		{
			// ERROR?
		}
		else
		{


		}

		// 此時已接受新的連線了, 準備資料給他

			CNetSocket* pNewSocket					= pNetBridge->CreateSocket();// true , NULL );

			pNewSocket->m_tcp_socket				= AcceptSocket;
			pNewSocket->m_overlapped_Recv.hEvent	= WSACreateEvent();	// Create 出來的 Event 是 Non-Signaled 狀態
			pNewSocket->m_overlapped_Send.hEvent	= WSACreateEvent();	// Create 出來的 Event 是 Non-Signaled 狀態

			/*
			if( pNetBridge->m_iomode == IOCP_MODE )
			{
				// iocp mode
				// Associate the new connection to our completion port
				HANDLE hrc = CreateIoCompletionPort( (HANDLE)pNewSocket->m_tcp_socket, pNetBridge->m_CompletionPort, (ULONG_PTR)pNewSocket,	0 );
				if( hrc == NULL )
				{
					// ERROR?
				}
			}
			else
			{
				// overlapped mode
				pNewSocket->m_thread_Recv				= CreateThread( NULL, 0, Thread_Recv,	pNewSocket, 0, &hID );
				pNewSocket->m_thread_Send				= CreateThread( NULL, 0, Thread_Send,	pNewSocket, 0, &hID );
			}
			*/

			// overlapped mode
				pNewSocket->m_thread_Recv				= CreateThread( NULL, 0, Thread_Recv,	pNewSocket, 0, &hID );
				pNewSocket->m_thread_Send				= CreateThread( NULL, 0, Thread_Send,	pNewSocket, 0, &hID );

		// 通知系統有新 Client 登入

			//CEventMsg* pMsg					= pNetBridge->CreateMsg();

			/*
			pMsg->m_emMsgType				= MSG_NEWCONNECTION;
			pMsg->m_dwNetID					= pSocket->m_dwNetID;
			pMsg->m_dwNewConnectionNetID	= pNewSocket->m_dwNetID;

			pNetBridge->m_cs_MessageAndEvent.Enter();
			pNetBridge->m_queueMsg.push( pMsg );	// 推進事件佇列
			pNetBridge->m_cs_MessageAndEvent.Leave();
			*/
	}
}
//-----------------------------------------------------------------
DWORD WINAPI CNetBridge_OVERLAPPED::Thread_Recv		( PVOID pParam )
{
	// 已測試過項目
	// a. 第一次接收, 兩個完整封包 , 第二次接收, 兩個完整
	// b. 第一次接收, 一個完整, 一個不完整, 第二次接收, 完整, 後面帶一個完整
	// c. 第一次接收, 一個完整, 一個不完全, 第二次接收, 完整, 後面帶一個完整

	CNetSocket*	pSocket			= ( CNetSocket* )pParam;
	CNetBridge_Base* pNetBridge		= pSocket->m_pNetBridge;

	DWORD	dwReturn = 0, dwFlag = 0;
	char	szBuff[DF_NB_PACKETBUFFERSIZE];

	WSABUF  wbuf;
	wbuf.buf							= szBuff;
	wbuf.len							= DF_NB_PACKETBUFFERSIZE;

	byte*	ptr							= (byte*)wbuf.buf;			// 每次收資料時所指向的位置
	DWORD	dwBufferSize				= DF_NB_PACKETBUFFERSIZE;	// 每次收資料時 Buffer Size

	byte*	pExtraBuffer				= NULL;						// 用來存放上一次收不完整的剩餘資料 Buffer
	DWORD	dwBytesRemian				= 0;						// 上一次封包還剩餘的資料大小還未收到

	DWORD	dwBytesRecv					= 0;						// 一次 I/O LOOP 共有多少 Bytes 收到
	DWORD	dwBytesNeedProcess			= 0;						// 還有多少 Bytes 須要處理
	DWORD	dwPacketSize				= 0;

	byte*	pPacket						= NULL;						// 用來存放封包資料
	byte*	pPacket_ptr					= NULL;						// 指向封包最後推到的地方

	PVOID	pNextPacketBuffer			= NULL;


	DWORD	dwBytes						= 0;

	//DWORD					= 0;	// 這次收到的封包量,還有多少 Byte 要處理 
	DWORD	dwBytesNeedForNextPacket	= 0;	// 多少 Byte 已收到


	DWORD	dwCounter = 0;


	while( 1 )
	{
		wbuf.buf		= (char*)ptr;
		wbuf.len		= dwBufferSize;


		if( ( dwReturn = WSARecv( pSocket->m_tcp_socket, &wbuf, 21, &dwBytesRecv, &dwFlag, &pSocket->m_overlapped_Recv, NULL ) ) == SOCKET_ERROR )
		{
			if( ( dwReturn = WSAGetLastError() ) != WSA_IO_PENDING )
			{
				int a = 3;
			}
			else
			{
				int a = 4;
			}

			// 錯誤


		}

		// 重置 PTR
		if( pExtraBuffer == NULL )
			ptr = (byte*)szBuff;
		else
			ptr = (byte*)pExtraBuffer;

		// 進入等待模式
		dwReturn = WaitForSingleObject( pSocket->m_overlapped_Recv.hEvent, INFINITE );   

		// 取得處理結果
		dwReturn = WSAGetOverlappedResult( pSocket->m_tcp_socket, &pSocket->m_overlapped_Recv, &dwBytesRecv, true, &dwFlag );


		InterlockedExchangeAdd( &pSocket->m_pNetBridge->m_bytesRecv, dwBytesRecv );


		WSAResetEvent( pSocket->m_overlapped_Recv.hEvent );	//將事件重設回 Non-Signaled 狀態

		dwBytesNeedProcess += dwBytesRecv;

		// 檢查是否接續上次未處理完的封包
		//if( pExtraBuffer != 0 )
		if( pPacket != NULL )
		{
			if( dwBytesRemian > dwBytesNeedProcess )
			{
				// 收到的資料, 仍不夠將封包收完
				memcpy( pPacket_ptr, ptr, dwBytesNeedProcess );

				// 移動指標
				ptr					+=	dwBytesNeedProcess;
				pPacket_ptr			+=	dwBytesNeedProcess;
				dwBytesRemian		-=	dwBytesNeedProcess;

				dwBytesNeedProcess	=	0;


			}
			else
			{
				memcpy( pPacket_ptr, ptr, dwBytesRemian );

				// 移動指標
				ptr					+=	dwBytesRemian;

				dwBytesNeedProcess	-=	dwBytesRemian;
				dwBytesRemian		=	0;

				// 收到一個完整的封包了, 推入訊息佇列

				/*
				CEventMsg* pMsg			= pNetBridge->CreateMsg();
				pMsg->m_emMsg			= MSG_PACKET;
				pMsg->m_dwNetID			= pSocket->m_dwNetID;
				pMsg->m_pPacket			= pPacket;
				pMsg->m_dwPacketSize	= dwPacketSize;

				pNetBridge->m_cs_MessageAndEvent.Enter();
				pNetBridge->m_queueMsg.push( pMsg );
				pNetBridge->m_cs_MessageAndEvent.Leave();
				*/


				pPacket				=	NULL;

			}
		}

		while( dwBytesNeedProcess != 0 )
		{
			//dwPacketSize	= pNetBridge->GetPacketSize( dwBytesNeedProcess, ptr );
			if( dwPacketSize != 0 )
			{
				pPacket = new byte[ dwPacketSize ];
				if( pPacket == NULL )
				{
					int a = 3;
				}

				if( dwPacketSize > dwBytesNeedProcess )
				{
					// 剩下的資料量不夠一個封包
					memcpy( pPacket, ptr, dwBytesNeedProcess );
					pPacket_ptr			=	pPacket + dwBytesNeedProcess;

					dwBytesRemian		=	dwPacketSize - dwBytesNeedProcess;
					dwBytesNeedProcess	=	0;

					// 接下來若要寫擴充緩衝區, 可以寫在這
					// 做出緩衝區, 接收資料
					if( pExtraBuffer != NULL )
						delete [] pExtraBuffer;

					dwBufferSize	= dwBytesRemian + DF_NB_PACKETBUFFERSIZE;;

					pExtraBuffer	= new byte[ dwBufferSize ];

					//wbuf.buf		= (char*)pExtraBuffer;
					//wbuf.len		= dwBytesRemian + DF_NB_PACKETBUFFERSIZE;

					// 移動指標
					ptr += dwBytesNeedProcess;

				}
				else
				{
					// 剩下的量夠一個封包
					memcpy( pPacket, ptr, dwPacketSize );
					dwBytesNeedProcess	-=	dwPacketSize;

					// 收到一個完整的封包了, 推入訊息佇列

					/*
					CEventMsg* pMsg			= pNetBridge->CreateMsg();
					pMsg->m_emMsg			= MSG_PACKET;
					pMsg->m_dwNetID			= pSocket->m_dwNetID;
					pMsg->m_pPacket			= pPacket;
					pMsg->m_dwPacketSize	= dwPacketSize;

					pNetBridge->m_cs_MessageAndEvent.Enter();
					pNetBridge->m_queueMsg.push( pMsg );
					pNetBridge->m_cs_MessageAndEvent.Leave();
					*/

					pPacket				=	NULL;

					// 移動指標
					ptr += dwPacketSize;
				}
			}
			else
			{
				// 資料量, 不夠可以檢查封包大小的
				// 跳開迴圈, 檢查資料是在那種 Buffer, 重置狀態重新接收
				break;
			} 
		}

		if( dwBytesNeedProcess != 0 )
		{
			//表還有剩餘資料, 有可能是[ 資料量, 不夠可以檢查封包大小的 ]
			if( pExtraBuffer != NULL )
			{
				memcpy( pExtraBuffer, szBuff, dwBytesNeedProcess );
				ptr		= pExtraBuffer + dwBytesNeedProcess;
			}
			else
			{
				memmove( szBuff, ptr, dwBytesNeedProcess );
				ptr				=	(byte*)( szBuff + dwBytesNeedProcess );
				dwBufferSize	-=	dwBytesNeedProcess;
			}
		}
		else
		{
			if( dwBytesRemian == 0 )
			{
				if( pExtraBuffer != NULL )
				{
					delete [] pExtraBuffer;
					pExtraBuffer = NULL;
				}

				ptr				= (byte*)szBuff;
				dwBufferSize	= DF_NB_PACKETBUFFERSIZE;
			}
			else
			{
				ptr		= pExtraBuffer;				
			}
		}
	}
}
//-----------------------------------------------------------------
int	CNetBridge_OVERLAPPED::Connect ( DWORD dwIP, DWORD dwPort, CEventObj* pEventObj )
{
	/*
	// Create Socket
	CNetSocket* pSocket		= CreateSocket();

	pSocket->m_tcp_socket	= socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );

	// Prepre Socket Address

	SOCKADDR_IN	sa;
	memset( &sa, 0, sizeof( SOCKADDR_IN ) );
	sa.sin_family		= AF_INET;
	sa.sin_addr.s_addr	= dwIP;
	sa.sin_port 		= htons( (WORD)dwPort );

	int iReturn			= WSAConnect( pSocket->m_tcp_socket, (SOCKADDR *)&sa, sizeof( SOCKADDR ), NULL, NULL, NULL, NULL );

	if( iReturn == SOCKET_ERROR )
	{
		// 連線失敗
		DeleteSocket( pSocket->m_dwNetID );
		//iReturn = WSAGetLastError();

		m_cs_MessageAndEvent.Enter();

		m_mapEvent[ pSocket->m_dwNetID ] = pEventObj;	// link the event

		CEventMsg* pMsg			= CreateMsg();
		pMsg->m_emMsg			= MSG_CONNECTFAILED;	
		m_queueMsg.push( pMsg );						// 推 MSG_CONNECTFAILED 進事件佇列

		m_cs_MessageAndEvent.Leave();

		return 0;
	}

	// 連線成功, 準備收發所須要的事件和執行緒

	DWORD hID = 0;

	pSocket->m_overlapped_Recv.hEvent	= WSACreateEvent();	// Create 出來的 Event 是 Non-Signaled 狀態
	pSocket->m_overlapped_Send.hEvent	= WSACreateEvent();	// Create 出來的 Event 是 Non-Signaled 狀態

	pSocket->m_thread_Send				= CreateThread( NULL, 0, Thread_Send,	pSocket, 0, &hID );
	pSocket->m_thread_Recv				= CreateThread( NULL, 0, Thread_Recv,	pSocket, 0, &hID );

	m_cs_MessageAndEvent.Enter();

	m_mapEvent[ pSocket->m_dwNetID ] = pEventObj;	// link the event

	/*
	CEventMsg* pMsg				= CreateMsg();
	pMsg->m_dwMsgID				= MSG_CONNECTED;
	pMsg->m_dwNetID				= pSocket->m_dwNetID;
	m_queueMsg.push( pMsg );	// 推 MSG_CONNECTED 進事件佇列
	*/

	//m_cs_MessageAndEvent.Leave();

	//return pSocket->m_dwNetID;
	return 0;
	
}

//-----------------------------------------------------------------
int	CNetBridge_OVERLAPPED::Host ( DWORD dwIP, DWORD dwPort, CEventObj* pEventObj )
{
	//int		rc;
	// create socket
	DWORD dwNetID;
	CNetSocket* pSocket = CreateSocket();// true, NULL, &dwNetID );

	// link the event
	/*
	m_cs_MessageAndEvent.Enter();
	m_mapEvent[ dwNetID ] = pEventObj;
	m_cs_MessageAndEvent.Leave();
	*/

	// create the tcp socket
	pSocket->m_tcp_socket	= socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );

	// bind the socket
	SOCKADDR_IN	sa;
	memset( &sa, 0, sizeof( SOCKADDR_IN ) );
	sa.sin_family		= AF_INET;

	if( dwIP != 0 )
		sa.sin_addr.s_addr	= dwIP;
	else
		sa.sin_addr.s_addr = INADDR_ANY;

	sa.sin_port 		= htons( (WORD)dwPort );

	bind( pSocket->m_tcp_socket, (SOCKADDR *) &sa, sizeof(SOCKADDR));

	// 建立一個 Event 用來處理 Accept
	//pSocket->m_event = WSACreateEvent(void);

		// overlapped mode
		// 建立 Thread 讓它等待 Accept 命令
		DWORD  hID			 = 0;

		listen( pSocket->m_tcp_socket , 100 );

		pSocket->m_thread_Accept = CreateThread( NULL, 0, Thread_Accept,	pSocket, 0, &hID );

	return dwNetID;
}
//-----------------------------------------------------------------
DWORD WINAPI CNetBridge_OVERLAPPED::Thread_Send( PVOID pParam )
{
	/*
	CNetSocket*	pSocket			= (CNetSocket*)pParam;
	CNetBridge_Base*	pNetBridge		= pSocket->m_pNetBridge;

	DWORD		dwFlag			= 0;
	DWORD		dwReturn		= 0;
	DWORD		dwBytesSend		= 0;
	int			iReturn			= 0;
	WSABUF		wBuf;
	CPacket*	pPacket			= NULL;

	while( 1 )
	{
		WaitForSingleObject( pSocket->m_event_PreSend, INFINITE );
		ResetEvent( pSocket->m_event_PreSend );

		// 取出 Queue
		while(1)
		{
			// 這裡可以設計成, 測試 I/O 是否有空, 要是沒空, 就把 Queue 裡面的資料拿出來先處理, 比方說壓縮 / 加密...etc
			pSocket->m_cs_queueSend.Enter();
			if( pSocket->m_queueSend.empty() == TRUE )
			{
				pSocket->m_cs_queueSend.Leave();
				break;
			}
			else
			{
				pPacket = pSocket->m_queueSend.front();
				pSocket->m_queueSend.pop();
			}
			pSocket->m_cs_queueSend.Leave();

			wBuf.buf	= (char*)pPacket->m_pPacket;
			wBuf.len	= pPacket->m_dwPacketSize;

			// 處理
			iReturn = WSASend( pSocket->m_tcp_socket, &wBuf, 1, &dwBytesSend, 0, &pSocket->m_overlapped_Send, NULL );
			if( iReturn != 0 )
			{
				int a = 3;
			}

			WaitForSingleObject( pSocket->m_overlapped_Send.hEvent, INFINITE );

			// 取得處理結果
			dwReturn = WSAGetOverlappedResult( pSocket->m_tcp_socket, &pSocket->m_overlapped_Send, &dwBytesSend, true, &dwFlag );

			InterlockedExchangeAdd( &pSocket->m_pNetBridge->m_bytesSend, dwBytesSend );

			delete [] pPacket->m_pPacket;
			delete pPacket;

			WSAResetEvent( pSocket->m_overlapped_Send.hEvent );
		}
	}
	*/
	return 0;
}
//-----------------------------------------------------------------
void	CNetBridge_OVERLAPPED::Send( DWORD dwNetID, DWORD dwSize, PVOID pBuffer, DWORD dwPriority, DWORD dwFlag )
{

	/*
	map< DWORD, CNetSocket* >::iterator it = m_mapSocket.find( dwNetID );

	if( it == m_mapSocket.end() )
	{
		return false;
	}

	CNetSocket*	pSocket = it->second;

	//m_mapSocket[ dwNetID ]

	//int			iReturn;
	//WSABUF		wBuf;
	//DWORD		dwBytes;

	//wBuf.buf = (char*)pPacket;
	//wBuf.len = dwSize;

	CPacket*	pPacket		= new CPacket;
	pPacket->m_dwPacketSize	= dwSize + sizeof( DWORD );
	pPacket->m_pPacket		= new byte[ pPacket->m_dwPacketSize ];

	memcpy(	pPacket->m_pPacket, &pPacket->m_dwPacketSize	, sizeof( DWORD ) );
	memcpy( ( pPacket->m_pPacket + sizeof( DWORD ) ), pBuffer, dwSize );

	pSocket->m_cs_queueSend.Enter();
	pSocket->m_queueSend.push( pPacket );
	pSocket->m_cs_queueSend.Leave();

	// 叫醒 SendThread 工作 , 壓力檢查 / 優先排序 / 加密 / 壓縮 / 傳送
	//WSASetEvent( pSocket->m_overlapped_Send.hEvent );
	SetEvent( pSocket->m_event_PreSend );

	//iReturn	=	WSASend( pSocket->m_tcp_socket, &wBuf, 1, &dwBytes, 0, &pSocket->m_overlapped_Send, NULL );
	*/

}
