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

#include "UserInfo.h"
#include "Simulation.h"
#include <bdLobby/bdMessageStore/bdMessageTypes/bdFriendCustomMessage.h>
#include <bdLobby/bdMessageStore/bdMessageTypes/bdFriendSessionInvitationMessage.h>
#include <bdLobby/bdMessageStore/bdMessageTypes/bdFriendshipProposalMessage.h>
#include <bdLobby/bdFriends/bdFriends.h>

#include <bdLobby/bdFriends/bdGetFriendsResult.h>
#include <bdLobby/bdFriends/bdGetBlockListResult.h>
#include <bdLobby/bdFriends/bdGetGroupNamesResult.h>
#include <bdLobby/bdFriends/bdGetGroupedFriendsResult.h>
#include <bdLobby/bdFriends/bdGetProposalListResult.h>

#define TITLE_ID (0x12F7)
#define PLAYER1 "FrndExample1"
#define PASS1 "MyPassword"
#define PLAYER2 "FrndExample2"
#define PASS2 "MyPassword"
#define INITIAL_GAME_TYPE (1)
#define CHANGED_GAME_TYPE (2)

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_messageText + m_screenText);

	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
	{
		const bdBool startKey = getScreen().wasKeyPressed(START_KEY);
		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 CREATE_PLAYER1:
			{
				createPlayer1Description(taskDescription);
				if(startKey)
				{
					startCreatePlayer1();
				}
			}
			break;
			case CREATE_PLAYER2:
			{
				createPlayer2Description(taskDescription);
				if(startKey)
				{
					startCreatePlayer2();
				}
			}
			break;
			case AUTHENTICATE_PLAYER1:
			{
				authenticatePlayer1Description(taskDescription);
				if(startKey)
				{
					startAuthenticatePlayer1();
				}
			}
			break;
			case AUTHENTICATE_PLAYER2:
			{
				authenticatePlayer2Description(taskDescription);
				if(startKey)
				{
					startAuthenticatePlayer2();
				}
			}
			break;
			case LOBBY_CONNECT:
			{
				lobbyServiceConnectDescription(taskDescription);
				if(startKey)
				{
					startLobbyServiceConnect();
				}
			}
			break;
			case CREATE_PROFILE:
			{
				createProfileDescription(taskDescription);
				if(startKey)
				{
					startCreateProfile();
				}
			}
				break;
			case GET_MESSAGES:
			{
				createGetMessagesDescription(taskDescription);
				if(startKey)
				{
					startGetMessages();
				}
			}
			break;
			case ACCEPT_PROPOSAL:
			{
				createAcceptProposalDescription(taskDescription);
				if(startKey)
				{
					startAcceptProposal();
				}
			}
			break;
			case REJECT_PROPOSAL:
			{
				createRejectProposalDescription(taskDescription);
				if(startKey)
				{
					startRejectProposal();
				}
			}
				break;
			case GET_FRIENDS:
			{
				createGetFriendsDescription(taskDescription);
				if(startKey)
				{
					startGetFriends();
				}
			}
			break;
			case PROPOSE_FRIENDSHIP:
			{
				createProposeFriendshipDescription(taskDescription);
				if(startKey)
				{
					startProposeFriendship();
				}
			}
			break;
			case LIST_PROPOSALS:
			{
				createListProposalsDescription(taskDescription);
				if(startKey)
				{
					startListProposals();
				}
			}
			break;
			case WITHDRAW_PROPOSAL:
			{
				createWithdrawProposalDescription(taskDescription);
				if(startKey)
				{
					startWithdrawProposal();
				}
			}
			break;

			case INVITE_FRIEND:
				{
					createInviteDescription(taskDescription);
					if (startKey)
					{
						startInvite();
					}
				}
			break;
			case ACCEPT_INVITATION:
				{
					createAcceptInviteDescription(taskDescription);
					if (startKey)
					{
						startAcceptInvite();
					}
				}
			break;
			case REJECT_INVITATION:
				{
					createRejectInviteDescription(taskDescription);
					if (startKey)
					{
						startRejectInvite();
					}
				}
			break;
			case SEND_CUSTOM:
				{
					createSendCustomDescription(taskDescription);
					if (startKey)
					{
						startSendCustom();
					}
				}
			break;
			case CREATE_GROUP:
				{
					createGroupDescription(taskDescription);
					if (startKey)
					{
						startGroup();
					}
				}
			break;
			case LIST_GROUPS:
				{
					createListGroupsDescription(taskDescription);
					if (startKey)
					{
						startListGroups();
					}
				}
			break;
			case ADD_FRIEND_TO_GROUP:
				{
					createAddFriendToGroupDescription(taskDescription);
					if (startKey)
					{
						startAddFriendToGroup();
					}
				}
			break;
			case LIST_GROUP_FRIENDS:
				{
					createListGroupFriendsDescription(taskDescription);
					if (startKey)
					{
						startListGroupFriends();
					}
				}
			break;
			case DELETE_GROUP:
				{
					createDeleteGroupDescription(taskDescription);
					if (startKey)
					{
						startDeleteGroup();
					}
				}
			break;
			case REMOVE_FRIEND:
				{
					createRemoveFriendDescription(taskDescription);
					if (startKey)
					{
						startRemoveFriend();
					}
				}
			break;
			case BLOCK_USER:
				{
					createBlockUserDescription(taskDescription);
					if (startKey)
					{
						startBlockUser();
					}
				}
			break;
			case LIST_BLOCKED:
				{
					createListBlockedDescription(taskDescription);
					if (startKey)
					{
						startListBlocked();
					}
				}
			break;
			case UNBLOCK_USER:
				{
					createUnblockUserDescription(taskDescription);
					if (startKey)
					{
						startUnblockUser();
					}
				}
			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 CREATE_PLAYER1:
		{
			createPlayer1Description(taskDescription);
			pumpCreatePlayer1();
		}
		break;
		case CREATE_PLAYER2:
		{
			createPlayer2Description(taskDescription);
			pumpCreatePlayer2();
		}
		break;
		case AUTHENTICATE_PLAYER1:
		{
			authenticatePlayer1Description(taskDescription);
			pumpAuthenticatePlayer1();
		}
		break;
		case AUTHENTICATE_PLAYER2:
		{
			authenticatePlayer2Description(taskDescription);
			pumpAuthenticatePlayer2();
		}
		break;
		case LOBBY_CONNECT:
		{
			lobbyServiceConnectDescription(taskDescription);
			pumpLobbyServiceConnect();
		}
		break;
		case CREATE_PROFILE:
		{
			createProfileDescription(taskDescription);
			pumpCreateProfile();
		}
		break;
		case GET_MESSAGES:
		{
			createGetMessagesDescription(taskDescription);
			pumpGetMessages();
		}
		break;
		case ACCEPT_PROPOSAL:
		{
			createAcceptProposalDescription(taskDescription);
			pumpAcceptProposal();
		}
		break;
		case REJECT_PROPOSAL:
		{
			createRejectProposalDescription(taskDescription);
			pumpRejectProposal();
		}
		break;
		case GET_FRIENDS:
		{
			createGetFriendsDescription(taskDescription);
			pumpGetFriends();
		}
		break;
		case PROPOSE_FRIENDSHIP:
		{
			createProposeFriendshipDescription(taskDescription);
			pumpProposeFriendship();
		}
		break;
		case LIST_PROPOSALS:
		{
			createListProposalsDescription(taskDescription);
			pumpListProposals();
		}
		break;
		case WITHDRAW_PROPOSAL:
		{
			createWithdrawProposalDescription(taskDescription);
			pumpWithdrawProposal();
		}
		break;
		case INVITE_FRIEND:
		{
			createInviteDescription(taskDescription);
			pumpInvite();
		}
		break;
		case ACCEPT_INVITATION:
		{
			createAcceptInviteDescription(taskDescription);
			pumpAcceptInvite();
		}
		break;
		case REJECT_INVITATION:
		{
			createRejectInviteDescription(taskDescription);
			pumpRejectInvite();
		}
		break;
		case SEND_CUSTOM:
		{
			createSendCustomDescription(taskDescription);
			pumpSendCustom();
		}
		break;
		case CREATE_GROUP:
		{
			createGroupDescription(taskDescription);
			pumpGroup();
		}
		break;
		case LIST_GROUPS:
		{
			createListGroupsDescription(taskDescription);
			pumpListGroups();
		}
		break;
		case ADD_FRIEND_TO_GROUP:
		{
			createAddFriendToGroupDescription(taskDescription);
			pumpAddFriendToGroup();
		}
		break;
		case LIST_GROUP_FRIENDS:
		{
			createListGroupFriendsDescription(taskDescription);
			pumpListGroupFriends();
		}
		break;
		case DELETE_GROUP:
		{
			createDeleteGroupDescription(taskDescription);
			pumpDeleteGroup();
		}
		break;
		case REMOVE_FRIEND:
		{
			createRemoveFriendDescription(taskDescription);
			pumpRemoveFriend();
		}
		break;
		case BLOCK_USER:
		{
			createBlockUserDescription(taskDescription);
			pumpBlockUser();
		}
		break;
		case LIST_BLOCKED:
		{
			createListBlockedDescription(taskDescription);
			pumpListBlocked();
		}
		break;
		case UNBLOCK_USER:
		{
			createUnblockUserDescription(taskDescription);
			pumpUnblockUser();
		}
		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 = CREATE_PLAYER1;
			nextTaskIfFailed = CHECK_DNS;
			nextTaskIfSkipped = CREATE_PLAYER1;
			displayLobbyError = false;
		}
		break;
		case CREATE_PLAYER1:
		{
			createPlayer1Description(m_lastTaskDescription);
			checkAuthServiceError();
			nextTaskIfDone = AUTHENTICATE_PLAYER1;
			nextTaskIfFailed = CREATE_PLAYER1;
			nextTaskIfSkipped = CREATE_PLAYER2;			
		}
		break;
		case CREATE_PLAYER2:
		{
			createPlayer1Description(m_lastTaskDescription);
			checkAuthServiceError();
			nextTaskIfDone = AUTHENTICATE_PLAYER2;
			nextTaskIfFailed = CREATE_PLAYER2;
			nextTaskIfSkipped = AUTHENTICATE_PLAYER1;			
		}
		break;
		case AUTHENTICATE_PLAYER1:
		{
			authenticatePlayer1Description(m_lastTaskDescription);
			checkAuthServiceError();
			nextTaskIfDone = LOBBY_CONNECT;
			nextTaskIfFailed = AUTHENTICATE_PLAYER1;
			nextTaskIfSkipped = AUTHENTICATE_PLAYER2;			
		}
		break;		
		case AUTHENTICATE_PLAYER2:
		{
			authenticatePlayer2Description(m_lastTaskDescription);
			checkAuthServiceError();
			nextTaskIfDone = LOBBY_CONNECT;
			nextTaskIfFailed = AUTHENTICATE_PLAYER2;
			nextTaskIfSkipped = LOBBY_CONNECT;			
		}
		break;
		case LOBBY_CONNECT:
		{
			lobbyServiceConnectDescription(m_lastTaskDescription);
			nextTaskIfDone = CREATE_PROFILE;
			nextTaskIfFailed = LOBBY_CONNECT;
			nextTaskIfSkipped = CREATE_PROFILE;
		}
		break;
		case CREATE_PROFILE:
		{
			createProfileDescription(m_lastTaskDescription);
			nextTaskIfDone = GET_MESSAGES;
			nextTaskIfFailed = CREATE_PROFILE;
			nextTaskIfSkipped = GET_MESSAGES;
		}
		break;
		case GET_MESSAGES:
		{
			createGetMessagesDescription(m_lastTaskDescription);
			nextTaskIfDone = determineNextTask(m_task);
			nextTaskIfFailed = GET_MESSAGES;
			nextTaskIfSkipped = GET_FRIENDS;
		}
		break;
		case ACCEPT_PROPOSAL:
		{
			createAcceptProposalDescription(m_lastTaskDescription);
			nextTaskIfDone = determineNextTask(m_task);
			nextTaskIfFailed = ACCEPT_PROPOSAL;
			nextTaskIfSkipped = REJECT_PROPOSAL;
		}
		break;
		case REJECT_PROPOSAL:
		{
			createRejectProposalDescription(m_lastTaskDescription);
			nextTaskIfDone = determineNextTask(m_task);
			nextTaskIfFailed = REJECT_PROPOSAL;
			nextTaskIfSkipped = determineNextTask(m_task);
		}
		break;
		case ACCEPT_INVITATION:
		{
			createAcceptInviteDescription(m_lastTaskDescription);
			nextTaskIfDone = determineNextTask(m_task);
			nextTaskIfFailed = ACCEPT_INVITATION;
			nextTaskIfSkipped = REJECT_INVITATION;
		}
		break;
		case REJECT_INVITATION:
		{
			createRejectInviteDescription(m_lastTaskDescription);
			nextTaskIfDone = determineNextTask(m_task);
			nextTaskIfFailed = REJECT_INVITATION;
			nextTaskIfSkipped = determineNextTask(m_task);
		}
		break;
		case GET_FRIENDS:
		{
			createGetFriendsDescription(m_lastTaskDescription);
			nextTaskIfDone = PROPOSE_FRIENDSHIP;
			nextTaskIfFailed = GET_FRIENDS;
			nextTaskIfSkipped = PROPOSE_FRIENDSHIP;
		}
		break;
		case PROPOSE_FRIENDSHIP:
		{
			createProposeFriendshipDescription(m_lastTaskDescription);
			nextTaskIfDone = LIST_PROPOSALS;
			nextTaskIfFailed = PROPOSE_FRIENDSHIP;
			nextTaskIfSkipped = LIST_PROPOSALS;
		}
		break;
		case LIST_PROPOSALS:
		{
			createListProposalsDescription(m_lastTaskDescription);
			nextTaskIfDone = WITHDRAW_PROPOSAL;
			nextTaskIfFailed = LIST_PROPOSALS;
			nextTaskIfSkipped = WITHDRAW_PROPOSAL;
		}
		break;
		case WITHDRAW_PROPOSAL:
		{
			createWithdrawProposalDescription(m_lastTaskDescription);
			nextTaskIfDone = INVITE_FRIEND;
			nextTaskIfFailed = PROPOSE_FRIENDSHIP;
			nextTaskIfSkipped = INVITE_FRIEND;
		}
		break;
		case INVITE_FRIEND:
		{
			createInviteDescription(m_lastTaskDescription);
			nextTaskIfDone = SEND_CUSTOM;
			nextTaskIfFailed = INVITE_FRIEND;
			nextTaskIfSkipped = SEND_CUSTOM;
		}
		break;
		case SEND_CUSTOM:
		{
			createSendCustomDescription(m_lastTaskDescription);
			nextTaskIfDone = CREATE_GROUP;
			nextTaskIfFailed = SEND_CUSTOM;
			nextTaskIfSkipped = CREATE_GROUP;
		}
		break;
		case CREATE_GROUP:
		{
			createGroupDescription(m_lastTaskDescription);
			nextTaskIfDone = LIST_GROUPS;
			nextTaskIfFailed = CREATE_GROUP;
			nextTaskIfSkipped = LIST_GROUPS;
		}
		break;
		case LIST_GROUPS:
		{
			createListGroupsDescription(m_lastTaskDescription);
			nextTaskIfDone = ADD_FRIEND_TO_GROUP;
			nextTaskIfFailed = LIST_GROUPS;
			nextTaskIfSkipped = ADD_FRIEND_TO_GROUP;
		}
		break;
		case ADD_FRIEND_TO_GROUP:
		{
			createAddFriendToGroupDescription(m_lastTaskDescription);
			nextTaskIfDone = LIST_GROUP_FRIENDS;
			nextTaskIfFailed = ADD_FRIEND_TO_GROUP;
			nextTaskIfSkipped = LIST_GROUP_FRIENDS;
		}
		break;
		case LIST_GROUP_FRIENDS:
		{
			createListGroupFriendsDescription(m_lastTaskDescription);
			nextTaskIfDone = DELETE_GROUP;
			nextTaskIfFailed = LIST_GROUP_FRIENDS;
			nextTaskIfSkipped = DELETE_GROUP;
		}
		break;
		case DELETE_GROUP:
		{
			createDeleteGroupDescription(m_lastTaskDescription);
			nextTaskIfDone = REMOVE_FRIEND;
			nextTaskIfFailed = DELETE_GROUP;
			nextTaskIfSkipped = REMOVE_FRIEND;
		}
		break;
		case REMOVE_FRIEND:
		{
			createRemoveFriendDescription(m_lastTaskDescription);
			nextTaskIfDone = BLOCK_USER;
			nextTaskIfFailed = REMOVE_FRIEND;
			nextTaskIfSkipped = BLOCK_USER;
		}
		break;
		case BLOCK_USER:
		{
			createBlockUserDescription(m_lastTaskDescription);
			nextTaskIfDone = LIST_BLOCKED;
			nextTaskIfFailed = BLOCK_USER;
			nextTaskIfSkipped = LIST_BLOCKED;
		}
		break;
		case LIST_BLOCKED:
		{
			createListBlockedDescription(m_lastTaskDescription);
			nextTaskIfDone = UNBLOCK_USER;
			nextTaskIfFailed = LIST_BLOCKED;
			nextTaskIfSkipped = UNBLOCK_USER;
		}
		break;
		case UNBLOCK_USER:
		{
			createUnblockUserDescription(m_lastTaskDescription);
			nextTaskIfDone = LOBBY_DISCONNECT;
			nextTaskIfFailed = UNBLOCK_USER;
			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_PLAYER1;
		}
		break;
	}

	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;
	}

	// 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
		{
			checkFriendsError();
		}
		bdNChar8 buf[32];
		LobbyErrorCodeToString(m_lobbyErrorCode, buf, sizeof(buf));
		m_lastTaskDescription += "\nError: ";
		m_lastTaskDescription += buf;
		m_lobbyErrorCode = BD_NO_ERROR;
	}

	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(m_lsgGetHostByName)
	{
		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::createPlayer1Description(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Create Player 1 (" PLAYER1 "/" PASS1 ")",	// READY
											"Creating Player 1",								// PENDING
											"Created Player 1",								// DONE
											"Create Player 1 Failed",						// FAILED
											"Create Player 1 Skipped"};						// SKIPPED

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

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

	bdAuthService *const authService = getAuthService();
	if(authService)
	{
		if(authService->createAccount(PLAYER1, PASS1))
		{
			m_taskStatus = PENDING;
		}
	}
}

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

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

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

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

	bdAuthService *const authService = getAuthService();
	if(authService)
	{
		if(authService->createAccount(PLAYER2, PASS2))
		{
			m_taskStatus = PENDING;
		}
	}
}

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

void Simulation::authenticatePlayer1Description(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Authenticate Account (" PLAYER1 "/" PASS1 ")",	// READY
											"Authenticating Player 1",									// PENDING
											"Authenticated Player 1",									// DONE
											"Authenticate Player 1 Failed",								// FAILED
											"Authenticate Player 1 Skipped"};							// SKIPPED

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

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

	bdAuthService *const authService = getAuthService();	
	if(authService)
	{
		if(authService->authorizeAccount(PLAYER1, PASS1))
		{
			m_taskStatus = PENDING;
			m_playerNumber = 1; // note which player is being used
		}
	}
}

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

void Simulation::authenticatePlayer2Description(bdString& description)
{
	const bdNChar8 *const descriptions[] = {"Authenticate Account (" PLAYER2 "/" PASS2 ")",	// READY
		"Authenticating Player 2",									// PENDING
		"Authenticated Player 2",									// DONE
		"Authenticate Player 2 Failed",								// FAILED
		"Authenticate Player 2 Skipped"};							// SKIPPED

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

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

	bdAuthService *const authService = getAuthService();	
	if(authService)
	{
		if(authService->authorizeAccount(PLAYER2, PASS2))
		{
			m_taskStatus = PENDING;
			m_playerNumber = 2; // note which player is being used
		}
	}
}

void Simulation::pumpAuthenticatePlayer2()
{
	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
			"Profile Created",					// 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)
	{
		// fail safe
		m_taskStatus = FAILED;

		bdProfiles *const profiles = GetProfiles();
		if(profiles && profiles->handleTask(m_remoteTask))
		{
			m_taskStatus = DONE;
		}
	}

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

void Simulation::createGetMessagesDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = 
	{	
		"Retrieve Messages",					// READY
		"Retrieving Messages",					// PENDING
		"Messages retrieved",					// DONE
		"Messages could not be retrieved",		// FAILED
		"Message retrieval Skipped"				// SKIPPED
	};	

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

void Simulation::startGetMessages()
{
	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::createAcceptProposalDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = 
	{	
			"Accept Proposal",						// READY
			"Accepting Proposal",					// PENDING
			"Proposal Accepted",					// DONE
			"Proposal Accept Failed",				// FAILED
			"Proposal Accept Skipped"				// SKIPPED
	};	

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

void Simulation::startAcceptProposal()
{
	m_taskStatus = FAILED;
	
	bdMessageStore *const messageStore = GetMessageStore();
	bdFriends *const friends = GetFriends();

	if(messageStore && friends)	
	{
		// find a friend proposal message
		for(bdUInt i=0; i < messageStore->getNumMessages(); i++) 
		{
			const bdLobbyMessageRef baseMessage = messageStore->getAt(i);
			if(baseMessage.notNull() && (baseMessage->m_msgType == BD_FRIENDSHIP_PROPOSAL_MSG))
			{				
				const bdFriendshipProposalMessageRef message = reference_cast<bdFriendshipProposalMessage>(baseMessage);

				bdOnlineUserID otherID = message->m_originatorID;
				m_remoteTask = friends->acceptProposal(0, otherID);
				m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);

				messageStore->removeAt(i);
				break; // only take one
			}
		}
	}
}

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

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

		bdFriends *const friends = GetFriends();
		if(friends && friends->handleTask(m_remoteTask))
		{
			m_taskStatus = DONE;
		}
	}

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

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

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

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

	// find a friend proposal message
	bdMessageStore *const messageStore = GetMessageStore();
	bdFriends *const friends = GetFriends();

	if(messageStore && friends)
	{
		for(bdUInt i = 0; i < messageStore->getNumMessages(); i++) 
		{
			const bdLobbyMessageRef baseMessage = messageStore->getAt(i);
			if(baseMessage.notNull() && (baseMessage->m_msgType == BD_FRIENDSHIP_PROPOSAL_MSG))
			{
				const bdFriendshipProposalMessageRef message = reference_cast<bdFriendshipProposalMessage>(baseMessage);
				
				bdOnlineUserID otherID = message->m_originatorID;
				m_remoteTask = friends->rejectProposal(0, otherID);
				m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);

				messageStore->removeAt(i);
				break; // only take one
			}
		}
	}

}

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

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

		bdFriends *const friends = GetFriends();
		if(friends && friends->handleTask(m_remoteTask))
		{
			m_taskStatus = DONE;
		}
	}

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

void Simulation::createGetFriendsDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = 
	{	
			"Get Friends List",						// READY
			"Getting Friends List",					// PENDING
			"Friends List:\n",						// DONE
			"Get Friends List Failed",				// FAILED
			"Get Friends List Skipped"				// SKIPPED
	};	

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

	if (m_taskStatus == DONE)
	{
		if (m_listString.getLength()) 
		{
			description += m_listString;
		}
		else
		{
			description += "No friends found.";
		}
	}
}

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

	bdFriends *const friends = GetFriends();
	if(friends)
	{
		m_remoteTask = friends->getFriends(0);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

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

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

		bdFriends *const friends = GetFriends();

		bdGetFriendsResult result;
		if(friends && friends->handleTask(m_remoteTask, &result))		
		{
			m_taskStatus = DONE;
			m_listString = "";

			const bdUInt numFriends = result.m_friends.getSize();
			for(bdUInt i=0; i < numFriends; i++)
			{
				const bdGetFriendsResult::bdFriend& friendi = result.m_friends[i];
				const bdNChar8 *const onlineText = friendi.m_isOnline?"Online":"Offline";
				bdNChar8 buffer[128];
				bdSnprintf(buffer, sizeof(buffer), "\nFriend: %s (%s)", friendi.m_userName, onlineText);				
				m_listString += buffer;				
			}
		}
	}

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

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

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

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

	bdFriends *const friends = GetFriends();
	if(friends)
	{	
		const bdNChar8 *const otherUserName = (m_playerNumber == 1 ? PLAYER2 : PLAYER1);
		const bdOnlineUserID otherID = bdAuthUtility::getUserID(otherUserName);
		m_remoteTask = friends->proposeFriendship(0, otherID);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

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

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

		bdFriends *const friends = GetFriends();
		if(friends && friends->handleTask(m_remoteTask))
		{
			m_taskStatus = DONE;
		}
	}

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

void Simulation::createListProposalsDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = 
	{	
			"List Friendship Proposals",						// READY
			"Listing Friendship Proposals",						// PENDING
			"Friendship Proposals:\n",							// DONE
			"List Friendship Proposals Failed",			// FAILED
			"List Friendship Proposals Skipped"			// SKIPPED
	};	

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

	if (m_taskStatus == DONE)
	{
		if (m_listString.getLength()) 
		{
			description += m_listString;
		}
		else
		{
			description += "No friend proposals found.";
		}
	}
}

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

	bdFriends *const friends = GetFriends();
	if(friends)
	{	
		m_remoteTask = friends->getProposalList(0);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

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

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

		bdFriends *const friends = GetFriends();
		if(friends)
		{				
			bdGetProposalListResult result;
			if(friends->handleTask(m_remoteTask, &result))
			{
				m_taskStatus = DONE;
				m_listString = "";

				const bdUInt numProposals = result.m_proposalList.getSize();
				for(bdUInt i = 0; i < numProposals; i++)
				{
					const bdGetProposalListResult::bdPotentialFriend& proposal = result.m_proposalList[i];

					bdNChar8 buffer[128];
					bdSnprintf(buffer, sizeof(buffer), "\nPotential Friend: %s", proposal.m_userName);
					m_listString += buffer;					
				}
			}
		}
	}

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

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

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

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

	bdFriends *const friends = GetFriends();
	if(friends)
	{	
		const bdNChar8 *const otherUserName = (m_playerNumber == 1 ? PLAYER2 : PLAYER1);
		const bdOnlineUserID otherID = bdAuthUtility::getUserID(otherUserName);
		m_remoteTask = friends->withdrawProposal(0, otherID);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

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

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

		bdFriends *const friends = GetFriends();
		if(friends && friends->handleTask(m_remoteTask))
		{
			m_taskStatus = DONE;
		}
	}

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

void Simulation::createInviteDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = 
	{	
			"Invite Friend to Session",						// READY
			"Inviting Friend to Session",					// PENDING
			"Friend invited to session",					// DONE
			"Invite Friend to Session Failed",				// FAILED
			"Invite Friend to Session Skipped"				// SKIPPED
	};	

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

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

	bdFriends *const friends = GetFriends();
	if(friends)
	{
		// Invite a friend to an imaginary game session whose securityId 
		// is set to 'SECRETI'.
		bdSecurityID secId;
		bdMemcpy(secId.ab, static_cast<const void* const>("SECRETI"), BD_SECURITY_ID_LENGTH);

		// invite can include arbitrary attachments
		bdByteBuffer attachment(15);
		bdMemcpy(attachment.getData(), "Attachment Data", 15);

		const bdNChar8 *const otherUserName = (m_playerNumber == 1 ? PLAYER2 : PLAYER1);
		const bdOnlineUserID otherID = bdAuthUtility::getUserID(otherUserName);
		
		m_remoteTask = friends->inviteFriend(0, otherID, secId, &attachment);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

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

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

		bdFriends *const friends = GetFriends();
		if(friends && friends->handleTask(m_remoteTask))
		{
			m_taskStatus = DONE;
		}
	}

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

void Simulation::createAcceptInviteDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = 
	{	
			"Accept Invite",					// READY
			"Accepting Invite",					// PENDING
			"Invite Accepted",					// DONE
			"Accept Invite Failed",				// FAILED
			"Accept Invite Skipped"				// SKIPPED
	};	

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

void Simulation::startAcceptInvite()
{
	m_taskStatus = FAILED;

	bdFriends *const friends = GetFriends();
	bdMessageStore *const messageStore = GetMessageStore();

	if(friends && messageStore)	
	{
		// find a friend proposal message		
		const bdUInt numMessages = messageStore->getNumMessages();
		for(bdUInt i = 0; i < numMessages; i++) 
		{
			const bdLobbyMessageRef baseMessage = messageStore->getAt(i);
			if(baseMessage.notNull() && (baseMessage->m_msgType == BD_FRIEND_SESSION_INVITATION_MSG))
			{
				const bdFriendSessionInvitationMessageRef message = reference_cast<bdFriendSessionInvitationMessage>(baseMessage);

				const bdOnlineUserID otherID = message->m_originatorID;
				m_remoteTask = friends->acceptInvitation(0, otherID);
				m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);

				messageStore->removeAt(i);
				break; // only take one
			}
		}
	}
}

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

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

		bdFriends *const friends = GetFriends();
		if(friends && friends->handleTask(m_remoteTask))
		{
			m_taskStatus = DONE;
		}
	}

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

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

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

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

	bdMessageStore *const messageStore = GetMessageStore();
	bdFriends *const friends = GetFriends();

	if(friends && messageStore)	
	{
		// find a friend proposal message		
		for(bdUInt i = 0; i < messageStore->getNumMessages(); i++) 
		{
			const bdLobbyMessageRef baseMessage = messageStore->getAt(i);
			if(baseMessage.notNull() && (baseMessage->m_msgType == BD_FRIEND_SESSION_INVITATION_MSG))
			{
				const bdFriendSessionInvitationMessageRef message = reference_cast<bdFriendSessionInvitationMessage>(baseMessage);

				const bdOnlineUserID otherID = message->m_originatorID;
				m_remoteTask = friends->rejectInvitation(0, otherID);
				m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);

				messageStore->removeAt(i);
				break; // only take one
			}
		}
	}
}

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

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

		bdFriends *const friends = GetFriends();
		if(friends && friends->handleTask(m_remoteTask))
		{
			m_taskStatus = DONE;
		}
	}

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

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

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

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

	bdFriends *const friends = GetFriends();
	if(friends)
	{
		const bdNChar8 *const msg = "How's things my friend?\n";
		const bdUInt msgsize = static_cast<bdUInt>(bdStrlen(msg))+1;

		bdByteBuffer payload(msgsize);
		bdMemcpy(payload.getData(), msg, msgsize);

		const bdNChar8 *const otherUserName = (m_playerNumber == 1 ? PLAYER2 : PLAYER1);
		const bdOnlineUserID otherID = bdAuthUtility::getUserID(otherUserName);
		
		m_remoteTask = friends->sendFriendMessage(0, otherID, payload, bdFriends::BD_PUSH_AND_PULL);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

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

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

		bdFriends *const friends = GetFriends();
		if (friends && friends->handleTask(m_remoteTask))
		{
			m_taskStatus = DONE;
		}
	}

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

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

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

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

	bdFriends *const friends = GetFriends();
	if(friends)
	{
		m_remoteTask = friends->setGroupName(0, 1, "test_group1");
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

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

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

		bdFriends *const friends = GetFriends();
		if(friends && friends->handleTask(m_remoteTask))
		{
			m_taskStatus = DONE;
		}
	}

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

void Simulation::createListGroupsDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = 
	{	
			"List Groups",						// READY
			"Listing Groups",					// PENDING
			"Groups:\n",							// DONE
			"List Groups Failed",				// FAILED
			"List Groups Skipped"				// SKIPPED
	};	

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

	if (m_taskStatus == DONE)
	{
		if (m_listString.getLength()) 
		{
			description += m_listString;
		}
		else
		{
			description += "No groups found.";
		}
	}
}

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

	bdFriends *const friends = GetFriends();
	if(friends)
	{
		m_remoteTask = friends->getGroupNames(0);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

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

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

		bdFriends *const friends = GetFriends();
		bdGetGroupNamesResult result;
		if(friends && friends->handleTask(m_remoteTask, &result))
		{
			m_taskStatus = DONE;
			m_listString = "";

			const bdUInt numGroups = result.m_friendgroups.getSize();
			for(bdUInt i=0; i < numGroups; i++)
			{
				const bdGetGroupNamesResult::bdFriendGroup& group = result.m_friendgroups[i];

				bdNChar8 buffer[128];
				bdSnprintf(buffer, sizeof(buffer), "\nGroupID: %u GroupName: %s", group.m_groupID, group.m_groupName);				
				m_listString += buffer;			
			}
		}
	}

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

void Simulation::createAddFriendToGroupDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = 
	{	
			"Add Friend to Group",						// READY
			"Adding Friend to Group",					// PENDING
			"Added Friend to Group",					// DONE
			"Add Friend to Group Failed",				// FAILED
			"Add Friend to Group Skipped"				// SKIPPED
	};	

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

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

	bdFriends *const friends = GetFriends();
	if(friends)
	{
		const bdNChar8 *const otherUserName = (m_playerNumber == 1 ? PLAYER2 : PLAYER1);
		const bdOnlineUserID otherID = bdAuthUtility::getUserID(otherUserName);	
		m_remoteTask = friends->setFriendGroup(0, otherID, 1);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

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

	if(m_taskStatus == DONE)
	{
		// fail safe
		m_taskStatus = FAILED;
	
		bdFriends *const friends = GetFriends();
		if(friends && friends->handleTask(m_remoteTask))
		{
			m_taskStatus = DONE;
		}
	}

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

void Simulation::createListGroupFriendsDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = 
	{	
			"List Friends and their Group",						// READY
			"Listing Friends and their Group",					// PENDING
			"Friends in Group:\n",								// DONE
			"List Friends and their Group Failed",				// FAILED
			"List Friends and their Group Skipped"				// SKIPPED
	};	

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

	if (m_taskStatus == DONE)
	{
		if (m_listString.getLength()) 
		{
			description += m_listString;
		}
		else
		{
			description += "None found.";
		}
	}
}

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

	bdFriends *const friends = GetFriends();
	if(friends)
	{
		m_remoteTask = friends->getGroupedFriends(0);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

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

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

		bdFriends *const friends = GetFriends();
		bdGetGroupedFriendsResult result;
		if(friends && friends->handleTask(m_remoteTask, &result))
		{
			m_taskStatus = DONE;
			m_listString = "";

			const bdUInt numFriends = result.m_friends.getSize();
			for(bdUInt i = 0; i < numFriends; i++)
			{
				const bdGetGroupedFriendsResult::bdGroupedFriend& groupedFriend = result.m_friends[i];
				const bdNChar8 *const onlineText = groupedFriend.m_isOnline?"Online":"Offline";

				bdNChar8 buffer[128];
				bdSnprintf(buffer, sizeof(buffer), "\nFriend: %s Online: %s GroupID: %u",
					groupedFriend.m_userName,
					onlineText,
					groupedFriend.m_groupID);

				m_listString += buffer;				
			}
		}
	}

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

void Simulation::createDeleteGroupDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = 
	{	
			"Delete Group",						// READY
			"Deleting Group",					// PENDING
			"Deleted Group",					// DONE
			"Delete Group Failed",				// FAILED
			"Delete Group Skipped"				// SKIPPED
	};	

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

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

	bdFriends *const friends = GetFriends();
	if(friends)
	{
		m_remoteTask = friends->deleteGroupName(0, 1);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

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

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

		bdFriends *const friends = GetFriends();
		if(friends && friends->handleTask(m_remoteTask))
		{
			m_taskStatus = DONE;
		}
	}

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

void Simulation::createRemoveFriendDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = 
	{	
			"Remove Friend",					// READY
			"Removing Friend",					// PENDING
			"Removed Friend",					// DONE
			"Remove Friend Failed",				// FAILED
			"Remove Friend Skipped"				// SKIPPED
	};	

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

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

	bdFriends *const friends = GetFriends();
	if(friends)
	{
		const bdNChar8 *const otherUserName = (m_playerNumber == 1 ? PLAYER2 : PLAYER1);
		const bdOnlineUserID otherID = bdAuthUtility::getUserID(otherUserName);

		m_remoteTask = friends->removeFriend(0, otherID);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

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

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

		bdFriends *const friends = GetFriends();
		if(friends && friends->handleTask(m_remoteTask))
		{
			m_taskStatus = DONE;
		}
	}

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

void Simulation::createBlockUserDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = 
	{	
			"Block User",						// READY
			"Blocking User",					// PENDING
			"Blocked User",						// DONE
			"Block User Failed",				// FAILED
			"Block User Skipped"				// SKIPPED
	};	

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

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

	bdFriends *const friends = GetFriends();
	if(friends)
	{
		const bdNChar8 *const otherUserName = (m_playerNumber == 1 ? PLAYER2 : PLAYER1);
		const bdOnlineUserID otherID = bdAuthUtility::getUserID(otherUserName);

		m_remoteTask = friends->setBlockedStatus(0, otherID, bdFriends::BD_FULL_BLOCK);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

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

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

		bdFriends *const friends = GetFriends();
		if(friends && friends->handleTask(m_remoteTask))
		{
			m_taskStatus = DONE;
		}
	}

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

void Simulation::createListBlockedDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = 
	{	
			"List Blocked Users",						// READY
			"Listing Blocked Users",					// PENDING
			"Blocked Users:\n",							// DONE
			"List Blocked Users Failed",				// FAILED
			"List Blocked Users Skipped"				// SKIPPED
	};	

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

	if (m_taskStatus == DONE)
	{
		if (m_listString.getLength()) 
		{
			description += m_listString;
		}
		else
		{
			description += "None found.";
		}
	}
}

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

	bdFriends *const friends = GetFriends();
	if(friends)
	{
		m_remoteTask = friends->getBlockedList(0);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

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

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

		bdFriends *const friends = GetFriends();
		bdGetBlockListResult result;
		if(friends && friends->handleTask(m_remoteTask, &result))
		{
			m_taskStatus = DONE;
			m_listString = "";

			const bdUInt numBlocked = result.m_blockList.getSize();
			for(bdUInt i = 0; i < numBlocked; i++)
			{
				const bdGetBlockListResult::bdBlockedUser& blocked = result.m_blockList[i];

				bdNChar8 buffer[128];
				bdSnprintf(buffer, sizeof(buffer), "\nUserName: %s BlockType: %u",
					blocked.m_userName,
					blocked.m_blockLevel);

				m_listString += buffer;				
			}
		}
	}

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

void Simulation::createUnblockUserDescription(bdString& description)
{
	const bdNChar8 *const descriptions[] = 
	{	
			"Unblock User",						// READY
			"Unblocking User",					// PENDING
			"Unblocked User",					// DONE
			"Unblock User Failed",				// FAILED
			"Unblock User Skipped"				// SKIPPED
	};	

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

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

	bdFriends *const friends = GetFriends();
	if(friends)
	{
		const bdNChar8 *const otherUserName = (m_playerNumber == 1 ? PLAYER2 : PLAYER1);
		const bdOnlineUserID otherID = bdAuthUtility::getUserID(otherUserName);

		m_remoteTask = friends->setBlockedStatus(0, otherID, bdFriends::BD_NO_BLOCK);
		m_taskStatus = CheckRemoteTaskStatus(m_remoteTask);
	}
}

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

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

		bdFriends *const friends = GetFriends();
		if(friends && friends->handleTask(m_remoteTask))
		{
			m_taskStatus = DONE;
		}
	}

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

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)
	{
		bdExamplePlatformInit::quit();
		m_taskStatus = DONE;
	}
	else
	{
		m_taskStatus = FAILED;
	}
}

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

void Simulation::checkFriendsError()
{
	const bdFriends *const friends = GetFriends();
	if(friends)
	{
		m_lobbyErrorCode = friends->getErrorCode();
	}
}

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

	bdMessageStore *const messageStore = GetMessageStore();
	if(messageStore)
	{
		const bdUInt numMessages = messageStore->getNumMessages();
		if(numMessages > 0)
		{
			m_messageText = "";
			m_messageTimer.start();
		}

		bdUInt messageIndex = 0;
		for(bdUInt control = 0; control < numMessages; control++)
		{
			bdLobbyMessageRef msg = messageStore->getAt(messageIndex);
			switch(msg->m_msgType) 
			{
				case BD_FRIENDSHIP_ACCEPT_MSG:
					{
						bdFriendshipAcceptMessageRef friendlMsg = reference_cast<bdFriendshipAcceptMessage>(msg);
						m_messageText += "\n";
						m_messageText += friendlMsg->m_originatorName;
						m_messageText += " has accepted your friendship proposal\n";
					}
					break;
				case BD_FRIENDSHIP_REJECT_MSG:
					{
						bdFriendshipRejectMessageRef friendlMsg = reference_cast<bdFriendshipRejectMessage>(msg);
						m_messageText += "\n";
						m_messageText += friendlMsg->m_originatorName;
						m_messageText += " has rejected your friendship proposal\n";
					}
					break;
				case BD_FRIENDSHIP_REVOKE_MSG:
					{
						bdFriendshipRevokeMessageRef friendlMsg = reference_cast<bdFriendshipRevokeMessage>(msg);
						m_messageText += "\n";
						m_messageText += friendlMsg->m_originatorName;
						m_messageText += " has revoked the friendship proposal\n";
					}
					break;
				case BD_FRIEND_SESSION_ACCEPT_MSG:
					{
						bdFriendSessionAcceptMessageRef friendlMsg = reference_cast<bdFriendSessionAcceptMessage>(msg);
						m_messageText += "\n";
						m_messageText += friendlMsg->m_originatorName;
						m_messageText += " has accepted your session invitation\n";
					}
					break;
				case BD_FRIEND_SESSION_REJECT_MSG:
					{
						bdFriendSessionRejectMessageRef friendlMsg = reference_cast<bdFriendSessionRejectMessage>(msg);
						m_messageText += "\n";
						m_messageText += friendlMsg->m_originatorName;
						m_messageText += " has rejected your session invitation\n";
					}
					break;
				case BD_FRIEND_CONNECTED_MSG:
					{
						bdFriendConnectedMessageRef friendlMsg = reference_cast<bdFriendConnectedMessage>(msg);
						m_messageText += "\n";
						m_messageText += friendlMsg->m_originatorName;
						m_messageText += " has connected\n";
					}
					break;
				case BD_FRIEND_DISCONNECTED_MSG:
					{
						bdFriendDisconnectedMessageRef friendlMsg = reference_cast<bdFriendDisconnectedMessage>(msg);
						m_messageText += "\n";
						m_messageText += friendlMsg->m_originatorName;
						m_messageText += " has disconnected\n";
					}
					break;
				case BD_FRIENDSHIP_PROPOSAL_MSG:
					{
						bdFriendshipProposalMessageRef friendlMsg = reference_cast<bdFriendshipProposalMessage>(msg);
						m_messageText += "\n";
						m_messageText += friendlMsg->m_originatorName;
						m_messageText += " wants to be your friend\n";
					}
					break;
				case BD_FRIEND_SESSION_INVITATION_MSG:
					{
						bdFriendSessionInvitationMessageRef friendlMsg = reference_cast<bdFriendSessionInvitationMessage>(msg);
						m_messageText += "\n";
						m_messageText += friendlMsg->m_originatorName;
						m_messageText += " wants you to join his session\n";
					}
					break;
				case BD_FRIEND_CUSTOM_MSG:
					{
						bdFriendCustomMessageRef friendlMsg = reference_cast<bdFriendCustomMessage>(msg);
						m_messageText += "\n";
						m_messageText += friendlMsg->m_originatorName;
						m_messageText += " has sent you a custom message\n";
					}
					break;
				case BD_FRIEND_BLOCK_MSG:
					{
						bdFriendCustomMessageRef friendlMsg = reference_cast<bdFriendCustomMessage>(msg);
						m_messageText += "\n";
						m_messageText += friendlMsg->m_originatorName;
						m_messageText += " has blocked you\n";
					}
					break;
				case BD_FRIEND_UNBLOCK_MSG:
					{
						bdFriendCustomMessageRef friendlMsg = reference_cast<bdFriendCustomMessage>(msg);
						m_messageText += "\n";
						m_messageText += friendlMsg->m_originatorName;
						m_messageText += " has unblocked you\n";
					}
					break;
				default:
				{
					//don't care..
				}
				break;
			}
			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_FRIENDSHIP_PROPOSAL_MSG ||
				msg->m_msgType ==  BD_FRIEND_SESSION_INVITATION_MSG)
			{
				// leave the message to be handled by GET_MESSAGES
				messageIndex++;
			}
			else 
			{
				// a notification is all that's necessary, remove the message
				messageStore->removeAt(messageIndex);
			}
		}
	}
}

Simulation::Task Simulation::determineNextTask(Task currentTask)
{
	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_FRIENDSHIP_PROPOSAL_MSG)
		{
			numProposals++;
		}
		else if(messageStore->getAt(i)->m_msgType == BD_FRIEND_SESSION_INVITATION_MSG)
		{
			numInvites++;
		}
	}
	switch(currentTask)
	{
		case GET_MESSAGES:
		{
			if(numProposals > 0)
			{
				nextTask = ACCEPT_PROPOSAL;
			}
			else if(numInvites > 0)
			{
				nextTask = ACCEPT_INVITATION;
			}
			else
			{
				nextTask = GET_MESSAGES;
			}
		}
		break;
		case ACCEPT_PROPOSAL:
		case REJECT_PROPOSAL:
		{
			if(numProposals > 1)
			{
				nextTask = ACCEPT_PROPOSAL;
			}
			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;
}

