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

#include "Simulation.h"
#include "UserInfo.h"

#include <bdLobby/bdMessageStore/bdMessageTypes/bdTeamInvitationMessage.h>
#include <bdLobby/bdMessageStore/bdMessageTypes/bdTeamWideNotificationMessage.h>
#include <bdLobby/bdMessageStore/bdMessageTypes/bdTeamSessionInvitationMessage.h>
#include <bdLobby/bdMessageStore/bdMessageTypes/bdTeamCustomMessage.h>
#include <bdLobby/bdMessageStore/bdMessageTypes/bdLobbyMessageType.h>

#define TITLE_ID (0x12F7)
#define USERNAME1 "TeamsExample1"
#define USERNAME2 "TeamsExample2"
#define PASSWORD "MyPassword"

// Uncomment this next line to have example run without needing user input
//#define RUN_TEAMS_EXAMPLE_AUTOMATEDLY

Simulation::Simulation()
: m_taskStatus(READY),
  m_task(START_NETWORK),
  m_changedScreen(true),
  m_authGetHostByName(BD_NULL),
  m_authService(BD_NULL),
  m_lsgGetHostByName(BD_NULL),
  m_remoteTask(BD_NULL),
  m_pumpLobbyConnection(false),
  m_lobbyErrorCode(BD_NO_ERROR)
{
}

Simulation::~Simulation()
{
}

bdBool Simulation::init(bdInt32 ,
						bdNChar8* [])
{
	bdBool ok = true;

	// start logging
	// we want to hear about all warnings and errors
	bdLogImpl *log = bdLog::getInstance();
	log->subscribe("warn", &m_logSubscriber);
	log->subscribe("err", &m_logSubscriber);
	log->subscribe("info", &m_logSubscriber);

	return ok;
}

bdBool Simulation::step(const bdFloat32)
{
	const bdBool quitKey = getScreen().wasKeyPressed(BD_QUIT);

	TaskStatus oldTaskStatus = m_taskStatus;

	if(m_taskStatus == READY)
	{
		startTask();
	}

	if(m_taskStatus == PENDING || m_taskStatus == DONE || m_taskStatus == FAILED)
	{
		// pump even if the status is DONE or FAILED to read out any results
		// and close any remote task handles
		pumpTask();
	}

	if(m_taskStatus == DONE || m_taskStatus == FAILED || m_taskStatus == SKIPPED)
	{
		// incase the task fails or completes in a single loop
		if(oldTaskStatus == READY)
		{
			oldTaskStatus = m_taskStatus;
		}

		displayTaskResult();
	}

	m_changedScreen = (oldTaskStatus != m_taskStatus);

	if(m_pumpLobbyConnection)
	{
		bdBool lostConnection = true;
		bdLobbyServiceImpl *const lobbyService = bdLobbyService::getInstance();
		if(lobbyService)
		{
			const bdLobbyConnection::Status status = lobbyService->getStatus();
			switch(status)
			{
				case bdConnection::BD_NOT_CONNECTED:
				case bdConnection::BD_CONNECTING:
				case bdConnection::BD_DISCONNECTING:
				case bdConnection::BD_DISCONNECTED:
				{
					lostConnection = true;
				}
				break;
				case bdConnection::BD_CONNECTED:
				{
					lostConnection = false;
				}
				break;
			}
		}

		if(lostConnection)
		{
			// set up for a reconnect
			m_pumpLobbyConnection = false;
			m_task = STOP_NETWORK;
			m_taskStatus = READY;
			m_changedScreen = true;
			CloseRemoteTask(&m_remoteTask);
			m_lastTaskDescription = "Lost connection to lobby.";
		}
	}

	checkMessageStore();

	getScreen().printToScreen(m_screenText + m_messageText);

	if(m_changedScreen)
	{
		m_screenText = "";
	}

	return !quitKey;
}

void Simulation::quit()
{
	bdLogImpl *log = bdLog::getInstance();
	log->unsubscribe("warn", &m_logSubscriber);
	log->unsubscribe("err", &m_logSubscriber);
	log->unsubscribe("info", &m_logSubscriber);
	
	stopNetwork();

	delete m_authGetHostByName;
	delete m_authService;
	delete m_lsgGetHostByName;
	
	if(m_remoteTask)
	{
		m_remoteTask->close();
	}
}

void Simulation::startTask()
{	
	const bdBool skipKey = getScreen().wasKeyPressed(SKIP_KEY);

	if (skipKey)
	{
		m_taskStatus = SKIPPED;
	}
	else
	{
#ifdef RUN_TEAMS_EXAMPLE_AUTOMATEDLY
		const bdBool startKey = true;
#else
		const bdBool startKey = getScreen().wasKeyPressed(START_KEY);
#endif
		bdString taskDescription("Unknown task");

		switch(m_task)
		{
			case START_NETWORK:
			{
				startNetworkDescription(taskDescription);
				if(startKey)
				{
					startNetwork();
				}
			}
			break;
			case CHECK_DNS:
			{
				checkDNSDescription(taskDescription);
				if(startKey)
				{
					startCheckDNS();
				}
			}
			break;
			case CHOOSE_USER_ACCOUNT_1:
			{
				chooseUserAccount1Description(taskDescription);
				if(startKey)
				{
					startChooseUserAccount1();
				}
			}
			break;
			case CHOOSE_USER_ACCOUNT_2:
			{
				chooseUserAccount2Description(taskDescription);
				if(startKey)
				{
					startChooseUserAccount2();
				}
			}
			break;
			case CREATE_ACCOUNT:
			{
				createAccountDescription(taskDescription);
				if(startKey)
				{
					startCreateAccount();
				}
			}
			break;
			case AUTHENTICATE_ACCOUNT:
			{
				authenticateAccountDescription(taskDescription);
				if(startKey)
				{
					startAuthenticateAccount();
				}
			}
			break;
			case LOBBY_CONNECT:
			{
				lobbyServiceConnectDescription(taskDescription);
				if(startKey)
				{
					startLobbyServiceConnect();
				}
			}
			break;
			case CREATE_PROFILE:
			{
				createProfileDescription(taskDescription);
				if(startKey)
				{
					startCreateProfile();
				}
			}
			break;
			case GET_MESSAGES:
			{
				getMessagesDescription(taskDescription);
				if(startKey)
				{
					startGetMessages();
				}
			}
			break;
			case ACCEPT_MEMBERSHIP:
			{
				acceptMembershipDescription(taskDescription);
				if(startKey)
				{
					startAcceptMembership();
				}
			}
			break;
			case REJECT_MEMBERSHIP:
			{
				rejectMembershipDescription(taskDescription);
				if(startKey)
				{
					startRejectMembership();
				}
			}
			break;
			case ACCEPT_INVITATION:
			{
				acceptInvitationDescription(taskDescription);
				if(startKey)
				{
					startAcceptInvitation();
				}
			}
			break;
			case REJECT_INVITATION:
			{
				rejectInvitationDescription(taskDescription);
				if(startKey)
				{
					startRejectInvitation();
				}
			}
			break;
			case CHECK_MEMBERSHIPS:
			{
				checkMembershipsDescription(taskDescription);
				if(startKey)
				{
					startCheckMemberships();
				}
			}
			break;
			case CREATE_TEAM:
			{
				createTeamDescription(taskDescription);
				if(startKey)
				{
					startCreateTeam();
				}
			}
			break;
			case UPDATE_TEAM:
			{
				updateTeamDescription(taskDescription);
				if(startKey)
				{
					startUpdateTeam();
				}
			}
			break;
			case GET_MEMBERS:
			{
				getMembersDescription(taskDescription);
				if(startKey)
				{
					startGetMembers();
				}
			}
			break;
			case PROPOSE_MEMBERSHIP:
			{
				proposeMembershipDescription(taskDescription);
				if(startKey)
				{
					startProposeMembership();
				}
			}
			break;
			case GET_PROPOSALS:
			{
				getProposalsDescription(taskDescription);
				if(startKey)
				{
					startGetProposals();
				}
			}
			break;
			case WITHDRAW_PROPOSAL:
			{
				withdrawProposalDescription(taskDescription);
				if(startKey)
				{
					startWithdrawProposal();
				}
			}
			break;
			case INVITE_TO_SESSION:
			{
				inviteToSessionDescription(taskDescription);
				if(startKey)
				{
					startInviteToSession();
				}
			}
			break;
			case PROMOTE_MEMBER:
			{
				promoteMemberDescription(taskDescription);
				if(startKey)
				{
					startPromoteMember();
				}
			}
			break;
			case DEMOTE_MEMBER:
			{
				demoteMemberDescription(taskDescription);
				if(startKey)
				{
					startDemoteMember();
				}
			}
			break;
			case KICK_MEMBER:
			{
				kickMemberDescription(taskDescription);
				if(startKey)
				{
					startKickMember();
				}
			}
			break;
			case SET_PUBLIC_TEAM_INFO:
			{
				setPublicTeamInfoDescription(taskDescription);
				if(startKey)
				{
					startSetPublicTeamInfo();
				}
			}
			break;
			case GET_PUBLIC_TEAM_INFO:
			{
				getPublicTeamInfoDescription(taskDescription);
				if(startKey)
				{
					startGetPublicTeamInfo();
				}
			}
			break;
			case SET_PRIVATE_TEAM_INFO:
			{
				setPrivateTeamInfoDescription(taskDescription);
				if(startKey)
				{
					startSetPrivateTeamInfo();
				}
			}
			break;
			case GET_PRIVATE_TEAM_INFO:
			{
				getPrivateTeamInfoDescription(taskDescription);
				if(startKey)
				{
					startGetPrivateTeamInfo();
				}
			}
			break;
			case SET_PUBLIC_MEMBER_INFO:
			{
				setPublicMemberInfoDescription(taskDescription);
				if(startKey)
				{
					startSetPublicMemberInfo();
				}
			}
			break;
			case GET_PUBLIC_MEMBER_INFO:
			{
				getPublicMemberInfoDescription(taskDescription);
				if(startKey)
				{
					startGetPublicMemberInfo();
				}
			}
			break;
			case SET_PRIVATE_MEMBER_INFO:
			{
				setPrivateMemberInfoDescription(taskDescription);
				if(startKey)
				{
					startSetPrivateMemberInfo();
				}
			}
			break;
			case GET_PRIVATE_MEMBER_INFO:
			{
				getPrivateMemberInfoDescription(taskDescription);
				if(startKey)
				{
					startGetPrivateMemberInfo();
				}
			}
			break;
			case SEND_MEMBER_MESSAGE:
			{
				sendMemberMessageDescription(taskDescription);
				if(startKey)
				{
					startSendMemberMessage();
				}
			}
			break;
			case SEND_ADMIN_MESSAGE:
			{
				sendAdminMessageDescription(taskDescription);
				if(startKey)
				{
					startSendAdminMessage();
				}
			}
			break;
			case LOBBY_DISCONNECT:
			{
				lobbyServiceDisconnectDescription(taskDescription);
				if(startKey)
				{
					startLobbyServiceDisconnect();
				}
			}
			break;
			case STOP_NETWORK:
			{
				stopNetworkDescription(taskDescription);
				if(startKey)
				{
					stopNetwork();
				}
			}
			break;
		}
		
		if(m_changedScreen)
		{
			m_screenText += taskDescription;
			m_screenText += "\n" START_TEXT;
			m_screenText += "\n" SKIP_TEXT;

			if(m_lastTaskDescription.getLength())
			{
				m_screenText += "\n\n";
				m_screenText += m_lastTaskDescription;				
			}
		}
	}
}

void Simulation::pumpTask()
{
	bdString taskDescription("Unknown task");

	switch(m_task)
	{
		case START_NETWORK:
		{
			startNetworkDescription(taskDescription);
			pumpStartNetwork();
		}
		break;
		case CHECK_DNS:
		{
			checkDNSDescription(taskDescription);
			pumpCheckDNS();
		}
		break;
		case CHOOSE_USER_ACCOUNT_1:
		{
			chooseUserAccount1Description(taskDescription);
			pumpChooseUserAccount1();
		}
		break;
		case CHOOSE_USER_ACCOUNT_2:
		{
			chooseUserAccount2Description(taskDescription);
			pumpChooseUserAccount2();
		}
		break;
		case CREATE_ACCOUNT:
		{
			createAccountDescription(taskDescription);
			pumpCreateAccount();
		}
		break;
		case AUTHENTICATE_ACCOUNT:
		{
			authenticateAccountDescription(taskDescription);
			pumpAuthenticateAccount();
		}
		break;
		case LOBBY_CONNECT:
		{
			lobbyServiceConnectDescription(taskDescription);
			pumpLobbyServiceConnect();
		}
		break;
		case CREATE_PROFILE:
		{
			createProfileDescription(taskDescription);
			pumpCreateProfile();
		}
		break;
		case GET_MESSAGES:
		{
			getMessagesDescription(taskDescription);
			pumpGetMessages();
		}
		break;
		case ACCEPT_MEMBERSHIP:
		{
			acceptMembershipDescription(taskDescription);
			pumpAcceptMembership();
		}
		break;
		case REJECT_MEMBERSHIP:
		{
			rejectMembershipDescription(taskDescription);
			pumpRejectMembership();
		}
		break;
		case ACCEPT_INVITATION:
		{
			acceptInvitationDescription(taskDescription);
			pumpAcceptInvitation();
		}
		break;
		case REJECT_INVITATION:
		{
			rejectInvitationDescription(taskDescription);
			pumpRejectInvitation();
		}
		break;
		case CHECK_MEMBERSHIPS:
		{
			checkMembershipsDescription(taskDescription);
			pumpCheckMemberships();
		}
		break;
		case CREATE_TEAM:
		{
			createTeamDescription(taskDescription);
			pumpCreateTeam();
		}
		break;
		case UPDATE_TEAM:
		{
			updateTeamDescription(taskDescription);
			pumpUpdateTeam();
		}
		break;
		case GET_MEMBERS:
		{
			getMembersDescription(taskDescription);
			pumpGetMembers();
		}
		break;
		case PROPOSE_MEMBERSHIP:
		{
			proposeMembershipDescription(taskDescription);
			pumpProposeMembership();
		}
		break;
		case GET_PROPOSALS:
		{
			getProposalsDescription(taskDescription);
			pumpGetProposals();
		}
		break;
		case WITHDRAW_PROPOSAL:
		{
			withdrawProposalDescription(taskDescription);
			pumpWithdrawProposal();
		}
		break;
		case INVITE_TO_SESSION:
		{
			inviteToSessionDescription(taskDescription);
			pumpInviteToSession();
		}
		break;
		case PROMOTE_MEMBER:
		{
			promoteMemberDescription(taskDescription);
			pumpPromoteMember();
		}
		break;
		case DEMOTE_MEMBER:
		{
			demoteMemberDescription(taskDescription);
			pumpDemoteMember();
		}
		break;
		case KICK_MEMBER:
		{
			kickMemberDescription(taskDescription);
			pumpKickMember();
		}
		break;
		case SET_PUBLIC_TEAM_INFO:
		{
			setPublicTeamInfoDescription(taskDescription);
			pumpSetPublicTeamInfo();
		}
		break;
		case GET_PUBLIC_TEAM_INFO:
		{
			getPublicTeamInfoDescription(taskDescription);
			pumpGetPublicTeamInfo();
		}
		break;
		case SET_PRIVATE_TEAM_INFO:
		{
			setPrivateTeamInfoDescription(taskDescription);
			pumpSetPrivateTeamInfo();
		}
		break;
		case GET_PRIVATE_TEAM_INFO:
		{
			getPrivateTeamInfoDescription(taskDescription);
			pumpGetPrivateTeamInfo();
		}
		break;
		case SET_PUBLIC_MEMBER_INFO:
		{
			setPublicMemberInfoDescription(taskDescription);
			pumpSetPublicMemberInfo();
		}
		break;
		case GET_PUBLIC_MEMBER_INFO:
		{
			getPublicMemberInfoDescription(taskDescription);
			pumpGetPublicMemberInfo();
		}
		break;
		case SET_PRIVATE_MEMBER_INFO:
		{
			setPrivateMemberInfoDescription(taskDescription);
			pumpSetPrivateMemberInfo();
		}
		break;
		case GET_PRIVATE_MEMBER_INFO:
		{
			getPrivateMemberInfoDescription(taskDescription);
			pumpGetPrivateMemberInfo();
		}
		break;
		case SEND_MEMBER_MESSAGE:
		{
			sendMemberMessageDescription(taskDescription);
			pumpSendMemberMessage();
		}
		break;
		case SEND_ADMIN_MESSAGE:
		{
			sendAdminMessageDescription(taskDescription);
			pumpSendAdminMessage();
		}
		break;
		case LOBBY_DISCONNECT:
		{
			lobbyServiceDisconnectDescription(taskDescription);
			pumpLobbyServiceDisconnect();
		}
		break;
		case STOP_NETWORK:
		{
			// nothing to to here
		}
		break;
	}

	if(m_changedScreen)
	{
		m_screenText += taskDescription;
	}
}

void Simulation::displayTaskResult()
{
	bdString taskDescription("Unknown task result");

	Task nextTaskIfDone = m_task;
	Task nextTaskIfFailed = m_task;
	Task nextTaskIfSkipped = m_task;

	bdBool displayLobbyError = true;

	switch(m_task)
	{
		case START_NETWORK:
		{
			startNetworkDescription(m_lastTaskDescription);
			nextTaskIfDone = CHECK_DNS;
			nextTaskIfFailed = START_NETWORK;
			nextTaskIfSkipped = START_NETWORK;
			displayLobbyError = false;
		}
		break;
		case CHECK_DNS:
		{
			checkDNSDescription(m_lastTaskDescription);
			nextTaskIfDone = CHOOSE_USER_ACCOUNT_1;
			nextTaskIfFailed = CHECK_DNS;
			nextTaskIfSkipped = CHOOSE_USER_ACCOUNT_1;
			displayLobbyError = false;
		}
		break;
		case CHOOSE_USER_ACCOUNT_1:
		{
			chooseUserAccount1Description(m_lastTaskDescription);
			nextTaskIfDone = CREATE_ACCOUNT;
			nextTaskIfFailed = CHOOSE_USER_ACCOUNT_1;
			nextTaskIfSkipped = CHOOSE_USER_ACCOUNT_2;
			displayLobbyError = false;
		}
		break;
		case CHOOSE_USER_ACCOUNT_2:
		{
			chooseUserAccount2Description(m_lastTaskDescription);
			nextTaskIfDone = CREATE_ACCOUNT;
			nextTaskIfFailed = CHOOSE_USER_ACCOUNT_2;
			nextTaskIfSkipped = CHOOSE_USER_ACCOUNT_1;
			displayLobbyError = false;
		}
		break;
		case CREATE_ACCOUNT:
		{
			createAccountDescription(m_lastTaskDescription);
			checkAuthServiceError();
			nextTaskIfDone = AUTHENTICATE_ACCOUNT;
			nextTaskIfFailed = CREATE_ACCOUNT;
			nextTaskIfSkipped = AUTHENTICATE_ACCOUNT;			
		}
		break;
		case AUTHENTICATE_ACCOUNT:
		{
			authenticateAccountDescription(m_lastTaskDescription);
			checkAuthServiceError();
			nextTaskIfDone = LOBBY_CONNECT;
			nextTaskIfFailed = AUTHENTICATE_ACCOUNT;
			nextTaskIfSkipped = LOBBY_CONNECT;			
		}
		break;
		case LOBBY_CONNECT:
		{
			lobbyServiceConnectDescription(m_lastTaskDescription);
			nextTaskIfDone = CREATE_PROFILE;
			nextTaskIfFailed = LOBBY_DISCONNECT;
			nextTaskIfSkipped = STOP_NETWORK;
			displayLobbyError = false;
		}
		break;
		case CREATE_PROFILE:
		{
			createProfileDescription(m_lastTaskDescription);
			nextTaskIfDone = GET_MESSAGES;
			nextTaskIfFailed = GET_MESSAGES;
			nextTaskIfSkipped = GET_MESSAGES;
		}
		break;
		case GET_MESSAGES:
		{
			getMessagesDescription(m_lastTaskDescription);
			nextTaskIfDone = determineNextTask(m_task);
			nextTaskIfFailed = GET_MESSAGES;
			nextTaskIfSkipped = CHECK_MEMBERSHIPS;
		}
		break;
		case ACCEPT_MEMBERSHIP:
		{
			acceptMembershipDescription(m_lastTaskDescription);
			nextTaskIfDone = determineNextTask(m_task);
			nextTaskIfFailed = ACCEPT_MEMBERSHIP;
			nextTaskIfSkipped = REJECT_MEMBERSHIP;
		}
		break;
		case REJECT_MEMBERSHIP:
		{
			rejectMembershipDescription(m_lastTaskDescription);
			nextTaskIfDone = determineNextTask(m_task);
			nextTaskIfFailed = REJECT_MEMBERSHIP;
			nextTaskIfSkipped = determineNextTask(m_task);
		}
		break;
		case ACCEPT_INVITATION:
		{
			acceptInvitationDescription(m_lastTaskDescription);
			nextTaskIfDone = determineNextTask(m_task);
			nextTaskIfFailed = ACCEPT_INVITATION;
			nextTaskIfSkipped = REJECT_INVITATION;
		}
		break;
		case REJECT_INVITATION:
		{
			rejectInvitationDescription(m_lastTaskDescription);
			nextTaskIfDone = determineNextTask(m_task);
			nextTaskIfFailed = REJECT_INVITATION;
			nextTaskIfSkipped = determineNextTask(m_task);
		}
		break;
		case CHECK_MEMBERSHIPS:
		{
			checkMembershipsDescription(m_lastTaskDescription);
			nextTaskIfDone = CREATE_TEAM;
			nextTaskIfFailed = CHECK_MEMBERSHIPS;
			nextTaskIfSkipped = CREATE_TEAM;
		}
		break;
		case CREATE_TEAM:
		{
			createTeamDescription(m_lastTaskDescription);
			nextTaskIfDone = UPDATE_TEAM;
			nextTaskIfFailed = CREATE_TEAM;
			nextTaskIfSkipped = UPDATE_TEAM;
		}
		break;
		case UPDATE_TEAM:
		{
			updateTeamDescription(m_lastTaskDescription);
			nextTaskIfDone = GET_MEMBERS;
			nextTaskIfFailed = UPDATE_TEAM;
			nextTaskIfSkipped = GET_MEMBERS;
		}
		break;
		case GET_MEMBERS:
		{
			getMembersDescription(m_lastTaskDescription);
			if(m_myTeam.m_teamID != BD_NULL)
			{
				nextTaskIfDone = PROPOSE_MEMBERSHIP;
				nextTaskIfFailed = GET_MEMBERS;
				nextTaskIfSkipped = PROPOSE_MEMBERSHIP;
			}
			else
			{
				nextTaskIfDone = GET_PUBLIC_TEAM_INFO;
				nextTaskIfFailed = GET_MEMBERS;
				nextTaskIfSkipped = GET_PUBLIC_TEAM_INFO;
			}
		}
		break;
		case PROPOSE_MEMBERSHIP:
		{
			proposeMembershipDescription(m_lastTaskDescription);
			nextTaskIfDone = GET_PROPOSALS;
			nextTaskIfFailed = PROPOSE_MEMBERSHIP;
			nextTaskIfSkipped = GET_PROPOSALS;
		}
		break;
		case GET_PROPOSALS:
		{
			getProposalsDescription(m_lastTaskDescription);
			if(m_proposals.getNumResults() > 0)
			{
				nextTaskIfDone = WITHDRAW_PROPOSAL;
				nextTaskIfFailed = GET_PROPOSALS;
				nextTaskIfSkipped = WITHDRAW_PROPOSAL;
			}
			else
			{
				nextTaskIfDone = INVITE_TO_SESSION;
				nextTaskIfFailed = GET_PROPOSALS;
				nextTaskIfSkipped = INVITE_TO_SESSION;
			}
		}
		break;
		case WITHDRAW_PROPOSAL:
		{
			withdrawProposalDescription(m_lastTaskDescription);
			nextTaskIfDone = INVITE_TO_SESSION;
			nextTaskIfFailed = INVITE_TO_SESSION;
			nextTaskIfSkipped = INVITE_TO_SESSION;
		}
		break;
		case INVITE_TO_SESSION:
		{
			inviteToSessionDescription(m_lastTaskDescription);
			if(m_myTeam.m_memberStatus == bdCheckTeamMembershipResult::BD_OWNER)
			{
				nextTaskIfDone = PROMOTE_MEMBER;
				nextTaskIfFailed = PROMOTE_MEMBER;
				nextTaskIfSkipped = PROMOTE_MEMBER;
			}
			else
			{
				nextTaskIfDone = GET_PUBLIC_TEAM_INFO;
				nextTaskIfFailed = GET_PUBLIC_TEAM_INFO;
				nextTaskIfSkipped = GET_PUBLIC_TEAM_INFO;
			}
		}
		break;
		case PROMOTE_MEMBER:
		{
			promoteMemberDescription(m_lastTaskDescription);
			nextTaskIfDone = DEMOTE_MEMBER;
			nextTaskIfFailed = DEMOTE_MEMBER;
			nextTaskIfSkipped = DEMOTE_MEMBER;
		}
		break;
		case DEMOTE_MEMBER:
		{
			demoteMemberDescription(m_lastTaskDescription);
			nextTaskIfDone = KICK_MEMBER;
			nextTaskIfFailed = KICK_MEMBER;
			nextTaskIfSkipped = KICK_MEMBER;
		}
		break;
		case KICK_MEMBER:
		{
			kickMemberDescription(m_lastTaskDescription);
			nextTaskIfDone = SET_PUBLIC_TEAM_INFO;
			nextTaskIfFailed = SET_PUBLIC_TEAM_INFO;
			nextTaskIfSkipped = SET_PUBLIC_TEAM_INFO;
		}
		break;
		case SET_PUBLIC_TEAM_INFO:
		{
			setPublicTeamInfoDescription(m_lastTaskDescription);
			nextTaskIfDone = GET_PUBLIC_TEAM_INFO;
			nextTaskIfFailed = GET_PUBLIC_TEAM_INFO;
			nextTaskIfSkipped = GET_PUBLIC_TEAM_INFO;
		}
		break;
		case GET_PUBLIC_TEAM_INFO:
		{
			getPublicTeamInfoDescription(m_lastTaskDescription);
			nextTaskIfDone = SET_PRIVATE_TEAM_INFO;
			nextTaskIfFailed = SET_PRIVATE_TEAM_INFO;
			nextTaskIfSkipped = SET_PRIVATE_TEAM_INFO;
		}
		break;
		case SET_PRIVATE_TEAM_INFO:
		{
			setPrivateTeamInfoDescription(m_lastTaskDescription);
			nextTaskIfDone = GET_PRIVATE_TEAM_INFO;
			nextTaskIfFailed = GET_PRIVATE_TEAM_INFO;
			nextTaskIfSkipped = GET_PRIVATE_TEAM_INFO;
		}
		break;
		case GET_PRIVATE_TEAM_INFO:
		{
			getPrivateTeamInfoDescription(m_lastTaskDescription);
			nextTaskIfDone = SET_PUBLIC_MEMBER_INFO;
			nextTaskIfFailed = SET_PUBLIC_MEMBER_INFO;
			nextTaskIfSkipped = SET_PUBLIC_MEMBER_INFO;
		}
		break;
		case SET_PUBLIC_MEMBER_INFO:
		{
			setPublicMemberInfoDescription(m_lastTaskDescription);
			nextTaskIfDone = GET_PUBLIC_MEMBER_INFO;
			nextTaskIfFailed = GET_PUBLIC_MEMBER_INFO;
			nextTaskIfSkipped = GET_PUBLIC_MEMBER_INFO;
		}
		break;
		case GET_PUBLIC_MEMBER_INFO:
		{
			getPublicMemberInfoDescription(m_lastTaskDescription);
			nextTaskIfDone = SET_PRIVATE_MEMBER_INFO;
			nextTaskIfFailed = SET_PRIVATE_MEMBER_INFO;
			nextTaskIfSkipped = SET_PRIVATE_MEMBER_INFO;
		}
		break;
		case SET_PRIVATE_MEMBER_INFO:
		{
			setPrivateMemberInfoDescription(m_lastTaskDescription);
			nextTaskIfDone = GET_PRIVATE_MEMBER_INFO;
			nextTaskIfFailed = GET_PRIVATE_MEMBER_INFO;
			nextTaskIfSkipped = GET_PRIVATE_MEMBER_INFO;
		}
		break;
		case GET_PRIVATE_MEMBER_INFO:
		{
			getPrivateMemberInfoDescription(m_lastTaskDescription);
			nextTaskIfDone = SEND_MEMBER_MESSAGE;
			nextTaskIfFailed = SEND_MEMBER_MESSAGE;
			nextTaskIfSkipped = SEND_MEMBER_MESSAGE;
		}
		break;
		case SEND_MEMBER_MESSAGE:
		{
			sendMemberMessageDescription(m_lastTaskDescription);
			if(m_myTeam.m_memberStatus == bdCheckTeamMembershipResult::BD_OWNER)
			{
				nextTaskIfDone = SEND_ADMIN_MESSAGE;
				nextTaskIfFailed = SEND_ADMIN_MESSAGE;
				nextTaskIfSkipped = SEND_ADMIN_MESSAGE;
			}
			else
			{
				nextTaskIfDone = LOBBY_DISCONNECT;
				nextTaskIfFailed = LOBBY_DISCONNECT;
				nextTaskIfSkipped = LOBBY_DISCONNECT;
			}
		}
		break;
		case SEND_ADMIN_MESSAGE:
		{
			sendAdminMessageDescription(m_lastTaskDescription);
			nextTaskIfDone = LOBBY_DISCONNECT;
			nextTaskIfFailed = LOBBY_DISCONNECT;
			nextTaskIfSkipped = LOBBY_DISCONNECT;
		}
		break;
		case LOBBY_DISCONNECT:
		{
			lobbyServiceDisconnectDescription(m_lastTaskDescription);			
			nextTaskIfDone = STOP_NETWORK;
			nextTaskIfFailed = LOBBY_DISCONNECT;
			nextTaskIfSkipped = STOP_NETWORK;
		}
		break;
		case STOP_NETWORK:
		{
			stopNetworkDescription(m_lastTaskDescription);
			nextTaskIfDone = START_NETWORK;
			nextTaskIfFailed = STOP_NETWORK;
			nextTaskIfSkipped = CREATE_ACCOUNT;
		}
		break;
	}

	// if task uses sets a lobby error code and has failed
	// display the error description
	if(displayLobbyError && (m_taskStatus == FAILED))
	{
		if(m_task == CREATE_PROFILE)
		{
			checkProfilesError();
		}
		else
		{
			checkTeamsError();
		}
		bdNChar8 buf[32];
		LobbyErrorCodeToString(m_lobbyErrorCode, buf, sizeof(buf));
		m_lastTaskDescription += "\nError: ";
		m_lastTaskDescription += buf;
		m_lobbyErrorCode = BD_NO_ERROR;
	}

	switch(m_taskStatus)
	{
		case READY:
		case PENDING:
		{
			BD_WARN(BD_LOG_LEVEL, "Unexpected task status.");
		}
		break;
		case DONE:
		{
			m_task = nextTaskIfDone;
		}
		break;
		case FAILED:
		{
			m_task = nextTaskIfFailed;
		}
		break;
		case SKIPPED:
		{
			m_task = nextTaskIfSkipped;
		}
		break;
	}



	m_taskStatus = READY;
}

void Simulation::startNetworkDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Start Network",				// READY
											"Starting Network",				// PENDING
											"Started Network",				// DONE
											"Starting Network Failed",		// FAILED
											"Starting Network Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::startNetwork()
{
	bdNetImpl *const net = bdNet::getInstance();
	bdNetStartParams params;
	params.m_onlineGame = true;

	// platform specific startup parameters
	bdPlatformParams platformParams;
	//TODO: check the return value here
	bdExamplePlatformInit::init(params, &platformParams);

	if(net->start(params))
	{
		m_taskStatus = PENDING;
	}
	else
	{
		m_taskStatus = FAILED;
	}
}

void Simulation::pumpStartNetwork()
{
	bdNetImpl *const net = bdNet::getInstance();
	net->pump();

	const bdNetImpl::bdNetStatus networkStatus = net->getStatus();
	switch(networkStatus)
	{
		case bdNetImpl::BD_NET_BIND_FAILED:
		case bdNetImpl::BD_NET_ONLINE_FAILED:
		case bdNetImpl::BD_NET_INIT_FAILED:
		case bdNetImpl::BD_NET_STOPPED:
		{
			// error conditions
			m_taskStatus = FAILED;
		}
		break;
		case bdNetImpl::BD_NET_PENDING:
		{
			// wait
			m_taskStatus = PENDING;
		}
		break;
		case bdNetImpl::BD_NET_DONE:
		{
			// complete
			m_taskStatus = DONE;
		}
	}
}

void Simulation::checkDNSDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Start DNS Lookup",			// READY
											"Performing DNS Lookup",	// PENDING
											"DNS Lookup Succeeded",		// DONE
											"DNS Lookup Failed",		// FAILED
											"DNS Lookup Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);

	if(m_taskStatus == DONE)
	{
		bdNChar8 addrString[BD_INET_ADDR_STRING_SIZE];
		m_authAddr.toString(addrString, sizeof(addrString));
		description +=  "\n " AUTH_ADDRESS ":";
		description += addrString;
		description +=  "\n";

		m_lsgAddr.toString(addrString, sizeof(addrString));
		description +=  " " LSG_ADDRESS ":";
		description += addrString;
	}

}		

void Simulation::startCheckDNS()
{
	const TaskStatus authDNSStatus = StartGetHostByName(AUTH_ADDRESS, &m_authGetHostByName, m_authAddr);
	const TaskStatus lsgDNSStatus = StartGetHostByName(LSG_ADDRESS, &m_lsgGetHostByName, m_lsgAddr);
	if((authDNSStatus == FAILED) || (lsgDNSStatus == FAILED))
	{
		m_taskStatus = FAILED;
	}

	if((authDNSStatus == PENDING) || (lsgDNSStatus == PENDING))
	{
		m_taskStatus = PENDING;
	}

	if((authDNSStatus == DONE) && (lsgDNSStatus == DONE))
	{
		m_taskStatus = DONE;
	}
}

void Simulation::pumpCheckDNS()
{
	TaskStatus authDNSStatus = DONE;
	TaskStatus lsgDNSStatus = DONE;

	if(m_authGetHostByName)
	{
		authDNSStatus = PumpGetHostByName(&m_authGetHostByName, m_authAddr);
	}

	if(lsgDNSStatus)
	{
		lsgDNSStatus = PumpGetHostByName(&m_lsgGetHostByName, m_lsgAddr);
	}

	if((authDNSStatus == FAILED) || (lsgDNSStatus == FAILED))
	{
		m_taskStatus = FAILED;
	}

	if((authDNSStatus == PENDING) || (lsgDNSStatus == PENDING))
	{
		m_taskStatus = PENDING;
	}

	if((authDNSStatus == DONE) && (lsgDNSStatus == DONE))
	{
		m_taskStatus = DONE;
	}
}

bdAuthService* Simulation::getAuthService()
{
	if(m_authService == BD_NULL)
	{
		const bdAddr authAddr(m_authAddr, AUTH_PORT);
		m_authService = new bdAuthService(TITLE_ID, authAddr);
	}

	return m_authService;
}


const bdAuthInfo *Simulation::getAuthInfo()
{
	if(m_authService != BD_NULL)
	{
		return m_authService->getAuthInfo();
	}

	return BD_NULL;
}


void Simulation::checkAuthServiceError()
{
	bdAuthService *const authService = getAuthService();
	if(authService)
	{
		m_lobbyErrorCode = authService->getErrorCode();
	}
}

void Simulation::pumpAuthServiceTask()
{
	// fail safe
	m_taskStatus = FAILED;

	bdAuthService *const authService = getAuthService();
	if(authService)
	{
		m_taskStatus = PENDING;
		const bdAuthService::bdStatus status = authService->getStatus();
		if(status == bdAuthService::BD_READY)
		{			
			const bdLobbyErrorCode lobbyErrorCode = authService->getErrorCode();
			if(lobbyErrorCode == BD_AUTH_NO_ERROR)
			{
				m_taskStatus = DONE;
			}
			else
			{
				m_taskStatus = FAILED;
			}
		}
	}
}


void Simulation::startChooseUserAccount1()
{
	// fail safe
	m_taskStatus = DONE;
	m_userName = USERNAME1;
}

void Simulation::pumpChooseUserAccount1()
{
}

void Simulation::chooseUserAccount1Description(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Choose User Account 1",			// READY
											"Choosing User Account 1",			// PENDING
											"Chose User Account 1",				// DONE
											"Choose User Account 1 Failed",		// FAILED
											"Choose User Account 1 Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::startChooseUserAccount2()
{
	// fail safe
	m_taskStatus = DONE;
	m_userName = USERNAME2;
}

void Simulation::pumpChooseUserAccount2()
{
}

void Simulation::chooseUserAccount2Description(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Choose User Account 2",			// READY
											"Choosing User Account 2",			// PENDING
											"Chose User Account 2",			// DONE
											"Choose User Account 2 Failed",		// FAILED
											"Choose User Account 2 Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::createAccountDescription(bdString& description)
{
	bdString createAccountStr = "Create Account (";
	createAccountStr += m_userName;
	createAccountStr += "/" PASSWORD ")";
	const bdNChar8 *const descriptions[] = {createAccountStr.getBuffer(),	// READY
											"Creating Account",								// PENDING
											"Created Account",								// DONE
											"Create Account Failed",						// FAILED
											"Create Account Skipped"};						// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::startCreateAccount()
{
	// fail safe
	m_taskStatus = FAILED;

	bdAuthService *const authService = getAuthService();
	if(authService)
	{
		if(authService->createAccount(m_userName.getBuffer(), PASSWORD))
		{
			m_taskStatus = PENDING;
		}
	}
}

void Simulation::pumpCreateAccount()
{
	pumpAuthServiceTask();
}

void Simulation::authenticateAccountDescription(bdString& description)
{
	bdString authenticateAccountStr = "Authenticate Account (";
	authenticateAccountStr  += m_userName;
	authenticateAccountStr += "/" PASSWORD ")";
	const bdNChar8 *const descriptions[] = {authenticateAccountStr.getBuffer(),	// READY
											"Authenticating Account",									// PENDING
											"Authenticated Account",									// DONE
											"Authenticate Account Failed",								// FAILED
											"Authenticate Account Skipped"};							// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::startAuthenticateAccount()
{
	// fail safe
	m_taskStatus = FAILED;

	bdAuthService *const authService = getAuthService();

	if(authService )
	{
		if(authService->authorizeAccount(m_userName.getBuffer(), PASSWORD))
		{
			m_taskStatus = PENDING;
		}
	}
}

void Simulation::pumpAuthenticateAccount()
{
	pumpAuthServiceTask();
}

void Simulation::lobbyServiceConnectDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Connect to Lobby Service",				// READY
											"Connecting to Lobby Service",			// PENDING
											"Connected to Lobby Service",			// DONE
											"Connect to Lobby Service Failed",		// FAILED
											"Connect to Lobby Service Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::startLobbyServiceConnect()
{
	// fail safe
	m_taskStatus = FAILED;

	bdLobbyServiceImpl *const lobbyService = bdLobbyService::getInstance();
	if(lobbyService)
	{
		const bdAddr lsgAddr(m_lsgAddr, LSG_PORT);
		const bdBool connecting = lobbyService->connect(lsgAddr, getAuthInfo());
		if(connecting)
		{
			m_taskStatus = PENDING;
		}
		// no need to keep the bdAuthService instance after we are connected to the lobby
		delete m_authService;
		m_authService = BD_NULL;
	}
}

void Simulation::pumpLobbyServiceConnect()
{
	// fail safe
	m_taskStatus = FAILED;

	m_pumpLobbyConnection = false;

	bdLobbyServiceImpl *const lobbyService = bdLobbyService::getInstance();
	if(lobbyService)
	{
		const bdLobbyConnection::Status connectionStatus = lobbyService->getStatus();
		switch(connectionStatus)
		{			
			case bdConnection::BD_NOT_CONNECTED:
			case bdConnection::BD_DISCONNECTING:
			case bdConnection::BD_DISCONNECTED:
			{
				m_taskStatus = FAILED;
			}
			break;
			case bdConnection::BD_CONNECTING:
			{
				m_taskStatus = PENDING;
			}
			break;
			case bdConnection::BD_CONNECTED:
			{
				m_taskStatus = DONE;
				m_pumpLobbyConnection = true;
			}
			break;			
		}
	}
}

void Simulation::createProfileDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Create Profile",			// READY
											"Creating Profile",			// PENDING
											"Created Profile",			// DONE
											"Create Profile Failed",	// FAILED
											"Create Profile Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::startCreateProfile()
{
	// fail safe
	m_taskStatus = FAILED;

	bdProfiles *const profiles = GetProfiles();

	if(profiles)
	{
		PublicProfileInfo profileInfo;
		profileInfo.m_experiencePoints = 555;
		m_remoteTask = profiles->createProfile(0,&profileInfo);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

void Simulation::pumpCreateProfile()
{
	m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);

	if((m_taskStatus == DONE) || (m_taskStatus == FAILED))
	{
		// fail safe
		m_taskStatus = FAILED;

		bdProfiles *const profiles = GetProfiles();
		if(profiles)
		{
			const bdBool taskHandled = profiles->handleTask(m_remoteTask, BD_NULL);
			if(taskHandled)
			{
				m_taskStatus = DONE;
			}
		}
		CloseRemoteTask(&m_remoteTask);
	}
}

void Simulation::getMessagesDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Get Messages (proposals and invites)",				// READY
											"Getting Messages",		// PENDING
											"Got Messages",			// DONE
											"Get Messages Failed",		// FAILED
											"Get Messages Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::startGetMessages()
{
	// fail safe
	m_taskStatus = FAILED;

	bdMessageStore *const messageStore = GetMessageStore();
	if(messageStore)
	{
		m_remoteTask = messageStore->getMessages(0, 0, 20, false, true);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

void Simulation::pumpGetMessages()
{
	m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);

	if(m_taskStatus == DONE)
	{
		// fail safe
		m_taskStatus = FAILED;

		bdMessageStore *const messageStore = GetMessageStore();
		if(messageStore)
		{
			const bdBool taskHandled = messageStore->handleTask(m_remoteTask);
			if(taskHandled)
			{
				m_taskStatus = DONE;
			}
		}
	}

	if((m_taskStatus == DONE) || (m_taskStatus == FAILED))
	{
		CloseRemoteTask(&m_remoteTask);
	}
}

void Simulation::acceptMembershipDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Accept Membership (skip to goto reject)",				// READY
											"Accepting Membership",			// PENDING
											"Accepted Membership",			// DONE
											"Accept Membership Failed",		// FAILED
											"Accept Membership Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::startAcceptMembership()
{
	// fail safe
	m_taskStatus = FAILED;

	bdTeamInvitationMessageRef message; 
	{
		// find a membership proposal message
		bdMessageStore *const messageStore = GetMessageStore();
		bdUInt i;
		for(i = 0; i < messageStore->getNumMessages(); i++) 
		{
			if(messageStore->getAt(i)->m_msgType == BD_TEAM_INVITATION_MSG)
			{
				message = reference_cast<bdTeamInvitationMessage>(messageStore->getAt(i));
				break;
			}
		}
		messageStore->removeAt(i);
	}
	bdTeams *const teams = GetTeams();
	if(teams && message.notNull())
	{
		m_remoteTask = teams->acceptMembership(0, message->m_teamID, message->m_originatorID);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

void Simulation::pumpAcceptMembership()
{
	pumpGenericTeamsTask();
}

void Simulation::rejectMembershipDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Reject Membership",				// READY
											"Rejecting Membership",			// PENDING
											"Rejected Membership",			// DONE
											"Reject Membership Failed",		// FAILED
											"Reject Membership Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::startRejectMembership()
{
	// fail safe
	m_taskStatus = FAILED;

	bdTeamInvitationMessageRef message; 
	{
		// find a membership proposal message
		bdMessageStore *const messageStore = GetMessageStore();
		bdUInt i;
		for(i = 0; i < messageStore->getNumMessages(); i++) 
		{
			if(messageStore->getAt(i)->m_msgType == BD_TEAM_INVITATION_MSG)
			{
				message = reference_cast<bdTeamInvitationMessage>(messageStore->getAt(i));
				break;
			}
		}
		messageStore->removeAt(i);
	}
	bdTeams *const teams = GetTeams();
	if(teams && message.notNull())
	{
		m_remoteTask = teams->rejectMembership(0, message->m_teamID, message->m_originatorID);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

void Simulation::pumpRejectMembership()
{
	pumpGenericTeamsTask();
}

void Simulation::acceptInvitationDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Accept Invitation (skip to goto reject)",				// READY
											"Accepting Invitation",			// PENDING
											"Accepted Invitation",			// DONE
											"Accept Invitation Failed",		// FAILED
											"Accept Invitation Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::startAcceptInvitation()
{
	// fail safe
	m_taskStatus = FAILED;

	bdTeamSessionInvitationMessageRef message; 
	{
		// find a membership proposal message
		bdMessageStore *const messageStore = GetMessageStore();
		bdUInt i;
		for(i = 0; i < messageStore->getNumMessages(); i++) 
		{
			if(messageStore->getAt(i)->m_msgType == BD_TEAM_SESSION_INVITATION_MSG)
			{
				message = reference_cast<bdTeamSessionInvitationMessage>(messageStore->getAt(i));
				break;
			}
		}
		messageStore->removeAt(i);
	}
	bdTeams *const teams = GetTeams();
	if(teams && message.notNull())
	{
		m_remoteTask = teams->acceptInvitation(0, message->m_originatorID);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

void Simulation::pumpAcceptInvitation()
{
	pumpGenericTeamsTask();
}

void Simulation::rejectInvitationDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Reject Invitation (skip to goto reject)",				// READY
											"Rejecting Invitation",			// PENDING
											"Rejected Invitation",			// DONE
											"Reject Invitation Failed",		// FAILED
											"Reject Invitation Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::startRejectInvitation()
{
	// fail safe
	m_taskStatus = FAILED;

	bdTeamSessionInvitationMessageRef message; 
	{
		// find a membership proposal message
		bdMessageStore *const messageStore = GetMessageStore();
		bdUInt i;
		for(i = 0; i < messageStore->getNumMessages(); i++) 
		{
			if(messageStore->getAt(i)->m_msgType == BD_TEAM_INVITE_TO_SESSION)
			{
				message = reference_cast<bdTeamSessionInvitationMessage>(messageStore->getAt(i));
				break;
			}
		}
		messageStore->removeAt(i);
	}
	bdTeams *const teams = GetTeams();
	if(teams && message.notNull())
	{
		m_remoteTask = teams->rejectInvitation(0, message->m_originatorID);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

void Simulation::pumpRejectInvitation()
{
	pumpGenericTeamsTask();
}

void Simulation::checkMembershipsDescription(bdString& description)
{
	bdString membershipsStr = "Got Memberships:\n";
	bdUInt i;
	for(i = 0; i < m_memberships.m_teams.getSize(); i++)
	{
		membershipsStr += m_memberships.m_teams[i].m_teamName;
		if(m_memberships.m_teams[i].m_memberStatus == bdCheckTeamMembershipResult::BD_ADMIN)
		{
			membershipsStr += "[ADMIN]\n";
		}
		else if(m_memberships.m_teams[i].m_memberStatus == bdCheckTeamMembershipResult::BD_OWNER)
		{
			membershipsStr += "[OWNER]\n";
		}
		else
		{
			membershipsStr += "\n";
		}
	}
	const bdNChar8 *const descriptions[] = {"Get Memberships",				// READY
											"Getting Memberships",			// PENDING
											membershipsStr.getBuffer(),		// DONE
											"Get Memberships Failed",		// FAILED
											"Get Memberships Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::startCheckMemberships()
{
	// fail safe
	m_taskStatus = FAILED;

	bdTeams *const teams = GetTeams();
	if(teams)
	{
		m_remoteTask = teams->checkMemberships(0);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

void Simulation::pumpCheckMemberships()
{
	m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);

	if(m_taskStatus == DONE)
	{
		// fail safe
		m_taskStatus = FAILED;

		bdTeams *const teams = GetTeams();
		if(teams)
		{
			m_memberships.reset();
			m_memberships.m_teams.clear();
			const bdBool taskHandled = teams->handleTask(m_remoteTask, &m_memberships);
			if(taskHandled)
			{
				m_taskStatus = DONE;
				// Set the m_myTeam member
				bdUInt i;
				for(i = 0; i < m_memberships.m_teams.getSize(); i++)
				{
					bdCheckTeamMembershipResult::bdTeam &team = m_memberships.m_teams[i];
					if(m_myTeam.m_teamID == BD_NULL || team.m_memberStatus > m_myTeam.m_memberStatus)
					{
						m_myTeam = team;
					}
				}
			}
		}
	}

	if((m_taskStatus == DONE) || (m_taskStatus == FAILED))
	{
		CloseRemoteTask(&m_remoteTask);
	}
}

void Simulation::startCreateTeam()
{
	// fail safe
	m_taskStatus = FAILED;

	bdTeams *const teams = GetTeams();
	if(teams)
	{
		bdString teamName = m_userName;
		teamName += "\'s Team";
		m_remoteTask = teams->createTeam(0, teamName.getBuffer());
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

void Simulation::pumpCreateTeam()
{
	m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);

	if(m_taskStatus == DONE)
	{
		// fail safe
		m_taskStatus = FAILED;

		bdTeams *const teams = GetTeams();
		if(teams)
		{
			const bdBool taskHandled = teams->handleTask(m_remoteTask, &m_createResult);
			if(taskHandled)
			{
				m_taskStatus = DONE;
				// Set the m_myTeam instance members to reflect the team just created.
				m_myTeam.m_teamID = m_createResult.m_teamID;
				m_myTeam.m_memberStatus = bdCheckTeamMembershipResult::BD_OWNER;
			}
		}
	}

	if((m_taskStatus == DONE) || (m_taskStatus == FAILED))
	{
		CloseRemoteTask(&m_remoteTask);
	}
}

void Simulation::createTeamDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Create Team",			// READY
											"Creating Team",		// PENDING
											"Created Team",			// DONE
											"Create Team Failed",	// FAILED
											"Create Team Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::startUpdateTeam()
{
	// fail safe
	m_taskStatus = FAILED;

	bdTeams *const teams = GetTeams();
	if(teams)
	{
		bdString teamName = m_userName;
		teamName += "\'s New Team";
		m_remoteTask = teams->updateTeam(0, m_myTeam.m_teamID, teamName);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

void Simulation::pumpUpdateTeam()
{
	m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);

	if(m_taskStatus == DONE)
	{
		// fail safe
		m_taskStatus = FAILED;

		bdTeams *const teams = GetTeams();
		if(teams)
		{
			const bdBool taskHandled = teams->handleTask(m_remoteTask, BD_NULL);
			if(taskHandled)
			{
				m_taskStatus = DONE;
			}
		}
	}

	if((m_taskStatus == DONE) || (m_taskStatus == FAILED))
	{
		CloseRemoteTask(&m_remoteTask);
	}
}

void Simulation::updateTeamDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Update Team",			// READY
											"Updating Team",		// PENDING
											"Updated Team",			// DONE
											"Update Team Failed",	// FAILED
											"Update Team Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::startGetMembers()
{
	// fail safe
	m_taskStatus = FAILED;

	bdTeams *const teams = GetTeams();
	if(teams && m_myTeam.m_teamID != BD_NULL)
	{
		m_remoteTask = teams->getMembers(0, m_myTeam.m_teamID);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

void Simulation::pumpGetMembers()
{
	m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);

	if(m_taskStatus == DONE)
	{
		// fail safe
		m_taskStatus = FAILED;

		bdTeams *const teams = GetTeams();
		if(teams)
		{
			m_teamMembers.reset();
			m_teamMembers.m_members.clear();
			const bdBool taskHandled = teams->handleTask(m_remoteTask, &m_teamMembers);
			if(taskHandled)
			{
				m_taskStatus = DONE;
			}
		}
	}

	if((m_taskStatus == DONE) || (m_taskStatus == FAILED))
	{
		CloseRemoteTask(&m_remoteTask);
	}
}

void Simulation::getMembersDescription(bdString& description)
{
	bdString resultStr = "Got Members:\n";
	bdUInt i;
	for(i = 0; i < m_teamMembers.m_members.getSize(); i++)
	{
		resultStr += m_teamMembers.m_members[i].m_userName;
		if(m_teamMembers.m_members[i].m_status == bdGetTeamMembersResult::BD_ORDINARY)
		{
			resultStr += "[ORDINARY MEMBER]";
		}
		else if(m_teamMembers.m_members[i].m_status == bdGetTeamMembersResult::BD_ADMIN)
		{
			resultStr += "[ADMIN]";
		}
		else if(m_teamMembers.m_members[i].m_status == bdGetTeamMembersResult::BD_OWNER)
		{
			resultStr += "[OWNER]";
		}
		if(m_teamMembers.m_members[i].m_isOnline)
		{
			resultStr += " - online\n";
		}
		else
		{
			resultStr += " - offline\n";
		}
	}

	const bdNChar8 *const descriptions[] = {"Get Members",			// READY
											"Getting Members",		// PENDING
											resultStr.getBuffer(),	// DONE
											"Get Members Failed",	// FAILED
											"Get Members Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::startProposeMembership()
{
	// fail safe
	m_taskStatus = FAILED;

	bdTeams *const teams = GetTeams();
	if(teams)
	{
		bdOnlineUserID newUserID;
		if(m_userName == USERNAME1)
		{
			newUserID = bdAuthUtility::getUserID(USERNAME2);
		}
		else
		{
			newUserID = bdAuthUtility::getUserID(USERNAME1);
		}
		bdByteBuffer attachment(128);
		const bdNChar8 *const invitationMessage = "Please join my team.";
		attachment.write(invitationMessage, bdStrnlen(invitationMessage, 128) + 1);
		m_remoteTask = teams->proposeMembership(0, m_myTeam.m_teamID, newUserID, &attachment);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

void Simulation::pumpProposeMembership()
{
	m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);

	if(m_taskStatus == DONE)
	{
		// fail safe
		m_taskStatus = FAILED;

		bdTeams *const teams = GetTeams();
		if(teams)
		{
			const bdBool taskHandled = teams->handleTask(m_remoteTask, BD_NULL);
			if(taskHandled)
			{
				m_taskStatus = DONE;
			}
		}
	}

	if((m_taskStatus == DONE) || (m_taskStatus == FAILED))
	{
		CloseRemoteTask(&m_remoteTask);
	}
}

void Simulation::proposeMembershipDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Propose Membership",			// READY
											"Proposing Membership",			// PENDING
											"Proposed Membership",			// DONE
											"Propose Membership Failed",		// FAILED
											"Propose Membership Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::startGetProposals()
{
	// fail safe
	m_taskStatus = FAILED;

	bdTeams *const teams = GetTeams();
	if(teams)
	{
		m_remoteTask = teams->getProposalList(0);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

void Simulation::pumpGetProposals()
{
	m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);

	if(m_taskStatus == DONE)
	{
		// fail safe
		m_taskStatus = FAILED;

		bdTeams *const teams = GetTeams();
		if(teams)
		{
			m_proposals.reset();
			m_proposals.m_proposalList.clear();
			const bdBool taskHandled = teams->handleTask(m_remoteTask, &m_proposals);
			if(taskHandled)
			{
				m_taskStatus = DONE;
			}
		}
	}

	if((m_taskStatus == DONE) || (m_taskStatus == FAILED))
	{
		CloseRemoteTask(&m_remoteTask);
	}
}

void Simulation::getProposalsDescription(bdString& description)
{
	bdString getProposalsStr = "Got outstanding proposals:\n";
	bdUInt i;
	for(i = 0; i < m_proposals.m_proposalList.getSize(); i++)
	{
		getProposalsStr += m_proposals.m_proposalList[i].m_userName;
		getProposalsStr += " to join ";
		getProposalsStr += m_proposals.m_proposalList[i].m_teamName;
		getProposalsStr += "\n";
	}
	const bdNChar8 *const descriptions[] = {"Get Proposals",			// READY
											"Getting Proposals",		// PENDING
											getProposalsStr.getBuffer(),// DONE
											"Get Proposals Failed",		// FAILED
											"Get Proposals Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::startWithdrawProposal()
{
	// fail safe
	m_taskStatus = FAILED;

	bdTeams *const teams = GetTeams();
	if(teams && m_proposals.m_proposalList.getSize() > 0)
	{
		bdOnlineUserID userID = m_proposals.m_proposalList[0].m_userID;
		bdTeamID teamID = m_proposals.m_proposalList[0].m_teamID;
		m_remoteTask = teams->withdrawProposal(0, userID, teamID);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

void Simulation::pumpWithdrawProposal()
{
	m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);

	if(m_taskStatus == DONE)
	{
		// fail safe
		m_taskStatus = FAILED;

		bdTeams *const teams = GetTeams();
		if(teams)
		{
			const bdBool taskHandled = teams->handleTask(m_remoteTask, BD_NULL);
			if(taskHandled)
			{
				m_taskStatus = DONE;
			}
		}
	}

	if((m_taskStatus == DONE) || (m_taskStatus == FAILED))
	{
		CloseRemoteTask(&m_remoteTask);
	}
}

void Simulation::withdrawProposalDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Withdraw Proposal",			// READY
											"Withdrawing Proposal",			// PENDING
											"Withdrew Proposal",			// DONE
											"Withdraw Proposal Failed",		// FAILED
											"Withdraw Proposal Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::startInviteToSession()
{
	// fail safe
	m_taskStatus = FAILED;

	// Find a userID that is not the local user to invite
	bdOnlineUserID userID = BD_NULL;
	bdUInt i;
	for(i = 0; i < m_teamMembers.m_members.getSize() && userID == BD_NULL; i++)
	{
		if(m_teamMembers.m_members[i].m_userID != bdAuthUtility::getUserID(m_userName))
		{
			userID = m_teamMembers.m_members[i].m_userID;
		}
	}

	bdTeams *const teams = GetTeams();
	if(teams && userID)
	{
		// We leave this uninitialized here. In a real implementation, this value
		// would be been retrieved from the bdMatchMaking API.
		bdSecurityID secID;
		
		bdByteBuffer attachment(128);
		const bdNChar8 *const invitationMessage = "Please join my team.";
		attachment.write(invitationMessage, bdStrnlen(invitationMessage, 128) + 1);

		m_remoteTask = teams->inviteMember(0, userID, secID, &attachment);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

void Simulation::pumpInviteToSession()
{
	m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);

	if(m_taskStatus == DONE)
	{
		// fail safe
		m_taskStatus = FAILED;

		bdTeams *const teams = GetTeams();
		if(teams)
		{
			const bdBool taskHandled = teams->handleTask(m_remoteTask, BD_NULL);
			if(taskHandled)
			{
				m_taskStatus = DONE;
			}
		}
	}

	if((m_taskStatus == DONE) || (m_taskStatus == FAILED))
	{
		CloseRemoteTask(&m_remoteTask);
	}
}

void Simulation::inviteToSessionDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Invite To Session",			// READY
											"Inviting To Session",			// PENDING
											"Invited To Session",			// DONE
											"Invite To Session Failed",		// FAILED
											"Invite To Session Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::startPromoteMember()
{
	// fail safe
	m_taskStatus = FAILED;

	bdTeams *const teams = GetTeams();

	// Check for team ownership, and that there is a member who can be promoted.
	bdBool amOwner = m_myTeam.m_memberStatus == bdCheckTeamMembershipResult::BD_OWNER;
	bdOnlineUserID userID = BD_NULL;
	bdUInt i;
	for(i = 0; i < m_teamMembers.m_members.getSize() && userID == BD_NULL; i++)
	{
		if(m_teamMembers.m_members[i].m_status == bdGetTeamMembersResult::BD_ORDINARY)
		{
			userID = m_teamMembers.m_members[i].m_userID;
		}
	}
	
	if(teams && amOwner && userID != BD_NULL)
	{
		m_remoteTask = teams->promoteMember(0, m_myTeam.m_teamID, userID);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

void Simulation::pumpPromoteMember()
{
	m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);

	if(m_taskStatus == DONE)
	{
		// fail safe
		m_taskStatus = FAILED;

		bdTeams *const teams = GetTeams();
		if(teams)
		{
			const bdBool taskHandled = teams->handleTask(m_remoteTask, BD_NULL);
			if(taskHandled)
			{
				m_taskStatus = DONE;
			}
		}
	}

	if((m_taskStatus == DONE) || (m_taskStatus == FAILED))
	{
		CloseRemoteTask(&m_remoteTask);
	}
}

void Simulation::promoteMemberDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Promote Member",			// READY
											"Promoting Member",			// PENDING
											"Promoted Member",			// DONE
											"Promote Member Failed",	// FAILED
											"Promote Member Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::startDemoteMember()
{
	// fail safe
	m_taskStatus = FAILED;

	bdTeams *const teams = GetTeams();

	// Check for team ownership, and that there is a member who can be demoted.
	bdBool amOwner = m_myTeam.m_memberStatus == bdCheckTeamMembershipResult::BD_OWNER;
	bdOnlineUserID userID = BD_NULL;
	bdUInt i;
	for(i = 0; i < m_teamMembers.m_members.getSize() && userID == BD_NULL; i++)
	{
		if(m_teamMembers.m_members[i].m_userID != bdAuthUtility::getUserID(m_userName))
		{
			userID = m_teamMembers.m_members[i].m_userID;
		}
	}
	if(teams && amOwner && userID != BD_NULL)
	{
		m_remoteTask = teams->demoteMember(0, m_myTeam.m_teamID, userID);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

void Simulation::pumpDemoteMember()
{
	m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);

	if(m_taskStatus == DONE)
	{
		// fail safe
		m_taskStatus = FAILED;

		bdTeams *const teams = GetTeams();
		if(teams)
		{
			const bdBool taskHandled = teams->handleTask(m_remoteTask, BD_NULL);
			if(taskHandled)
			{
				m_taskStatus = DONE;
			}
		}
	}

	if((m_taskStatus == DONE) || (m_taskStatus == FAILED))
	{
		CloseRemoteTask(&m_remoteTask);
	}
}

void Simulation::demoteMemberDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Demote Member",			// READY
											"Demoting Member",			// PENDING
											"Demoted Member",			// DONE
											"Demote Member Failed",		// FAILED
											"Demote Member Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::startKickMember()
{
	// fail safe
	m_taskStatus = FAILED;

	bdTeams *const teams = GetTeams();

	// Check for team ownership, and that there is a member who can be demoted.
	bdBool amAdmin = m_myTeam.m_memberStatus != bdCheckTeamMembershipResult::BD_ORDINARY;
	bdOnlineUserID userID = BD_NULL;
	bdUInt i;
	for(i = 0; i < m_teamMembers.m_members.getSize() && userID == BD_NULL; i++)
	{
		if(m_teamMembers.m_members[i].m_status == bdGetTeamMembersResult::BD_ORDINARY
		   && m_teamMembers.m_members[i].m_userID != bdAuthUtility::getUserID(m_userName))
		{
			userID = m_teamMembers.m_members[i].m_userID;
		}
	}
	if(teams && amAdmin && userID != BD_NULL)
	{
		m_remoteTask = teams->kickMember(0, m_myTeam.m_teamID, userID);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

void Simulation::pumpKickMember()
{
	m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);

	if(m_taskStatus == DONE)
	{
		// fail safe
		m_taskStatus = FAILED;

		bdTeams *const teams = GetTeams();
		if(teams)
		{
			const bdBool taskHandled = teams->handleTask(m_remoteTask, BD_NULL);
			if(taskHandled)
			{
				m_taskStatus = DONE;
			}
		}
	}

	if((m_taskStatus == DONE) || (m_taskStatus == FAILED))
	{
		CloseRemoteTask(&m_remoteTask);
	}
}

void Simulation::kickMemberDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Kick Member",			// READY
											"Kicking Member",		// PENDING
											"Kicked Member",		// DONE
											"Kick Member Failed",	// FAILED
											"Kick Member Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::startSetPublicTeamInfo()
{
	// fail safe
	m_taskStatus = FAILED;

	bdTeams *const teams = GetTeams();
	if(teams && m_myTeam.m_memberStatus == bdCheckTeamMembershipResult::BD_OWNER)
	{
		PublicTeamInfo teamInfo;
		teamInfo.m_int1 = 0;
		teamInfo.m_int2 = 0;
		teamInfo.m_int3 = 0;
		teamInfo.m_int4 = 0;
		teamInfo.m_int5 = 0;
		teamInfo.m_int6 = 0;
		teamInfo.m_string1 = "Motto: live and let die";
		teamInfo.m_string2 = "key words";
		m_remoteTask = teams->setPublicInfo(0, m_myTeam.m_teamID, &teamInfo);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

void Simulation::pumpSetPublicTeamInfo()
{
	m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);

	if(m_taskStatus == DONE)
	{
		// fail safe
		m_taskStatus = FAILED;

		bdTeams *const teams = GetTeams();
		if(teams)
		{
			const bdBool taskHandled = teams->handleTask(m_remoteTask, BD_NULL);
			if(taskHandled)
			{
				m_taskStatus = DONE;
			}
		}
	}

	if((m_taskStatus == DONE) || (m_taskStatus == FAILED))
	{
		CloseRemoteTask(&m_remoteTask);
	}
}

void Simulation::setPublicTeamInfoDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Set Public Team Info",				// READY
											"Setting Public Team Info",			// PENDING
											"Set Public Team Info Successful",	// DONE
											"Set Public Team Info Failed",		// FAILED
											"Set Public Team Info Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::startGetPublicTeamInfo()
{
	// fail safe
	m_taskStatus = FAILED;

	bdTeams *const teams = GetTeams();
	if(teams && m_myTeam.m_teamID != BD_NULL)
	{
		m_remoteTask = teams->getPublicInfo(0, m_myTeam.m_teamID);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

void Simulation::pumpGetPublicTeamInfo()
{
	m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);

	if(m_taskStatus == DONE)
	{
		// fail safe
		m_taskStatus = FAILED;

		bdTeams *const teams = GetTeams();
		if(teams)
		{
			const bdBool taskHandled = teams->handleTask(m_remoteTask, &m_publicTeamInfo);
			if(taskHandled)
			{
				m_taskStatus = DONE;
			}
		}
	}

	if((m_taskStatus == DONE) || (m_taskStatus == FAILED))
	{
		CloseRemoteTask(&m_remoteTask);
	}
}

void Simulation::getPublicTeamInfoDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Get Public Team Info",			// READY
		"Getting Public Team Info",		// PENDING
		"Got Public Team Info",			// DONE
		"Get Public Team Info Failed",	// FAILED
		"Get Public Team Info Skipped"};// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);

	if (m_taskStatus == DONE)
	{
		description += "\n";
		description += m_publicTeamInfo.m_data.m_string1;
		description += "\n";
		description += m_publicTeamInfo.m_data.m_string2;
	}
}

void Simulation::startSetPrivateTeamInfo()
{
	// fail safe
	m_taskStatus = FAILED;

	bdTeams *const teams = GetTeams();
	if(teams && m_myTeam.m_memberStatus == bdCheckTeamMembershipResult::BD_OWNER)
	{
		PrivateTeamInfo teamInfo;
		teamInfo.m_string1 = "Use strategy 16b from clan website.";
		teamInfo.m_string2 = "Enemy base C.";
		m_remoteTask = teams->setPrivateInfo(0, m_myTeam.m_teamID, &teamInfo);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

void Simulation::pumpSetPrivateTeamInfo()
{
	m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);

	if(m_taskStatus == DONE)
	{
		// fail safe
		m_taskStatus = FAILED;

		bdTeams *const teams = GetTeams();
		if(teams)
		{
			const bdBool taskHandled = teams->handleTask(m_remoteTask, BD_NULL);
			if(taskHandled)
			{
				m_taskStatus = DONE;
			}
		}
	}

	if((m_taskStatus == DONE) || (m_taskStatus == FAILED))
	{
		CloseRemoteTask(&m_remoteTask);
	}
}

void Simulation::setPrivateTeamInfoDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Set Private Team Info",			// READY
											"Setting Private Team Info",			// PENDING
											"Set Private Team Info Successful",			// DONE
											"Set Private Team Info Failed",		// FAILED
											"Set Private Team Info Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::startGetPrivateTeamInfo()
{
	// fail safe
	m_taskStatus = FAILED;

	bdTeams *const teams = GetTeams();
	if(teams && m_myTeam.m_teamID != BD_NULL)
	{
		m_remoteTask = teams->getPrivateInfo(0, m_myTeam.m_teamID);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

void Simulation::pumpGetPrivateTeamInfo()
{
	m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);

	if(m_taskStatus == DONE)
	{
		// fail safe
		m_taskStatus = FAILED;

		bdTeams *const teams = GetTeams();
		if(teams)
		{
			const bdBool taskHandled = teams->handleTask(m_remoteTask, &m_privateTeamInfo);
			if(taskHandled)
			{
				m_taskStatus = DONE;
			}
		}
	}

	if((m_taskStatus == DONE) || (m_taskStatus == FAILED))
	{
		CloseRemoteTask(&m_remoteTask);
	}
}

void Simulation::getPrivateTeamInfoDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Get Private Team Info",			// READY
											"Getting Private Team Info",			// PENDING
											"Got Private Team Info",			// DONE
											"Get Private Team Info Failed",		// FAILED
											"Get Private Team Info Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);

	if (m_taskStatus == DONE)
	{
		description += "\n";
		description += m_privateTeamInfo.m_data.m_string1;
		description += "\n";
		description += m_privateTeamInfo.m_data.m_string2;
	}
}

void Simulation::startSetPublicMemberInfo()
{
	// fail safe
	m_taskStatus = FAILED;

	bdTeams *const teams = GetTeams();
	if(teams && m_myTeam.m_teamID != BD_NULL)
	{
		PublicTeamMemberInfo memberInfo;
		memberInfo.m_int1 = 0;
		memberInfo.m_int2 = 0;
		memberInfo.m_int3 = 0;
		memberInfo.m_string1 = "Scout";
		memberInfo.m_string2 = "PingIsland";
		m_remoteTask = teams->setPublicMemberInfo(0, m_myTeam.m_teamID, &memberInfo);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

void Simulation::pumpSetPublicMemberInfo()
{
	m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);

	if(m_taskStatus == DONE)
	{
		// fail safe
		m_taskStatus = FAILED;

		bdTeams *const teams = GetTeams();
		if(teams)
		{
			const bdBool taskHandled = teams->handleTask(m_remoteTask, BD_NULL);
			if(taskHandled)
			{
				m_taskStatus = DONE;
			}
		}
	}

	if((m_taskStatus == DONE) || (m_taskStatus == FAILED))
	{
		CloseRemoteTask(&m_remoteTask);
	}
}

void Simulation::setPublicMemberInfoDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Set Public Member Info",			// READY
											"Setting Public Member Info",			// PENDING
											"Set Public Member Info Succeed",		// DONE
											"Set Public Member Info Failed",		// FAILED
											"Set Public Member Info Skipped"};		// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::startGetPublicMemberInfo()
{
	// fail safe
	m_taskStatus = FAILED;

	bdTeams *const teams = GetTeams();
	if(teams && m_teamMembers.m_members.getSize() > 0)
	{
		bdOnlineUserID userID;
		userID = m_teamMembers.m_members[0].m_userID;

		m_remoteTask = teams->getPublicMemberInfo(0, m_myTeam.m_teamID, userID);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

void Simulation::pumpGetPublicMemberInfo()
{
	m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);

	if(m_taskStatus == DONE)
	{
		// fail safe
		m_taskStatus = FAILED;

		bdTeams *const teams = GetTeams();
		if(teams)
		{
			const bdBool taskHandled = teams->handleTask(m_remoteTask, &m_publicTeamMemberInfo);
			if(taskHandled)
			{
				m_taskStatus = DONE;
			}
		}
	}

	if((m_taskStatus == DONE) || (m_taskStatus == FAILED))
	{
		CloseRemoteTask(&m_remoteTask);
	}
}

void Simulation::getPublicMemberInfoDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Get Public Member Info",			// READY
											"Getting Public Member Info",		// PENDING
											"Got Public Member Info",			// DONE
											"Get Public Member Info Failed",	// FAILED
											"Get Public Member Info Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);

	if (m_taskStatus == DONE)
	{
		description += "\n";
		description += m_publicTeamMemberInfo.m_data.m_string1;
		description += "\n";
		description += m_publicTeamMemberInfo.m_data.m_string2;
	}
}

void Simulation::startSetPrivateMemberInfo()
{
	// fail safe
	m_taskStatus = FAILED;

	bdTeams *const teams = GetTeams();
	if(teams && m_myTeam.m_teamID != BD_NULL)
	{
		PrivateTeamMemberInfo memberInfo;
		memberInfo.m_int1 = 3;
		memberInfo.m_string1 = "Sahara";
		memberInfo.m_string2 = "Defender";

		m_remoteTask = teams->setPrivateMemberInfo(0, m_myTeam.m_teamID, &memberInfo);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

void Simulation::pumpSetPrivateMemberInfo()
{
	m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);

	if(m_taskStatus == DONE)
	{
		// fail safe
		m_taskStatus = FAILED;

		bdTeams *const teams = GetTeams();
		if(teams)
		{
			const bdBool taskHandled = teams->handleTask(m_remoteTask, BD_NULL);
			if(taskHandled)
			{
				m_taskStatus = DONE;
			}
		}
	}

	if((m_taskStatus == DONE) || (m_taskStatus == FAILED))
	{
		CloseRemoteTask(&m_remoteTask);
	}
}

void Simulation::setPrivateMemberInfoDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Set Private Member Info",			// READY
											"Setting Private Member Info",		// PENDING
											"Set Private Member Info Successful",// DONE
											"Set Private Member Info Failed",	// FAILED
											"Set Private Member Info Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::startGetPrivateMemberInfo()
{
	// fail safe
	m_taskStatus = FAILED;

	bdTeams *const teams = GetTeams();
	if(teams && m_myTeam.m_teamID != BD_NULL)
	{
		bdOnlineUserID userID;
		userID = bdAuthUtility::getUserID(m_userName);

		m_remoteTask = teams->getPrivateMemberInfo(0, m_myTeam.m_teamID, userID);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

void Simulation::pumpGetPrivateMemberInfo()
{
	m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);

	if(m_taskStatus == DONE)
	{
		// fail safe
		m_taskStatus = FAILED;

		bdTeams *const teams = GetTeams();
		if(teams)
		{
			const bdBool taskHandled = teams->handleTask(m_remoteTask, &m_privateTeamMemberInfo);
			if(taskHandled)
			{
				m_taskStatus = DONE;
			}
		}
	}

	if((m_taskStatus == DONE) || (m_taskStatus == FAILED))
	{
		CloseRemoteTask(&m_remoteTask);
	}
}

void Simulation::getPrivateMemberInfoDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Get Private Member Info",			// READY
											"Getting Private Member Info",		// PENDING
											"Got Private Member Info",			// DONE
											"Get Private Member Info Failed",	// FAILED
											"Get Private Member Info Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);

	if (m_taskStatus == DONE)
	{
		description += "\n";
		description += m_privateTeamMemberInfo.m_data.m_string1;
		description += "\n";
		description += m_privateTeamMemberInfo.m_data.m_string2;
	}
}

void Simulation::startSendMemberMessage()
{
	// fail safe
	m_taskStatus = FAILED;

	// Find a userID that is not the local user to send a message to.
	bdOnlineUserID userID = BD_NULL;
	bdUInt i;
	for(i = 0; i < m_teamMembers.m_members.getSize() && userID != BD_NULL; i++)
	{
		if(m_teamMembers.m_members[i].m_userID != bdAuthUtility::getUserID(m_userName))
		{
			userID = m_teamMembers.m_members[i].m_userID;
		}
	}

	bdTeams *const teams = GetTeams();
	
	if(teams && m_teamMembers.m_members.getSize() > 0)
	{
		bdByteBuffer buffer(128);
		bdString msg = "Hey ";
		msg += m_teamMembers.m_members[i].m_userName;
		msg += " would you like to play with me tonight?";
		buffer.write(msg.getBuffer(), msg.getLength()+1);

		m_remoteTask = teams->sendMemberMessage(0, userID, buffer, bdTeams::BD_PUSH_ONLY);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

void Simulation::pumpSendMemberMessage()
{
	m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);

	if(m_taskStatus == DONE)
	{
		// fail safe
		m_taskStatus = FAILED;

		bdTeams *const teams = GetTeams();
		if(teams)
		{
			const bdBool taskHandled = teams->handleTask(m_remoteTask, BD_NULL);
			if(taskHandled)
			{
				m_taskStatus = DONE;
			}
		}
	}

	if((m_taskStatus == DONE) || (m_taskStatus == FAILED))
	{
		CloseRemoteTask(&m_remoteTask);
	}
}

void Simulation::sendMemberMessageDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Send Member Message",			// READY
											"Sending Member Message",		// PENDING
											"Sent Member Message",			// DONE
											"Send Member Message Failed",	// FAILED
											"Send Member Message Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::startSendAdminMessage()
{
	// fail safe
	m_taskStatus = FAILED;

	bdTeams *const teams = GetTeams();
	if(teams && m_myTeam.m_memberStatus != bdCheckTeamMembershipResult::BD_ORDINARY)
	{
		bdByteBuffer buffer(128);
		bdString msg = "Hey everyone, who's available Friday for team match?";
		buffer.write(msg.getBuffer(), msg.getLength()+1);

		m_remoteTask = teams->sendAdminMessage(0, m_myTeam.m_teamID, buffer, bdTeams::BD_PULL_ONLY);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

void Simulation::pumpSendAdminMessage()
{
	m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);

	if(m_taskStatus == DONE)
	{
		// fail safe
		m_taskStatus = FAILED;

		bdTeams *const teams = GetTeams();
		if(teams)
		{
			const bdBool taskHandled = teams->handleTask(m_remoteTask, BD_NULL);
			if(taskHandled)
			{
				m_taskStatus = DONE;
			}
		}
	}

	if((m_taskStatus == DONE) || (m_taskStatus == FAILED))
	{
		CloseRemoteTask(&m_remoteTask);
	}
}

void Simulation::sendAdminMessageDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Send Admin Message",			// READY
											"Sending Admin Message",		// PENDING
											"Sent Admin Message",			// DONE
											"Send Admin Message Failed",	// FAILED
											"Send Admin Message Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::lobbyServiceDisconnectDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Disconnect from Lobby Service",			// READY
											"Disconnecting from Lobby Service",			// PENDING
											"Disconnected from Lobby Service",			// DONE
											"Disconnect from Lobby Service Failed",		// FAILED
											"Disconnect from Lobby Service Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::startLobbyServiceDisconnect()
{
	// fail safe
	m_taskStatus = FAILED;

	bdLobbyServiceImpl *const lobbyService = bdLobbyService::getInstance();
	if(lobbyService)
	{
		lobbyService->disconnect();
		m_taskStatus = PENDING;
	}
}

void Simulation::pumpLobbyServiceDisconnect()
{
	// fail safe
	m_taskStatus = FAILED;

	bdLobbyServiceImpl *const lobbyService = bdLobbyService::getInstance();
	if(lobbyService)
	{
		const bdLobbyConnection::Status status = lobbyService->getStatus();
		switch(status)
		{
			case bdConnection::BD_DISCONNECTED:
			case bdConnection::BD_NOT_CONNECTED:
			{
				m_taskStatus = DONE;
			}
			break;
			case bdConnection::BD_CONNECTING:
			case bdConnection::BD_CONNECTED:
			{
				m_taskStatus = FAILED;
			}
			break;
			case bdConnection::BD_DISCONNECTING:
			{
				m_taskStatus = PENDING;
			}
			break;
		}
	}
}

void Simulation::stopNetworkDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Stop Network",					// READY
											"Stopping Network",				// PENDING
											"Stopped Network",				// DONE
											"Stopping Network Failed",		// FAILED
											"Stopping Network Skipped"};	// SKIPPED

	const bdUInt numDescriptions = sizeof(descriptions) / sizeof(bdNChar8*);
	IndexStrings(descriptions, numDescriptions, m_taskStatus, description);
}

void Simulation::stopNetwork()
{
	bdNetImpl *const net = bdNet::getInstance();
	net->stop();
	if(net->getStatus() == bdNetImpl::BD_NET_STOPPED)
	{
		m_taskStatus = DONE;
	}
	else
	{
		m_taskStatus = FAILED;
	}
}

void Simulation::checkProfilesError()
{
	const bdProfiles *const profiles = GetProfiles();
	if(profiles)
	{
		m_lobbyErrorCode = profiles->getErrorCode();
	}
}

void Simulation::checkTeamsError()
{
	const bdTeams *const teams = GetTeams();
	if(teams)
	{
		m_lobbyErrorCode = teams->getErrorCode();
	}
}

void Simulation::pumpGenericTeamsTask()
{
	m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);

	if(m_taskStatus == DONE)
	{
		// fail safe
		m_taskStatus = FAILED;

		bdTeams *const teams = GetTeams();
		if(teams)
		{
			const bdBool taskHandled = teams->handleTask(m_remoteTask, BD_NULL);
			if(taskHandled)
			{
				m_taskStatus = DONE;
			}
		}
	}

	if((m_taskStatus == DONE) || (m_taskStatus == FAILED))
	{
		CloseRemoteTask(&m_remoteTask);
	}
}

Simulation::Task Simulation::determineNextTask(Task currentTask)
{
	// if we fail to setup nextTask then exiting is wise.
	Task nextTask = STOP_NETWORK;

	// Inspect the message store to see if there are any proposals or invites
	// outstanding.
	bdUInt numProposals = 0;
	bdUInt numInvites = 0;
	bdMessageStore *const messageStore = GetMessageStore();
	bdUInt i;
	for(i = 0; i < messageStore->getNumMessages(); i++) 
	{
		if(messageStore->getAt(i)->m_msgType == BD_TEAM_INVITATION_MSG)
		{
			numProposals++;
		}
		else if(messageStore->getAt(i)->m_msgType == BD_TEAM_SESSION_INVITATION_MSG)
		{
			numInvites++;
		}
	}
	switch(currentTask)
	{
		case GET_MESSAGES:
		{
			if(numProposals > 0)
			{
				nextTask = ACCEPT_MEMBERSHIP;
			}
			else if(numInvites > 0)
			{
				nextTask = ACCEPT_INVITATION;
			}
			else
			{
				nextTask = GET_MESSAGES;
			}
		}
		break;
		case ACCEPT_MEMBERSHIP:
		case REJECT_MEMBERSHIP:
		{
			if(numProposals > 1)
			{
				nextTask = ACCEPT_MEMBERSHIP;
			}
			else if(numInvites > 0)
			{
				nextTask = ACCEPT_INVITATION;
			}
			else
			{
				nextTask = GET_MESSAGES;
			}
		}
		break;
		case ACCEPT_INVITATION:
		case REJECT_INVITATION:
		{
			if(numInvites > 1)
			{
				nextTask = ACCEPT_INVITATION;
			}
			else
			{
				nextTask = GET_MESSAGES;
			}
		}
		break;
		default:
		{
			// don't care..
		}
		break;
	}
	return nextTask;
}

void Simulation::checkMessageStore()
{
	if(m_messageTimer.getElapsedTimeInSeconds() > 5)
	{
		m_messageTimer.reset();
		m_messageText = "";
	}

	bdMessageStore *const messageStore = bdLobbyService::getInstance()->getMessageStore();
	if(messageStore->getNumMessages() > 0)
	{
		m_messageText = "";
		m_messageTimer.start();
	}
	bdUInt i;
	bdUInt messageIndex = 0;
	bdUInt numMessages = messageStore->getNumMessages();
	for(i=0; i<numMessages; i++)
	{
		m_messageText += "\n\n";
		bdLobbyMessageRef msg = messageStore->getAt(messageIndex);
		switch(msg->m_msgType) 
		{
			case BD_TEAM_INVITATION_MSG:
			{
				// The bdTeamInvitationMessage class actually represents a proposal. It will
				// be renamed in the next major release.
				bdTeamInvitationMessageRef concreteMsg = reference_cast<bdTeamInvitationMessage>(msg);
				m_messageText += "Received a team proposal from ";
				m_messageText += concreteMsg->m_originatorName;
				m_messageText += " for team ";
				m_messageText += concreteMsg->m_teamName;
				m_messageText += ". Message attachment contains:\n\"";
				
				const bdUInt msgTextLen = 128;
				bdNChar8 msgText[msgTextLen];
				bdMemset(msgText, '\0', msgTextLen);
				if(concreteMsg->m_attachmentSize <= msgTextLen)
				{
					bdMemcpy(msgText, concreteMsg->m_attachment, concreteMsg->m_attachmentSize);
				}
				
				m_messageText += msgText;
				m_messageText += "\"";
			}
			break;
			case BD_TEAM_SESSION_INVITATION_MSG:
			{
				bdTeamSessionInvitationMessageRef concreteMsg = reference_cast<bdTeamSessionInvitationMessage>(msg);
				m_messageText += "Received a session invitation from ";
				m_messageText += concreteMsg->m_originatorName;
				m_messageText += " for team ";
				m_messageText += concreteMsg->m_teamName;
				m_messageText += ". Message attachment contains:\n\"";

				const bdUInt msgTextLen = 128;
				bdNChar8 msgText[msgTextLen];
				bdMemset(msgText, '\0', msgTextLen);
				if(concreteMsg->m_attachmentSize <= msgTextLen)
				{
					bdMemcpy(msgText, concreteMsg->m_attachment, concreteMsg->m_attachmentSize);
				}

				m_messageText += msgText;
				m_messageText += "\"";
			}
			break;
			case BD_TEAM_MEMBER_CUSTOM_MSG:
			{
				bdTeamMemberCustomMessageRef concreteMsg = reference_cast<bdTeamMemberCustomMessage>(msg);
				m_messageText += "Received a private member message from ";
				m_messageText += concreteMsg->m_originatorName;
				m_messageText += " in team ";
				m_messageText += concreteMsg->m_teamName;
				m_messageText += ". Message attachment contains:\n\"";

				const bdUInt msgTextLen = 128;
				bdNChar8 msgText[msgTextLen];
				bdMemset(msgText, '\0', msgTextLen);
				concreteMsg->m_data->read(msgText, msgTextLen);
				m_messageText += msgText;
				m_messageText += "\"";
			}
			break;
			case BD_TEAM_ADMIN_CUSTOM_MSG:
			{
				bdTeamAdminCustomMessageRef concreteMsg = reference_cast<bdTeamAdminCustomMessage>(msg);
				m_messageText += "Received a team broadcast message from administrator ";
				m_messageText += concreteMsg->m_originatorName;
				m_messageText += " in team ";
				m_messageText += concreteMsg->m_teamName;
				m_messageText += ". Message attachment contains:\n\"";

				const bdUInt msgTextLen = 128;
				bdNChar8 msgText[msgTextLen];
				concreteMsg->m_data->read(msgText, msgTextLen);

				m_messageText += msgText;
				m_messageText += "\"";
			}
			break;
			// The following cases are all notifications and have near identical
			// implementations.
			case BD_TEAM_ACCEPT_MSG:
			{
				bdTeamAcceptMessageRef concreteMsg = reference_cast<bdTeamAcceptMessage>(msg);
				m_messageText += "Received BD_TEAM_ACCEPT_MSG notification from ";
				m_messageText += concreteMsg->m_originatorName;
				m_messageText += " regarding team ";
				m_messageText += concreteMsg->m_teamName;
				// Add the user into the local m_teamMembers object
				{
					bdGetTeamMembersResult::bdTeamMember member;
					member.m_isOnline = false;
					member.m_status = bdGetTeamMembersResult::BD_ORDINARY;
					member.m_userID = concreteMsg->m_originatorID;
					bdStrlcpy(member.m_userName, concreteMsg->m_originatorName, BD_MAX_USERNAME_LENGTH);
					m_teamMembers.m_members.pushBack(member);
				}
			}
			break;
			case BD_TEAM_REJECT_MSG:
			{
				bdTeamRejectMessageRef concreteMsg = reference_cast<bdTeamRejectMessage>(msg);
				m_messageText += "Received BD_TEAM_REJECT_MSG notification from ";
				m_messageText += concreteMsg->m_originatorName;
				m_messageText += " regarding team ";
				m_messageText += concreteMsg->m_teamName;
			}
			break;
			case BD_TEAM_LEAVE_MSG:
			{
				bdTeamLeaveMessageRef concreteMsg = reference_cast<bdTeamLeaveMessage>(msg);
				m_messageText += "Received BD_TEAM_LEAVE_MSG notification from ";
				m_messageText += concreteMsg->m_originatorName;
				m_messageText += " regarding team.\n";
				m_messageText += concreteMsg->m_teamName;				
				m_messageText += concreteMsg->m_relevantName;
				m_messageText += " has left the team ";
				// Remove the user from the local m_teamMembers object
				{
					bdUInt i;
					for(i = 0; i < m_teamMembers.m_members.getSize(); i++)
					{
						if(m_teamMembers.m_members[i].m_userID == concreteMsg->m_originatorID)
						{
							m_teamMembers.m_members.removeAt(i);
							break;
						}
					}
				}
			}
			break;
			case BD_TEAM_PROMOTION_MSG:
			{
				bdTeamPromotionMessageRef concreteMsg = reference_cast<bdTeamPromotionMessage>(msg);
				m_messageText += "Received BD_TEAM_PROMOTION_MSG notification from ";
				m_messageText += concreteMsg->m_originatorName;
				m_messageText += " regarding team ";
				m_messageText += concreteMsg->m_teamName;
				m_messageText += "\nUserName ";
				m_messageText += concreteMsg->m_relevantName;
				m_messageText += " has been promoted to Admin.";
				// Promote the user's status in the local m_teamMembers object
				{
					bdUInt i;
					for(i = 0; i < m_teamMembers.m_members.getSize(); i++)
					{
						if(m_teamMembers.m_members[i].m_userID == concreteMsg->m_originatorID)
						{
							m_teamMembers.m_members[i].m_status = bdGetTeamMembersResult::BD_ADMIN;
							break;
						}
					}
				}
			}
			break;
			case BD_TEAM_KICK_MSG:
			{
				bdTeamKickMessageRef concreteMsg = reference_cast<bdTeamKickMessage>(msg);
				m_messageText += "Received BD_TEAM_KICK_MSG notification from ";
				m_messageText += concreteMsg->m_originatorName;
				m_messageText += " regarding team ";
				m_messageText += concreteMsg->m_teamName;
				m_messageText += concreteMsg->m_relevantName;
				m_messageText += " has been kicked.";
				// Remove the user from the local m_teamMembers object
				{
					bdUInt i;
					for(i = 0; i < m_teamMembers.m_members.getSize(); i++)
					{
						if(m_teamMembers.m_members[i].m_userID == concreteMsg->m_originatorID)
						{
							m_teamMembers.m_members.removeAt(i);
							break;
						}
					}
				}
			}
			break;
			case BD_TEAM_SESSION_ACCEPT_MSG:
			{
				bdTeamSessionAcceptMessageRef concreteMsg = reference_cast<bdTeamSessionAcceptMessage>(msg);
				m_messageText += "Received BD_TEAM_SESSION_ACCEPT_MSG notification from ";
				m_messageText += concreteMsg->m_originatorName;
				m_messageText += " regarding team ";
				m_messageText += concreteMsg->m_teamName;
			}
			break;
			case BD_TEAM_SESSION_REJECT_MSG:
			{
				bdTeamSessionRejectMessageRef concreteMsg = reference_cast<bdTeamSessionRejectMessage>(msg);
				m_messageText += "Received BD_TEAM_SESSION_REJECT_MSG notification from ";
				m_messageText += concreteMsg->m_originatorName;
				m_messageText += " regarding team ";
				m_messageText += concreteMsg->m_teamName;
			}
			break;
			case BD_TEAM_MEMBER_CONNECTED_MSG:
			{
				bdTeamMemberConnectedMessageRef concreteMsg = reference_cast<bdTeamMemberConnectedMessage>(msg);
				m_messageText += "Received BD_TEAM_MEMBER_CONNECTED_MSG notification from ";
				m_messageText += concreteMsg->m_originatorName;
				m_messageText += " regarding team ";
				m_messageText += concreteMsg->m_teamName;
				// Update the user's online status in the local m_teamMembers object
				{
					bdUInt i;
					for(i = 0; i < m_teamMembers.m_members.getSize(); i++)
					{
						if(m_teamMembers.m_members[i].m_userID == concreteMsg->m_originatorID)
						{
							m_teamMembers.m_members[i].m_isOnline = true;
							break;
						}
					}
				}
			}
			break;
			case BD_TEAM_MEMBER_DISCONNECTED_MSG:
			{
				bdTeamMemberDisconnectedMessageRef concreteMsg = reference_cast<bdTeamMemberDisconnectedMessage>(msg);
				m_messageText += "Received BD_TEAM_MEMBER_DISCONNECTED_MSG notification from ";
				m_messageText += concreteMsg->m_originatorName;
				m_messageText += " regarding team ";
				m_messageText += concreteMsg->m_teamName;
				// Update the user's online status in the local m_teamMembers object
				{
					bdUInt i;
					for(i = 0; i < m_teamMembers.m_members.getSize(); i++)
					{
						if(m_teamMembers.m_members[i].m_userID == concreteMsg->m_originatorID)
						{
							m_teamMembers.m_members[i].m_isOnline = false;
							break;
						}
					}
				}
			}
			break;
			case BD_TEAM_DISSOLVED:
			{
				bdTeamDissolvedRef concreteMsg = reference_cast<bdTeamDissolved>(msg);
				m_messageText += "Received BD_TEAM_DISSOLVED notification from ";
				m_messageText += concreteMsg->m_originatorName;
				m_messageText += " regarding team ";
				m_messageText += concreteMsg->m_teamName;
				// Remove the team from the local m_memberships object
				{
					bdUInt i;
					for(i = 0; i < m_memberships.m_teams.getSize(); i++)
					{
						if(m_memberships.m_teams[i].m_teamID == concreteMsg->m_teamID)
						{
							m_memberships.m_teams.removeAt(i);
							break;
						}
					}
				}
			}
			break;
			case BD_TEAMNAME_UPDATED:
			{
				bdTeamNameUpdatedRef concreteMsg = reference_cast<bdTeamNameUpdated>(msg);
				m_messageText += "Received BD_TEAMNAME_UPDATED notification from ";
				m_messageText += concreteMsg->m_originatorName;
				m_messageText += " regarding team ";
				m_messageText += concreteMsg->m_teamName;
				// Update the teamname in the local m_memberships object
				{
					bdUInt i;
					for(i = 0; i < m_memberships.m_teams.getSize(); i++)
					{
						if(m_memberships.m_teams[i].m_teamID == concreteMsg->m_teamID)
						{
							bdStrlcpy(m_memberships.m_teams[i].m_teamName, concreteMsg->m_teamName, BD_MAX_TEAMNAME_LENGTH);
							break;
						}
					}
				}
			}
			break;
			case BD_TEAM_PROMOTION_TO_OWNER_MSG:
			{
				bdTeamOwnerPromotionMessageRef concreteMsg = reference_cast<bdTeamOwnerPromotionMessage>(msg);
				m_messageText += "Received BD_TEAM_PROMOTION_TO_OWNER_MSG notification from ";
				m_messageText += concreteMsg->m_originatorName;
				m_messageText += " regarding team ";
				m_messageText += concreteMsg->m_teamName;
				// Promote the user's status in the local m_teamMembers object
				{
					bdUInt i;
					for(i = 0; i < m_teamMembers.m_members.getSize(); i++)
					{
						if(m_teamMembers.m_members[i].m_userID == concreteMsg->m_originatorID)
						{
							m_teamMembers.m_members[i].m_status = bdGetTeamMembersResult::BD_OWNER;
							break;
						}
					}
				}
			}
			break;
			case BD_TEAMMEMBERSHIP_PROPOSAL_CANCEL_MSG:
			{
				bdTeamMembershipProposalCancelMessageRef concreteMsg = reference_cast<bdTeamMembershipProposalCancelMessage>(msg);
				m_messageText += "Received BD_TEAMMEMBERSHIP_PROPOSAL_CANCEL_MSG notification from ";
				m_messageText += concreteMsg->m_originatorName;
				m_messageText += " regarding team ";
				m_messageText += concreteMsg->m_teamName;
			}
			break;
			case BD_TEAMMEMBER_STATUS_ONLINE:
			{
				bdTeamMemberStatusUpdateMessageRef concreteMsg = reference_cast<bdTeamMemberStatusUpdateMessage>(msg);
				m_messageText += "Received BD_TEAMMEMBER_STATUS_ONLINE notification from ";
				m_messageText += concreteMsg->m_originatorName;
				m_messageText += " regarding team ";
				m_messageText += concreteMsg->m_teamName;
				// Update the user's online status in the local m_teamMembers object
				{
					bdUInt i;
					for(i = 0; i < m_teamMembers.m_members.getSize(); i++)
					{
						if(m_teamMembers.m_members[i].m_userID == concreteMsg->m_originatorID)
						{
							m_teamMembers.m_members[i].m_isOnline = true;
							break;
						}
					}
				}
			}
			break;
			case BD_TEAMMEMBER_DEMOTED_TO_ORDINARY:
			{
				bdTeamDemotionMessageRef concreteMsg = reference_cast<bdTeamDemotionMessage>(msg);
				m_messageText += "Received BD_TEAMMEMBER_DEMOTED_TO_ORDINARY notification from ";
				m_messageText += concreteMsg->m_originatorName;
				m_messageText += " regarding team ";
				m_messageText += concreteMsg->m_teamName;
				m_messageText += ".\n";
				m_messageText += concreteMsg->m_relevantName;
				m_messageText += " has been demoted from Admin.";

				// Promote the user's status in the local m_teamMembers object
				{
					bdUInt i;
					for(i = 0; i < m_teamMembers.m_members.getSize(); i++)
					{
						if(m_teamMembers.m_members[i].m_userID == concreteMsg->m_originatorID)
						{
							m_teamMembers.m_members[i].m_status = bdGetTeamMembersResult::BD_ORDINARY;
							break;
						}
					}
				}
			}
			break;

			case BD_TEAM_PUBLIC_INFO_UPDATED:
			{
				bdTeamPublicInfoUpdatedMessageRef concreteMsg = reference_cast<bdTeamPublicInfoUpdatedMessage>(msg);
				m_messageText += "Received bdTeamPublicInfoUpdatedMessage notification from ";
				m_messageText += concreteMsg->m_originatorName;
				m_messageText += " regarding team ";
				m_messageText += concreteMsg->m_teamName;
				m_messageText += ".\n";
			}
			break;
			case BD_TEAM_PRIVATE_INFO_UPDATED:
			{
				bdTeamPrivateInfoUpdatedMessageRef concreteMsg = reference_cast<bdTeamPrivateInfoUpdatedMessage>(msg);
				m_messageText += "Received bdTeamPrivateInfoUpdatedMessage notification from ";
				m_messageText += concreteMsg->m_originatorName;
				m_messageText += " regarding team ";
				m_messageText += concreteMsg->m_teamName;
				m_messageText += ".\n";
			}
			break;
			case BD_TEAMMEMBER_PUBLIC_INFO_UPDATED:
			{
					bdTeamMemberPublicInfoUpdatedMessageRef concreteMsg = reference_cast<bdTeamMemberPublicInfoUpdatedMessage>(msg);
					m_messageText += "Received bdTeamMemberPublicInfoUpdatedMessage notification from ";
					m_messageText += concreteMsg->m_originatorName;
					m_messageText += " regarding team ";
					m_messageText += concreteMsg->m_teamName;
					m_messageText += ".\n";
			}
			break;
			case BD_TEAMMEMBER_PRIVATE_INFO_UPDATED:
			{
				bdTeamMemberPrivateInfoUpdatedMessageRef concreteMsg = reference_cast<bdTeamMemberPrivateInfoUpdatedMessage>(msg);
				m_messageText += "Received bdTeamMemberPrivateInfoUpdatedMessage notification from ";
				m_messageText += concreteMsg->m_originatorName;
				m_messageText += " regarding team ";
				m_messageText += concreteMsg->m_teamName;
				m_messageText += ".\n";
			}
			break;

			default:
			{
				// Do nothing.
			}
		}
		m_messageText += "\n";
		// The following a special messages that we deal with elsewhere, so we
		// don't remove them until then.
		if(	msg->m_msgType !=  BD_TEAM_INVITATION_MSG &&
			msg->m_msgType !=  BD_TEAM_SESSION_INVITATION_MSG)
		{
			messageStore->removeAt(messageIndex);
		}
		else
		{
			// leave the message to be handled by GET_MESSAGES
			messageIndex++;
		}
	}
}

