// Include
#include "loginsrv.h"

// Local definitions
#pragma warning( disable: 4127 )
#pragma warning( disable: 4244 )
#pragma warning( disable: 4267 )

// Global data

// cSender Constructor
cSender::cSender(void)
{
}

// ~cSender Destructor
cSender::~cSender(void)
{
}

// Initialize Method
bool cSender::Initialize(char* addr, unsigned short numWorkerThreads)
{
	PHOSTENT phe;

	// Common Server IPv4 林家甫 父电促.
	ZeroMemory( (void*)&mGame, sizeof(SOCKADDR_IN) );
	mGame.sin_family = AF_INET;
	mGame.sin_port   = htons( U_GAME_SPORT );
	mGame.sin_addr.s_addr = inet_addr( addr );

	if ( mGame.sin_addr.s_addr == INADDR_NONE )
	{
		// the host name for the server is not in dot format, therefore try it just as a string
		if ( (phe = gethostbyname( addr )) != NULL )
			CopyMemory( &mGame.sin_addr, phe->h_addr_list[0], phe->h_length );
		else
			return false;
	}

	// LogDemon IPv4 林家甫 父电促.
	ZeroMemory( (void*)&mLog, sizeof(SOCKADDR_IN) );
	mLog.sin_family = AF_INET;
	mLog.sin_port   = htons( U_LOG_SPORT );
	mLog.sin_addr.s_addr = inet_addr( addr );

	if ( mLog.sin_addr.s_addr == INADDR_NONE )
	{
		// the host name for the server is not in dot format, therefore try it just as a string
		if ( (phe = gethostbyname( addr )) != NULL )
			CopyMemory( &mLog.sin_addr, phe->h_addr_list[0], phe->h_length );
		else
			return false;
	}

	return cIocpUdpSend::Initialize( numWorkerThreads );
}

// Shutdown Method
void cSender::Shutdown(DWORD maxWait)
{
	Sleep( 50 );
	cIocpUdpSend::Shutdown( maxWait );
}

// GetPacket Method
MSGBUF* cSender::GetPacket(void** handle, char tos, char protocol, SOCKADDR_IN addr)
{
	PerIoContext* perIoContext = mIoContextPool->GetIoContext( mSocket, IOCP_REQUEST_WRITE, addr );
	MSGBUF*       msgBuf       = NULL;

	if ( perIoContext != NULL )
	{
		Packet* packet = (Packet*)perIoContext->buffer;

		packet->ver  = PHVer;
		packet->hlen = PHLen;
		packet->tos  = tos;
		packet->tlen = packet->hlen;

		(*handle) = perIoContext;
		msgBuf    = (MSGBUF*)(perIoContext->buffer + packet->hlen);
		msgBuf->protocol = protocol;
	}

	return msgBuf;
}

// SendPacket Method
bool cSender::SendPacket(void* handle, unsigned long length)
{
	PerIoContext* perIoContext = (PerIoContext*)handle;
	Packet*       packet       = (Packet*)perIoContext->buffer;

	packet->tlen = packet->hlen + (u_short)length;

	perIoContext->offset = packet->tlen;
	return SendPost( perIoContext );
}

// GetRegisterDate Method
void cSender::GetRegisterDate(TIMESTAMP_STRUCT* ts)
{
	SYSTEMTIME st;
	GetLocalTime( &st );
	ts->year     = st.wYear;
	ts->month    = st.wMonth;
	ts->day      = st.wDay;
	ts->hour     = st.wHour;
	ts->minute   = st.wMinute;
	ts->second   = st.wSecond;
	ts->fraction = st.wMilliseconds * 1000000;
}

// PostServerEvent Method
bool cSender::PostServerEvent(char* message)
{
	HANDLE        handle      = NULL;
	SERVER_EVENT* serverEvent = (SERVER_EVENT*)GetPacket( &handle, TOS_LOGIN_LOG, MB_SERVER_EVENT, mLog );
	if ( serverEvent != NULL )
	{
		char*  source   = g_loginSrv->GetServiceName( );
		char*  computer = g_loginSrv->GetHostName( );
		u_long length   = sizeof(SERVER_EVENT) - sizeof(serverEvent->message);

		GetRegisterDate( &serverEvent->registerDate );
		strcpy( serverEvent->source, source );
		strcpy( serverEvent->computer, computer );
		strcpy( serverEvent->message, message );
		
		length += strlen(serverEvent->message);
		return SendPacket( handle, length );
	}
	return false;
}

// PostMemberEvent Method
bool cSender::PostMemberEvent(char type, char category, long memberIdx, char* message)
{
	HANDLE handle = NULL;
	MEMBER_EVENT* memberEvent = (MEMBER_EVENT*)GetPacket( &handle, TOS_LOGIN_LOG, MB_MEMBER_EVENT, mLog );
	if ( memberEvent != NULL )
	{
		char*  source   = g_loginSrv->GetServiceName( );
		char*  computer = g_loginSrv->GetHostName( );
		u_long length   = sizeof(MEMBER_EVENT) - sizeof(memberEvent->message);

		GetRegisterDate( &memberEvent->registerDate );
		memberEvent->type = type;
		strcpy( memberEvent->source, source );
		memberEvent->category = category;
		memberEvent->memberIdx = memberIdx;
		strcpy( memberEvent->computer, computer );
		strcpy( memberEvent->message, message );

		length += strlen( memberEvent->message );
		return SendPacket( handle, length );
	}
	return false;
}

// PostConcurrentEvent Method
bool cSender::PostConcurrentEvent(long serverIdx, long minimum, long maximum, char* message)
{
	HANDLE handle = NULL;
	CONCURRENT_EVENT* concurrentEvent = (CONCURRENT_EVENT*)GetPacket( &handle, TOS_LOGIN_LOG, MB_CONCURRENT_EVENT, mLog );
	if ( concurrentEvent != NULL )
	{
		char*  computer = g_loginSrv->GetHostName( );
		u_long length   = sizeof(CONCURRENT_EVENT) - sizeof(concurrentEvent->message);

		GetRegisterDate( &concurrentEvent->registerDate );
		concurrentEvent->serverIdx = serverIdx;
		concurrentEvent->minimum   = minimum;
		concurrentEvent->maximum   = maximum;
		strcpy( concurrentEvent->computer, computer );
		strcpy( concurrentEvent->message, message );

		length += strlen( concurrentEvent->message );
		return SendPacket( handle, length );
	}
	return false;
}

// PostChSync Method
bool cSender::PostChSync( )
{
	HANDLE          handle    = NULL;
	MB_SYN_CH_SYNC* synChSync = (MB_SYN_CH_SYNC*)GetPacket( &handle, TOS_GAME, MB_CH_SYNC_SYN, mGame );
	if ( synChSync != NULL )
	{
		return SendPacket( handle, sizeof(MB_SYN_CH_SYNC) );
	}
	return false;
}

// PostChList Method
bool cSender::PostChList(ServerTable* root)
{
	HANDLE          handle    = NULL;
	MB_SYN_CH_LIST* synChList = (MB_SYN_CH_LIST*)GetPacket( &handle, TOS_GAME, MB_CH_LIST_SYN, mGame );
	if ( synChList != NULL )
	{
		PerChannel* ch = root->pool;
		for ( BYTE i = 0; i < root->channelCounter; i++ )
		{
			synChList->channels[ i ].cid    = ch->cid;
			synChList->channels[ i ].status = ch->status;
			ch = ch->next;

			synChList->rowCount++;
		}
		return SendPacket( handle, synChList->Length( ) );
	}
	return false;
}

// PostChStatus Method
bool cSender::PostChStatus(long cid, BYTE status)
{
	HANDLE            handle      = NULL;
	MB_SYN_CH_STATUS* synChStatus = (MB_SYN_CH_STATUS*)GetPacket( &handle, TOS_GAME, MB_CH_STATUS_SYN, mGame );
	if ( synChStatus != NULL )
	{
		synChStatus->cid    = cid;
		synChStatus->status = status;
		return SendPacket( handle, sizeof(MB_SYN_CH_STATUS) );
	}
	return false;
}
