// Session.cpp : implementation file
//

#include "stdafx.h"
#include "gosview.h"
#include "Session.h"
#include "gosviewdoc.h"

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


const char *CSession::ConnectStateName[7] =
{
	"Not Connected",
	"Awaiting Connection",
	"Connected",
	"Receiving Log Header",
	"Receiving Log",
	"Processing Log",
	"Session Error"
};


/////////////////////////////////////////////////////////////////////////////
// CSession



CSession::CSession()
{
	m_eState = NotConnected;

	WORD wVersionRequired = MAKEWORD(1,1);
	WSADATA wsaData;

	if( WSAStartup( wVersionRequired, &wsaData ) )
	{
		DebugBreak();
	}
/*
	char hostName[50];
	PHOSTENT pHostEnt;

	if( ( gethostname( hostName, 50 ) != 0 ) ||
		( ( pHostEnt = gethostbyname(hostName)) == NULL ) )
	{
		DebugBreak();
	}
	wsprintf( m_IPAddr, "%s", inet_ntoa(*(in_addr *) pHostEnt->h_addr) );
*/	
}


CSession::~CSession()
{
	KillTimer(1);
	Disconnect();
	WSACleanup();
}


BEGIN_MESSAGE_MAP(CSession, CWnd)
	//{{AFX_MSG_MAP(CSession)
	ON_WM_TIMER()
	ON_WM_CREATE()
	//}}AFX_MSG_MAP
	ON_MESSAGE( WM_USER+1 , OnAsyncLog )
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CSession message handlers


void CSession::Connect( char *name )
{
	if( m_eState != NotConnected )
		return;

	// create sockets
	m_CommandSocket = socket( AF_INET, SOCK_STREAM, 0 );
	if( m_CommandSocket == INVALID_SOCKET )
	{
		DebugBreak();
	}
	m_LogSocket = socket( AF_INET, SOCK_STREAM, 0 );
	if( m_LogSocket == INVALID_SOCKET )
	{
		DebugBreak();
	}

	SOCKADDR_IN addr;
	addr.sin_family = AF_INET;
	//addr.sin_port = _htons(pservent->s_port);
	addr.sin_port = 0;
	addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);

	if( bind( m_CommandSocket, (LPSOCKADDR)&addr, sizeof(addr) ) == SOCKET_ERROR )
	{
		DebugBreak();
	}

	if( bind( m_LogSocket, (LPSOCKADDR)&addr, sizeof(addr) ) == SOCKET_ERROR )
	{
		DebugBreak();
	}

	PHOSTENT pHostEnt;

	if( ( pHostEnt = gethostbyname(name)) == NULL )
	{
		return;
	}
	wsprintf( m_IPAddr, "%s", inet_ntoa(*(in_addr *) pHostEnt->h_addr) );

	//	m_hClientThread=CreateThread(NULL, 0, CreateClientThread, (void *)this, 0, &ID );


	m_pTargetName = name;
	m_eState = AwaitingConnection;
	SOCKADDR_IN addrServer;

	addrServer.sin_family = AF_INET;
	addrServer.sin_port = htons(3002);
	
	addrServer.sin_addr.s_addr = inet_addr( m_IPAddr /* "157.55.22.191" /* m_pTargetName */ );
	if( connect(m_CommandSocket,(LPSOCKADDR)&addrServer, sizeof(addrServer) ) == SOCKET_ERROR )
	{
		int nError = WSAGetLastError();
	}


	addrServer.sin_family = AF_INET;
	addrServer.sin_port = htons(3001);
	addrServer.sin_addr.s_addr = inet_addr( m_IPAddr /* "157.55.22.191" /* m_pTargetName */ );

	if( WSAAsyncSelect( m_LogSocket, m_hWnd, WM_USER+1, FD_CONNECT|FD_READ|FD_WRITE|FD_CLOSE ) == SOCKET_ERROR )
	{
		DebugBreak();
	}

	if( connect(m_LogSocket,(LPSOCKADDR)&addrServer, sizeof(addrServer) ) == SOCKET_ERROR )
	{
		int nError = WSAGetLastError();

		if( nError == WSAEWOULDBLOCK )
		{
			;
		}
		else
		{

			if( nError == WSAECONNREFUSED )
			{
				m_eState = SessionError;
			}

			if( nError == WSAETIMEDOUT )
			{
				m_eState = SessionError;
			}
		}
	}

	_int64 freq;
	SendCommand( GVCMD_GETFREQ, 0, NULL );
	ReceiveData( 8, (char *)&freq );
	m_pDoc->SetFreq( freq );
}

void CSession::Disconnect()
{
	if( m_eState != NotConnected )
	{
		m_eState = NotConnected;
		if( m_CommandSocket )
			SendCommand( GVCMD_CLOSECONNECTIONS, 0, NULL );
		if( m_CommandSocket )
			closesocket( m_CommandSocket );
		if( m_LogSocket )
			closesocket( m_LogSocket );
	}
}


long CSession::OnAsyncLog( WPARAM wParam, LPARAM lParam )
{
	int nBytesReceived;

	if( WSAGETSELECTERROR(lParam) != 0 )
	{
		return 0L;
	}

	switch( WSAGETSELECTEVENT(lParam) )
	{
	case FD_CONNECT:
		m_eState = Connected;
		break;
	case FD_READ:
		switch( m_eState )
		{
		case Connected:
			m_eState = ReceivingLogHeader;
			m_nLogBytesRequired = sizeof( GosLogInfo );
			m_pLogReceiveAddr = (char *)&m_IncomingInfo;
		case ReceivingLogHeader:
			nBytesReceived = recv( m_LogSocket, m_pLogReceiveAddr, m_nLogBytesRequired, 0 );
			if( nBytesReceived == SOCKET_ERROR )
			{
				int m_nLastError = WSAGetLastError();
				if( m_nLastError == WSAEWOULDBLOCK )
				{
					m_eState = Connected;
					break;
				}
				m_eState = SessionError;
				break;
			}
			if( nBytesReceived == 0 )
				m_eState = Connected;
			m_nLogBytesRequired -= nBytesReceived;
			if( m_nLogBytesRequired )
				break;
			m_eState = ReceivingLog;
			m_nLogBytesRequired = m_IncomingInfo.logLength;
			m_pIncomingLogBuffer = (unsigned long *)malloc( m_IncomingInfo.logLength );
			m_pLogReceiveAddr = (char *)m_pIncomingLogBuffer;
		case ReceivingLog:
			if( m_nLogBytesRequired )
			{
				nBytesReceived = recv( m_LogSocket, m_pLogReceiveAddr, m_nLogBytesRequired, 0 );
				if( nBytesReceived == SOCKET_ERROR )
				{
					int m_nLastError = WSAGetLastError();
					if( m_nLastError == WSAEWOULDBLOCK )
					{
						break;
					}
					m_eState = SessionError;
					break;
				}
				m_nLogBytesRequired -= nBytesReceived;
				m_pLogReceiveAddr += nBytesReceived;
				if( m_nLogBytesRequired )
					break;
			}
			m_eState = ProcessingLog;
			m_pDoc->ParseNewLog( m_pIncomingLogBuffer, &m_IncomingInfo );
			m_pIncomingLogBuffer = NULL;	// NOTE: CGosViewDoc now owns the log buffer
		case ProcessingLog:

			m_eState = Connected;
			break;
		default:
			;
		}
		break;
	default:
		;
	}

	return 0;
}

void CSession::OnTimer(UINT nIDEvent) 
{
	if( m_eState == Connected )
	{
		SendCommand( GVCMD_HEARTBEAT, 0, NULL );
	}
}

int CSession::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CWnd::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	SetTimer(1,4000,NULL);	// every 4 seconds send a keep-alive heartbeat
	
	return 0;
}
