// DWBS ------------------------------------------------------------------ DWBS
//
// PLATFORM		: ALL
// PRODUCT		: BIT_DEMON
// VISIBILITY	: PUBLIC
//
// DWBS ------------------------------------------------------------------ DWBS

#include <bdExample/bdExampleCommonLobby/bdExampleCommonLobby.h>

void BD_CALL IndexStrings(const bdNChar8 *const strings[],
						  const bdUInt numStrings,
						  const bdUInt index,
						  bdString& dest)
{
	if(index < numStrings)
	{
		dest = strings[index];
	}
	else
	{
		dest = "String index out of range";
	}
}

void BD_CALL LobbyErrorCodeToString(const bdLobbyErrorCode code,
									bdNChar8 *const buffer,
									const bdUWord bufferSize)
{
// set up the macros to create an array of enum values
#define BD_LOBBY_ERROR_CODES_BEGIN	bdLobbyErrorCode lookup[] = {
#define BD_LOBBY_ERROR_CODE(c, v)	c,
#define BD_LOBBY_ERROR_CODES_END(c)	c };

// include the error values
#include <bdLobby/bdLobbyErrorCodes.h>

#undef BD_LOBBY_ERROR_CODES_BEGIN
#undef BD_LOBBY_ERROR_CODE
#undef BD_LOBBY_ERROR_CODES_END

// set up the macros to create an array of strings
#define BD_LOBBY_ERROR_CODES_BEGIN	bdNChar8* lobbyErrorCodeDescs[] = {
#define BD_LOBBY_ERROR_CODE(c, v)	#c,
#define BD_LOBBY_ERROR_CODES_END(c)	#c };

// include the error values
#include <bdLobby/bdLobbyErrorCodes.h>

#undef BD_LOBBY_ERROR_CODES_BEGIN
#undef BD_LOBBY_ERROR_CODE
#undef BD_LOBBY_ERROR_CODES_END

	const bdUInt numCodes = sizeof(lobbyErrorCodeDescs) / sizeof(bdNChar8*);

	// find the index of the code in the lookup array
	const bdNChar8 *desc = "Unknown bdLobbyErrorCode";

	bdBool found = false;
	for(bdUInt i = 0; !found && (i < numCodes); i++)
	{
		if(lookup[i] == code)
		{
			desc = lobbyErrorCodeDescs[i];
			found = true;
		}
	}

	bdStrlcpy(buffer, desc, bufferSize);
}

void BD_CALL LobbyMessageTypeToString(const bdLobbyMessageType type,
									  bdNChar8 *const buffer,
									  const bdUWord bufferSize)
{
// set up the macros to create an array of enum values
#define BD_LOBBY_MESSAGE_TYPES_BEGIN	bdLobbyMessageType lookup[] = {
#define BD_LOBBY_MESSAGE_TYPE(MSG_TYPE_NAME, MSG_TYPE_VAL, MSG_IMPL, MSG_CLASSNAME)	MSG_TYPE_NAME,
#define BD_LOBBY_MESSAGE_TYPES_END(MSG_TYPE_NAME)	MSG_TYPE_NAME };

// include the error values
#include <bdLobby/bdMessageStore/bdMessageTypes/bdLobbyMessageTypes.h>

#undef BD_LOBBY_MESSAGE_TYPES_BEGIN
#undef BD_LOBBY_MESSAGE_TYPE
#undef BD_LOBBY_MESSAGE_TYPES_END

// set up the macros to create an array of strings
#define BD_LOBBY_MESSAGE_TYPES_BEGIN	bdNChar8* lobbyMessageTypeDescs[] = {
#define BD_LOBBY_MESSAGE_TYPE(MSG_TYPE_NAME, MSG_TYPE_VAL, MSG_IMPL, MSG_CLASSNAME)	#MSG_TYPE_NAME,
#define BD_LOBBY_MESSAGE_TYPES_END(MSG_TYPE_NAME)	#MSG_TYPE_NAME };

// include the error values
#include <bdLobby/bdMessageStore/bdMessageTypes/bdLobbyMessageTypes.h>

#undef BD_LOBBY_MESSAGE_TYPES_BEGIN
#undef BD_LOBBY_MESSAGE_TYPE
#undef BD_LOBBY_MESSAGE_TYPES_END

	const bdUInt numTypes = sizeof(lobbyMessageTypeDescs) / sizeof(bdNChar8*);

	// find the index of the type in the lookup array
	const bdNChar8 *desc = "Unknown bdLobbyMessageType";

	bdBool found = false;
	for(bdUInt i = 0; !found && (i < numTypes); i++)
	{
		if(lookup[i] == type)
		{
			desc = lobbyMessageTypeDescs[i];
			found = true;
		}
	}

	bdStrlcpy(buffer, desc, bufferSize);
}

#ifndef BD_PLATFORM_XENON

TaskStatus BD_CALL StartGetHostByName(const bdNChar8 *const domainNameStr,
									  bdGetHostByName **getHostByName,
									  const bdInetAddr resolvedAddr)
{
	// fail safe
	TaskStatus taskStatus = FAILED;

	// is the address already resolved
	if(!resolvedAddr.isValid())
	{
		// DNS lookup objects are transitory so we create them on the heap
		bdGetHostByName *getHostByNamePtr = BD_NULL;

		if(*getHostByName == BD_NULL)
		{
			*getHostByName = new bdGetHostByName();
			getHostByNamePtr = *getHostByName;
		}

		if(getHostByNamePtr)
		{
			if(getHostByNamePtr->start(domainNameStr, DNS_LOOKUP_TIMEOUT))
			{
				taskStatus = PENDING;
			}
		}
	}
	else
	{
		taskStatus = DONE;
	}

	return taskStatus;
}

TaskStatus BD_CALL PumpGetHostByName(bdGetHostByName **getHostByName,
									 bdInetAddr &resolvedAddr)
{
	// fail safe
	TaskStatus taskStatus = FAILED;

	if(getHostByName)
	{
		bdGetHostByName *const getHostByNamePtr = *getHostByName;
		if(getHostByNamePtr)
		{
			const bdGetHostByName::bdStatus getHostByNameStatus = getHostByNamePtr->getStatus();

			// there is no need for a switch here, but with it in the compiler will
			// warn us if any new states are added to bdGetHostByName::Status
			switch(getHostByNameStatus)
			{
				case bdGetHostByName::BD_FAILED:
				{
					// error conditions
					taskStatus = FAILED;
				}
				break;
				case bdGetHostByName::BD_PENDING:
				{
					// wait
					taskStatus = PENDING;
				}
				break;
				case bdGetHostByName::BD_READY:
				{
					// finished
					const bdBool addrResolved = getHostByNamePtr->getNumAddresses() > 0;
					if(addrResolved)
					{
						const bdInAddr inAddr = getHostByNamePtr->getAddressAt(0);
						resolvedAddr.set(inAddr);
					}

					if(addrResolved && resolvedAddr.isValid())
					{
						taskStatus = DONE;
					}
				}
			}

			if((taskStatus == FAILED) || (taskStatus == DONE))
			{
				delete getHostByNamePtr;
				*getHostByName = BD_NULL;
			}
		}
	}

	return taskStatus;
}
#endif //#ifndef BD_PLATFORM_XENON


TaskStatus BD_CALL CheckRemoteTaskStatus(bdRemoteTask *const remoteTask)
{
	// fail safe
	TaskStatus status = FAILED;

	if(remoteTask)
	{
		const bdRemoteTask::bdStatus remoteTaskStatus = remoteTask->getStatus();
		switch(remoteTaskStatus)
		{
			case bdRemoteTask::BD_EMPTY:
			case bdRemoteTask::BD_TIMED_OUT:
			{
				status = FAILED;
			}
			break;
			case bdRemoteTask::BD_PENDING:
			{
				status = PENDING;
			}
			break;
			case bdRemoteTask::BD_DONE:
			{
				status = DONE;
			}
			break;
			default:
				break;
		}
	}
	return status;
}

void BD_CALL CloseRemoteTask(bdRemoteTask **remoteTask)
{
	if(remoteTask)
	{
		bdRemoteTask *const remoteTaskPtr = *remoteTask;
		if(remoteTaskPtr)
		{
			remoteTaskPtr->close();
			*remoteTask = BD_NULL;
		}
	}
}

bdMatchMaking* BD_CALL GetMatchMaking()
{
	bdMatchMaking *matchmaking = BD_NULL;
	bdLobbyServiceImpl *const lobbyService = bdLobbyService::getInstance();
	if(lobbyService)
	{
		matchmaking = lobbyService->getMatchMaking();
	}
	return matchmaking;
}

bdStats* BD_CALL GetStats()
{
	bdStats *stats = BD_NULL;
	bdLobbyServiceImpl *const lobbyService = bdLobbyService::getInstance();
	if(lobbyService)
	{
		stats = lobbyService->getStats();
	}
	return stats;

}

bdProfiles* BD_CALL GetProfiles()
{
	bdProfiles *profiles = BD_NULL;
	bdLobbyServiceImpl *const lobbyService = bdLobbyService::getInstance();
	if(lobbyService)
	{
		profiles = lobbyService->getProfilesManager();
	}
	return profiles;
}

bdFriends* BD_CALL GetFriends()
{
	bdFriends *friends = BD_NULL;
	bdLobbyServiceImpl *const lobbyService = bdLobbyService::getInstance();
	if(lobbyService)
	{
		friends = lobbyService->getFriends();
	}
	return friends;
}

bdChannelChat* BD_CALL GetChannelChat()
{
	bdChannelChat* channelchat = BD_NULL;
	bdLobbyServiceImpl *const lobbyService = bdLobbyService::getInstance();
	if(lobbyService)
	{
		channelchat = lobbyService->getChannelChat();
	}
	return channelchat;
}

bdTeams* BD_CALL GetTeams()
{
	bdTeams* teams = BD_NULL;
	bdLobbyServiceImpl *const lobbyService = bdLobbyService::getInstance();
	if(lobbyService)
	{
		teams = lobbyService->getTeams();
	}
	return teams;
}

bdMessageStore* BD_CALL GetMessageStore()
{
	bdMessageStore* messageStore = BD_NULL;
	bdLobbyServiceImpl *const lobbyService = bdLobbyService::getInstance();
	if(lobbyService)
	{
		messageStore = lobbyService->getMessageStore();
	}
	return messageStore;
}

bdTitleUtilities* BD_CALL GetTitleUtilities()
{
	bdTitleUtilities* titleUtilities = BD_NULL;
	bdLobbyServiceImpl *const lobbyService = bdLobbyService::getInstance();
	if(lobbyService)
	{
		titleUtilities = lobbyService->getTitleUtilities();
	}
	return titleUtilities;
}

void BD_CALL printInfo(const bdChannelInfo& channelInfo,
					   bdNChar8 *buf,
					   const bdUInt length)
{
	bdSnprintf(buf, length, "%s (%u/%u)", channelInfo.m_channelName, channelInfo.m_numSubscribers, channelInfo.m_maxSubscribers);
}

void BD_CALL printInfo(const bdGetChannelMembersResult::bdChannelMember& memberInfo,
					   bdNChar8 *buf,
					   const bdUInt length)
{
	bdStrlcpy(buf, memberInfo.m_userName, length);
}

bdKeyArchive* BD_CALL GetKeyArchive()
{
	bdKeyArchive* keyArchive = BD_NULL;
	bdLobbyServiceImpl *const lobbyService = bdLobbyService::getInstance();
	if(lobbyService)
	{
		keyArchive = lobbyService->getKeyArchive();
	}
	return keyArchive;
}
