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

#include <bdLobby/bdMatchMaking/bdMatchMaking.h>

#include <bdLobby/bdMatchMaking/bdMatchMakingInfo.h>
#include <bdLobby/bdRemoteTaskManager/bdRemoteTaskManager.h>

#define BD_LOG_LEVEL	("lobby/matchmaking")

bdMatchMaking::bdMatchMaking(bdRemoteTaskManager *const remoteTaskManager)
: m_remoteTaskManager(remoteTaskManager),
  m_errorCode(BD_NO_ERROR)
{
}


bdMatchMaking::~bdMatchMaking()
{
	m_remoteTaskManager = BD_NULL;
}


bdRemoteTask *bdMatchMaking::createSession(const bdUByte8 /*controllerIndex*/,
										   bdMatchMakingInfo *const params)
{
	bdRemoteTask *task = startTask(0,
								   params,
								   BD_MM_CREATE_SESSION);

	return task;
}


bdRemoteTask *bdMatchMaking::updateSession(const bdUByte8 /*controllerIndex*/,
										   bdMatchMakingInfo *const params)
{
	bdRemoteTask *task = startTask(0,
								   params,
								   BD_MM_UPDATE_SESSION);

	return task;
}


bdRemoteTask* bdMatchMaking::deleteSession(const bdUByte8 /*controllerIndex*/,
										   const bdSecurityID& securityID)
{
	bdRemoteTask *task = BD_NULL;
	bdBitBuffer buffer(0,true);
	buffer.writeUByte8(0);
	buffer.writeBlob(securityID.ab, sizeof(bdSecurityID));
	
	// start message
	m_errorCode = m_remoteTaskManager->startTask(&task,
												 BD_MATCHMAKING_SERVICE,
												 BD_MM_DELETE_SESSION,
												 buffer);
	return task;
}


bdRemoteTask* bdMatchMaking::findSessionFromID(const bdSecurityID& securityID)
{
	bdRemoteTask *task = BD_NULL;
	bdBitBuffer buffer(0,true);
	
	// write empty controller index, it doesn't matter who has requested findSessionFromID
	buffer.writeUByte8(0); 

	buffer.writeBlob(securityID.ab, sizeof(bdSecurityID));

	// start message
	m_errorCode = m_remoteTaskManager->startTask(&task,
												 BD_MATCHMAKING_SERVICE,
												 BD_MM_FIND_SESSION_BY_ID,
												 buffer);

	return task;
}


bdRemoteTask* bdMatchMaking::findSessions(bdCustomQueryParams *const params)
{	
	// write empty controller index, it doesn't matter who has requested findSessionFromID
	bdUByte8 controllerID = 0;

	bdRemoteTask *task = startTask(controllerID,
								   params,
								   BD_MM_FIND_SESSIONS);

	return task;
}


bdRemoteTask* bdMatchMaking::startTask(const bdUByte8 /*controllerIndex*/,
									   bdQueryParams *params,
									   const bdUByte8 BD_TASK_ID)
{
	// write interface params, and bdStatsInfo custom params
	bdBitBuffer buffer(0, true);
	buffer.writeUByte8(0);

	// serialize additional params if present
	if (params != BD_NULL)
	{
		params->serialize(buffer);
		//TODO: is this still needed?
		int x = 0;
		buffer.writeBits(&x, 8);
		buffer.writeBits(&x, 8);
	}

	// start task
	bdRemoteTask *task = BD_NULL;

	m_errorCode = m_remoteTaskManager->startTask(&task,
												 BD_MATCHMAKING_SERVICE,
												 BD_TASK_ID,
												 buffer);
	return task;
}


bdBool bdMatchMaking::handleTask(const bdRemoteTask *const remoteTask, 
								 bdQueryResult *const queryResult)
{
	bdBool ok;
	bdBitBufferRef buffer = remoteTask->getResults();
	bdUInt32 taskErrorCode = BD_MAX_ERROR_CODE;
	ok = buffer->readUInt32(taskErrorCode);
	if (ok)
	{
		m_errorCode = static_cast<bdLobbyErrorCode>(taskErrorCode);
		if (m_errorCode == BD_NO_ERROR)
		{
			bdUByte8 operation;
			ok = buffer->readUByte8(operation);
			if(ok)
			{
				switch (operation)
				{
					case BD_MM_CREATE_SESSION:
					case BD_MM_FIND_SESSION_BY_ID:
					case BD_MM_FIND_SESSIONS:
					{
						if (queryResult)
						{
							bdUInt32 numReplies = 0;
							ok = buffer->readUInt32(numReplies);
							if (ok && numReplies > 0)
							{
								ok = queryResult->handleResult(numReplies, buffer);
							}
						}
					}
					break;
					case BD_MM_DELETE_SESSION:
					case BD_MM_UPDATE_SESSION:
					{
						// no results here, just task completed
					}
					break;
					default:
					{
					}
					break;
				}
			}
		}
#if defined BD_DEBUG
		else
		{
			bdUInt64 transactionID;
			bdUInt64 connectionID;

			connectionID = m_remoteTaskManager->getConnectionID();
			transactionID = remoteTask->getTransactionID();

			// here we originally called bdRemoteTaskManager::obtainTransactionID
			BD_WARN(BD_LOG_LEVEL, "Transaction ID " BD_UINT_64_FORMAT ":" BD_UINT_64_FORMAT " failed.",
				connectionID, transactionID);
		}
#endif // BD_DEBUG
	}
	return (m_errorCode == BD_NO_ERROR && ok);
}

bdLobbyErrorCode bdMatchMaking::getErrorCode() const
{
	return m_errorCode;
}
