// Include
#include "gamesrv.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;

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

	if ( mLogin.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( &mLogin.sin_addr, phe->h_addr_list[0], phe->h_length );
		else
			return false;
	}

	// Game 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)
{
	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_GAME_LOG, MB_SERVER_EVENT, mLog );
	if ( serverEvent != NULL )
	{
		char*  source   = g_gameSrv->GetServiceName( );
		char*  computer = g_gameSrv->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_GAME_LOG, MB_MEMBER_EVENT, mLog );
	if ( memberEvent != NULL )
	{
		char*  source   = g_gameSrv->GetServiceName( );
		char*  computer = g_gameSrv->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;
}

// PostCharacterEvent Method
bool cSender::PostCharacterEvent(char category, long memberIdx, long serverIdx, long characterIdx, char* message)
{
	HANDLE           handle         = NULL;
	CHARACTER_EVENT* characterEvent = (CHARACTER_EVENT*)GetPacket( &handle, TOS_GAME_LOG, MB_CHARACTER_EVENT, mLog );
	if ( characterEvent != NULL )
	{
		char*  computer = g_gameSrv->GetHostName( );
		u_long length   = sizeof(CHARACTER_EVENT) - sizeof(characterEvent->message);

		GetRegisterDate( &characterEvent->registerDate );
		characterEvent->category     = category;
		characterEvent->memberIdx    = memberIdx;
		characterEvent->serverIdx    = serverIdx;
		characterEvent->characterIdx = characterIdx;
		strcpy( characterEvent->computer, computer );
		strcpy( characterEvent->message, message );

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

// PostMoneyEvent Method
bool cSender::PostMoneyEvent(long serverIdx, long characterIdx, long before, long after, char* message)
{
	HANDLE       handle     = NULL;
	MONEY_EVENT* moneyEvent = (MONEY_EVENT*)GetPacket( &handle, TOS_GAME_LOG, MB_MONEY_EVENT, mLog );
	if ( moneyEvent != NULL )
	{
		char*  computer = g_gameSrv->GetHostName( );
		u_long length   = sizeof(MONEY_EVENT) - sizeof(moneyEvent->message);

		GetRegisterDate( &moneyEvent->registerDate );
		moneyEvent->serverIdx    = serverIdx;
		moneyEvent->characterIdx = characterIdx;
		moneyEvent->before       = before;
		moneyEvent->after        = after;
		strcpy( moneyEvent->computer, computer );
		strcpy( moneyEvent->message, message );

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

// PostDepositEvent Method
bool cSender::PostDepositEvent(long serverIdx, long characterIdx, long before, long after, char* message)
{
	HANDLE         handle = NULL;
	DEPOSIT_EVENT* depositEvent = (DEPOSIT_EVENT*)GetPacket( &handle, TOS_GAME_LOG, MB_DEPOSIT_EVENT, mLog );
	if ( depositEvent != NULL )
	{
		char*  computer = g_gameSrv->GetHostName( );
		u_long length   = sizeof(DEPOSIT_EVENT) - sizeof(depositEvent->message);

		GetRegisterDate( &depositEvent->registerDate );
		depositEvent->serverIdx    = serverIdx;
		depositEvent->characterIdx = characterIdx;
		depositEvent->before       = before;
		depositEvent->after        = after;
		strcpy( depositEvent->computer, computer );
		strcpy( depositEvent->message, message );

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

// PostInventoryEvent Method
bool cSender::PostInventoryEvent(long serverIdx, char category, long inventoryIdx, long characterIdx, long itemDefineIndex, short number, short count, BYTE enhanced, BYTE seal, char* message)
{
	HANDLE           handle = NULL;
	INVENTORY_EVENT* inventoryEvent = (INVENTORY_EVENT*)GetPacket( &handle, TOS_GAME_LOG, MB_INVENTORY_EVENT, mLog );
	if ( inventoryEvent != NULL )
	{
		char*  computer = g_gameSrv->GetHostName( );
		u_long length   = sizeof(INVENTORY_EVENT) - sizeof(inventoryEvent->message);

		GetRegisterDate( &inventoryEvent->registerDate );
		inventoryEvent->serverIdx       = serverIdx;
		inventoryEvent->category        = category;
		inventoryEvent->inventoryIdx    = inventoryIdx;
		inventoryEvent->characterIdx    = characterIdx;
		inventoryEvent->itemDefineIndex = itemDefineIndex;
		inventoryEvent->number          = number;
		inventoryEvent->count           = count;
		inventoryEvent->enhanced        = enhanced;
		inventoryEvent->seal            = seal;
		strcpy( inventoryEvent->computer, computer );
		strcpy( inventoryEvent->message, message );

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

// PostQuestEvent Method
bool cSender::PostQuestEvent(long serverIdx, char category, long characterIdx, long questIdx, char* message)
{
	HANDLE       handle     = NULL;
	QUEST_EVENT* questEvent = (QUEST_EVENT*)GetPacket( &handle, TOS_GAME_LOG, MB_QUEST_EVENT, mLog );
	if ( questEvent != NULL )
	{
		char*  computer = g_gameSrv->GetHostName();
		u_long length   = sizeof(QUEST_EVENT) - sizeof(questEvent->message);

		GetRegisterDate( &questEvent->registerDate );
		questEvent->serverIdx	 = serverIdx;
		questEvent->category	 = category;
		questEvent->characterIdx = characterIdx;
		questEvent->questIdx	 = questIdx;
		strcpy( questEvent->computer, computer );
		strcpy( questEvent->message, message );

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

bool cSender::PostGuildEvent( long serverIdx, long characterIdx, long guildIdx, char guildPosition, char* message )
{
	HANDLE		handle		= NULL;
	GUILD_EVENT* guildEvent = (GUILD_EVENT*)GetPacket( &handle, TOS_GAME_LOG, MB_GUILD_EVENT, mLog );
	if( guildEvent != NULL )
	{
		char* computer = g_gameSrv->GetHostName();
		u_long length  = sizeof(GUILD_EVENT) - sizeof(guildEvent->message);

		GetRegisterDate( &guildEvent->registerDate );
		guildEvent->serverIdx		= serverIdx;
		guildEvent->characterIdx	= characterIdx;
		guildEvent->guildIdx		= guildIdx;
		guildEvent->guildPosition	= guildPosition;
		strcpy( guildEvent->computer, computer );
		strcpy( guildEvent->message, message );

		length += strlen(guildEvent->message);
		return SendPacket( handle, 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, mLogin );
	if ( synChStatus != NULL )
	{
		synChStatus->cid    = cid;
		synChStatus->status = status;
		return SendPacket( handle, sizeof(MB_SYN_CH_STATUS) );
	}
	return false;
}

// PostServerNotice Method
bool cSender::PostServerNotice(long cid, wchar_t* message)
{
	HANDLE                handle       = NULL;
	MB_SYN_SERVER_NOTICE* serverNotice = (MB_SYN_SERVER_NOTICE*)GetPacket( &handle, TOS_GAME, MB_SERVER_NOTICE_SYN, mGame );
	if ( serverNotice != NULL )
	{
		serverNotice->cid = cid;
		wcscpy( serverNotice->message, message );

		return SendPacket( handle, sizeof(MB_SYN_SERVER_NOTICE) );
	}
	return false;
}

// PostChatShout Method
bool cSender::PostChatShout(long cid, unsigned short numOfMap, long characterIdx, wchar_t* name, wchar_t* message)
{
	HANDLE             handle    = NULL;
	MB_SYN_CHAT_SHOUT* chatShout = (MB_SYN_CHAT_SHOUT*)GetPacket( &handle, TOS_GAME, MB_CHAT_SHOUT_SYN, mGame );
	if ( chatShout != NULL )
	{
		chatShout->cid          = cid;
		chatShout->numOfMap     = numOfMap;
		chatShout->characterIdx = characterIdx;
		wcscpy( chatShout->name,    name    );
		wcscpy( chatShout->message, message );

		return SendPacket( handle, sizeof(MB_SYN_CHAT_SHOUT) );
	}
	return false;
}

// PostPVPJoin Method
bool cSender::PostPVPStatus(long cid, BYTE status)
{
	HANDLE             handle  = NULL;
	MB_SYN_PVP_STATUS* postMsg = (MB_SYN_PVP_STATUS*)GetPacket( &handle, TOS_GAME, MB_PVP_STATUS_SYN, mGame );
	if ( postMsg != NULL )
	{
		postMsg->cid    = cid;
		postMsg->status = status;
		return SendPacket( handle, sizeof(MB_SYN_PVP_STATUS) );
	}
	return false;
}

// PostPVPJoin Method
bool cSender::PostPVPNotice( long cid, unsigned char leftMinute )
{
	HANDLE             handle  = NULL;
	MB_SYN_PVP_NOTICE* postMsg = (MB_SYN_PVP_NOTICE*)GetPacket( &handle, TOS_GAME, MB_PVP_NOTICE_SYN, mGame );
	if ( postMsg != NULL )
	{
		postMsg->cid    = cid;
		postMsg->leftMinute = leftMinute;
		return SendPacket( handle, sizeof(MB_SYN_PVP_NOTICE) );
	}
	return false;
}

// PostGuildSync Method
bool cSender::PostGuildSync(long cid, char* msg, int len)
{
	HANDLE             handle    = NULL;
	MB_SYN_GUILD_SYNC* guildSync = (MB_SYN_GUILD_SYNC*)GetPacket( &handle, TOS_GAME, MB_GUILD_SYNC_SYN, mGame );
	unsigned long      length;
	if ( guildSync != NULL )
	{
		length = sizeof(MB_SYN_GUILD_SYNC)-sizeof(guildSync->msg);

		guildSync->cid = cid;
		memcpy( guildSync->msg, msg, len );

		length += len;
		return SendPacket( handle, length );
	}
	return false;
}

// PostGuildConnectSync
bool cSender::PostGuildConnectSync( long cid )
{
	HANDLE             handle    = NULL;
	MB_SYN_GUILD_CONNECTSYNC* guildSync = (MB_SYN_GUILD_CONNECTSYNC*)GetPacket( &handle, TOS_GAME, MB_GUILD_CONNECTSYNC_SYN, mGame );
	if ( guildSync != NULL )
	{
		guildSync->cid    = cid;
		return SendPacket( handle, sizeof(MB_SYN_GUILD_CONNECTSYNC) );
	}
	return false;
}

// PostMonsterSync Method
bool cSender::PostMonsterSync( long cid, char* msg, int len )
{
	HANDLE             handle    = NULL;
	MB_SYN_MONSTER_SYNC* pSync = (MB_SYN_MONSTER_SYNC*)GetPacket( &handle, TOS_GAME, MB_MONSTER_SYN_SYN, mGame );
	unsigned long      length;
	if( pSync != NULL )
	{
		length = sizeof(MB_SYN_MONSTER_SYNC)-sizeof(pSync->msg);

		pSync->cid = cid;
		memcpy( pSync->msg, msg, len );

		length += len;
		return SendPacket( handle, length );
	}
	return false;
}

bool cSender::PostChatSync( long cid, char* msg, int len )
{
	HANDLE				handle	 = NULL;
	MB_SYN_CHAT_SYNC*	chatSync = (MB_SYN_CHAT_SYNC*)GetPacket( &handle, TOS_GAME, MB_CHAT_SYN, mGame );
	unsigned long		length	 = 0;
	if( chatSync != NULL )
	{
		length = sizeof(MB_SYN_CHAT_SYNC)-sizeof(chatSync->msg);

		chatSync->cid = cid;
		memcpy( chatSync->msg, msg, len );

		length += len;
		return SendPacket( handle, length );
	}
	return false;
}

