// ClientSocket.cpp : implementation file
//

#include "stdafx.h"
#include "PSAT.h"
#include "ClientSocket.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CClientSocket

CClientSocket::CClientSocket()
{
	m_nCurrState = DISCONNECTED;

	CAsyncSocket::CAsyncSocket();
}

CClientSocket::~CClientSocket()
{
}


// Do not edit the following lines, which are needed by ClassWizard.
#if 0
BEGIN_MESSAGE_MAP(CClientSocket, CAsyncSocket)
	//{{AFX_MSG_MAP(CClientSocket)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()
#endif	// 0

/////////////////////////////////////////////////////////////////////////////
// CClientSocket member functions
BOOL CClientSocket::IsConnected()
{
	if ( m_nCurrState < 4 ) // Connecting도 Connected된 상태가 아니다.
	{
		return FALSE;
	}
	return TRUE;
}

int CClientSocket::SendData( KPacket* pData )
{
	if ( !IsConnected() ) return MYSOCK_PROGRAMMING_ERROR;

	if ( m_WriteBuffer.GetLength() > 0 )
	{
		m_WriteBuffer.SetData ( (BYTE *)pData , pData->m_nPacketSize );
		SendWouldBlockData();
		return 0;
	}
	int nTotalSentSize = 0;
	while ( 1 )
	{
		int nSentDataSize = Send ( pData, pData->m_nPacketSize );
		if ( nSentDataSize > 0 )
		{
			nTotalSentSize += nSentDataSize;
			if ( pData->m_nPacketSize == nTotalSentSize )
			{
				break;
			}
		}
		else	// Error
		{
			if ( WSAEWOULDBLOCK == GetLastError() )
			{
				m_WriteBuffer.SetData ( ((BYTE *)pData) + nTotalSentSize , pData->m_nPacketSize - nTotalSentSize );
			}
			else
			{
				Disconnect();
			}
			break;
		}
	}
	
	return nTotalSentSize;
}

void CClientSocket::SetWnd(HWND hwnd)
{
	m_pHwnd = hwnd;
}

void CClientSocket::OnClose(int nErrorCode) 
{
	Disconnect();

	::SendMessage ( m_pHwnd , WM_SOCKET_DISCONNECTED , 0 , 0 );

	CAsyncSocket::OnClose(nErrorCode);
}

void CClientSocket::Linger()
{
	int what = 0;
	struct linger sL;
	sL.l_onoff = 1; // linger on
	sL.l_linger = 0; // waiting time (sec.)
	what = CAsyncSocket::SetSockOpt( SO_LINGER, (void*)&sL, sizeof( sL ) );
	if ( what == SOCKET_ERROR )
	{
		; // ??????
	}
}

void CClientSocket::Disconnect()
{
	m_ReadBuffer.Empty();
	m_WriteBuffer.Empty();

	if ( m_nCurrState < 3 ) 
	{
		return;
	}
	int nStatus = MYSOCK_NOERROR;
	m_nCurrState = DISCONNECTTING;
	
	if ( m_hSocket == INVALID_SOCKET )
	{
		m_nCurrState = DISCONNECTED;
		return;
	}

	Linger();

	CAsyncSocket::AsyncSelect( FD_CLOSE );
	CAsyncSocket::ShutDown();
	CAsyncSocket::Close();

	m_nCurrState = DISCONNECTED;
}

void CClientSocket::OnReceive(int nErrorCode) 
{
	char szBuffer[BUFFERING_SIZE];
	memset ( szBuffer, 0, sizeof ( szBuffer ) );
	int nLength = Receive ( szBuffer, BUFFERING_SIZE );
	if ( nLength > 0 )
	{
		m_ReadBuffer.SetData( (BYTE*)szBuffer, nLength );
		KPacket	* pPacket = NULL;
		int i = 0;
		while ( m_ReadBuffer.GetLength() >= sizeof ( KPacket ) ) 
		{
			pPacket = (KPacket *)m_ReadBuffer.GetBuffer();
			if ( m_ReadBuffer.GetLength() >= pPacket->m_nPacketSize ) 
			{
				::SendMessage(m_pHwnd, WM_SOCKET_RECEIVED_DATA, (WPARAM)pPacket , pPacket->m_nPacketSize );

				m_ReadBuffer.UseBuffer( pPacket->m_nPacketSize );
			}
			else
			{
				break;
			}
			i++;
		}
	}
	else
	{
		Disconnect();
	}
}

void CClientSocket::OnConnect(int nErrorCode) 
{
	if ( 0 == nErrorCode )
	{
		m_nCurrState = CONNECTED;
		::SendMessage ( m_pHwnd , WM_SOCKET_CONNECTED , (WPARAM)this , 0 );
	}
	CAsyncSocket::OnConnect(nErrorCode);
}

int CClientSocket::Connect ( CString strAddr, int PortNo )
{
	int nStatus = MYSOCK_NOERROR; // is Zero
	if ( m_nCurrState ) return nStatus;

	int nStateCopy = m_nCurrState;
	m_nCurrState = CONNECTTING;

	if ( !CAsyncSocket::Create() )
	{
		return MYSOCK_WINSOCK_ERROR;
	}

	if ( CAsyncSocket::AsyncSelect( FD_READ | FD_WRITE | FD_CONNECT | FD_CLOSE ) == SOCKET_ERROR )
	{
		return MYSOCK_WINSOCK_ERROR;
	}

	CAsyncSocket::Connect ( strAddr, PortNo );
	return nStatus;
}

void CClientSocket::SendWouldBlockData()
{
	m_nCurrState = WRITING;
	if ( m_WriteBuffer.GetLength() > 0 )
	{
		int nTotalSentSize = 0;
		while ( 1 )
		{
			int nSentDataSize = Send ( m_WriteBuffer.GetBuffer() , m_WriteBuffer.GetLength() );
			if ( nSentDataSize > 0 )
			{
				m_WriteBuffer.UseBuffer ( nSentDataSize );
				if ( m_WriteBuffer.GetLength() == 0 )
				{
					break;
				}
			}
			else	
			{
				if ( WSAEWOULDBLOCK != GetLastError() )
				{
					Disconnect();
				}
				break;
			}
		}
	}
	m_nCurrState = CONNECTED;
}

void CClientSocket::OnSend(int nErrorCode) 
{
	if ( m_nCurrState == DISCONNECTTING ) return;
	if ( m_nCurrState == DISCONNECTED ) return;

	int nReturn = MYSOCK_NOERROR;
	if ( m_nCurrState != WRITING )
	{
		SendWouldBlockData();	
	}
	CAsyncSocket::OnSend(nErrorCode);
}
