//
// Asura_PC_DirectPlay_Server.cpp
//
// Created by Kevin Lea - 14/06/2001 10:16:37
// 
// Copyright (C) 2001 Rebellion, All Rights Reserved.
//

#include "Core/Asura.h"

// This file's header.
#include "Network/Asura_PC_DirectPlay_Server.h"

// Engine independent.
#include "Core/Asura_Maths.h"
#include "Debugging/Asura_Assert.h"
#include "Debugging/Asura_Logfile.h"
#include "Network/Asura_Message.h"
#include "Network/Asura_Network.h"
#include "Network/Asura_Network_Session.h"

// Engine platform-specific.
#include "Core/Asura_dxutil.h"
#include "Network/Asura_PC_DirectPlay.h"
#include "Network/dp8sim.h"
#ifdef ASURA_PC_SUPPORT_GCDKEY
#include "Network/Asura_PC_GCDKey.h"
#endif

extern GUID Project_GUID;

//-----------------------------------------------------------------------------
// Defines, and constants
//-----------------------------------------------------------------------------
// (MH - 13.08.2003) put this in DirectPlay header
//#define SIMPLESERVER_DEFAULT_PORT           0x6501 // arbitrary port number for this app

DEBUGVAR bool dbg_bPrintSendToClientTimeouts = false;
DEBUGVAR bool dbg_bPrintSendToClientGuaranteedTimeouts = false;

//-----------------------------------------------------------------------------
// Player context locking defines
//-----------------------------------------------------------------------------
CRITICAL_SECTION g_csPlayerContext;
#define PLAYER_LOCK()                   EnterCriticalSection( &g_csPlayerContext ); 
#define PLAYER_ADDREF( pPlayerInfo )    if( pPlayerInfo ) pPlayerInfo->lRefCount++;
#define PLAYER_RELEASE( pPlayerInfo )   if( pPlayerInfo ) { pPlayerInfo->lRefCount--; if( pPlayerInfo->lRefCount <= 0 ) SAFE_DELETE( pPlayerInfo ); } pPlayerInfo = NULL;
#define PLAYER_UNLOCK()                 LeaveCriticalSection( &g_csPlayerContext );


//-----------------------------------------------------------------------------
// Global variables
//-----------------------------------------------------------------------------
LONG               g_lNumberOfActivePlayers      = 0;       // Number of players currently in game
TCHAR              g_strSessionName[MAX_PATH];              // Session name
DWORD              g_dwPort;                                // Port


static Asura_String gComputerName("Deadmeat");

static void GetComputerName(void)
{
	HKEY hKey;

	if 
	(
		ERROR_SUCCESS == RegOpenKeyEx
		(
			HKEY_LOCAL_MACHINE,
			"SYSTEM\\CurrentControlSet\\Control\\ComputerName\\ActiveComputerName",
			REG_OPTION_NON_VOLATILE,
			KEY_ALL_ACCESS,
			&hKey
		)
	)
	{
		char szBuf[MAX_PATH+1];
		DWORD dwType = REG_NONE;
		DWORD dwSize = sizeof szBuf;
		
		if
		(
			ERROR_SUCCESS == RegQueryValueEx
			(
				hKey,
				const_cast<char *>("ComputerName"),
				0,
				&dwType,
				reinterpret_cast<LPBYTE>(szBuf),
				&dwSize
			)
			&& REG_SZ == dwType
		)
		{
			int length=strlen(szBuf);
			if(length)
			{
				gComputerName = szBuf;
			}
				
		}

		RegCloseKey(hKey);
	}
}

void Asura_PC_DirectPlay::SetServerName(const Asura_UnicodeChar* wszName)
{
    s_wszSessionName = wszName;
}

// Kevin Lea - 14/06/2001 10:42:30 - Asura_PC_DirectPlay server stuff
Asura_PC_DirectPlay_Server* Asura_PC_DirectPlay::s_pxServer;

const Asura_UnicodeChar* Asura_PC_DirectPlay::s_wszSessionName = NULL;

bool Asura_PC_DirectPlay::StartServerAndHostSession(void)
{
    HRESULT hr;
    PDIRECTPLAY8ADDRESS pDP8AddrLocal = NULL;
	GUID xSPGuid = CLSID_DP8SP_TCPIP;

    WCHAR SessionName[MAX_PATH];
	Asura_Network_Session* pxSession;

    if (s_wszSessionName)
    {
        Asura_PrintfToBfr(SessionName, L"%s", MAX_PATH, true, s_wszSessionName);
    }
    else
    {
        GetComputerName();
	    int i = 0;
	    do
	    {
		    SessionName[i] = (Asura_UnicodeChar)gComputerName[i];
	    }
	    while(gComputerName[i++]!=0);
        
    }
	
    Asura_PC_DirectPlay_Server::CreateInstance( &s_pxServer );
    if( !s_pxServer ) { goto cleanup; }

    // Init IDirectPlay8Server
    {
        DWORD uFlags = 0;
        if( !Asura_Network::IsPlayingOnInternet() )
        {
            uFlags |= DPNINITIALIZE_HINT_LANSESSION;
        }

        hr = s_pxServer->Initialize( NULL, ServerMessageHandler, uFlags );
        if( FAILED(hr) )
        {
            Asura_Assert( false, "s_pxServer->Initialise() failed." );
            goto cleanup;
        }
    }

    hr = CoCreateInstance
	 	 (
			CLSID_DirectPlay8Address,
			NULL, 
			CLSCTX_ALL,
			IID_IDirectPlay8Address, 
			(LPVOID*) &pDP8AddrLocal
	 	 );
    if( FAILED(hr) )
    {
        Asura_Assert( false, "CoCreateInstance() failed." );
        goto cleanup;
    }

    // (MH - 14.08.2003) hack to get network simulator working
	// same as code in StartClient, expect called on server objects.
	if (s_bUseNetworkSimulator)
	{
		HRESULT                     hr              = S_OK;
		DPN_SERVICE_PROVIDER_INFO*  pdnSPInfo       = NULL;
		DPN_SERVICE_PROVIDER_INFO*  pdnSPInfoEnum   = NULL;
		DWORD                       dwItems         = 0;
		DWORD                       dwSize          = 0;   

		// Enumerate all the Service Providers available
		hr = s_pxServer->EnumServiceProviders(NULL, NULL, NULL, &dwSize, &dwItems, 0);

		if( FAILED(hr) && hr != DPNERR_BUFFERTOOSMALL)
		{
			Asura_Assert(false, "failed to count SPs");
		}
		else
		{
			pdnSPInfo = (DPN_SERVICE_PROVIDER_INFO*) new BYTE[dwSize];
    
			if( FAILED( hr = s_pxServer->EnumServiceProviders(NULL, NULL, pdnSPInfo, &dwSize, &dwItems, 0 ) ) )
			{
				Asura_Assert(false, "failed to list SPs");
			}
			else
			{
				pdnSPInfoEnum = pdnSPInfo;
				for ( u_int i = 0; i < dwItems; i++ )
				{
					//if (pdnSPInfoEnum->dwFlags & DPNSPINFO_NETWORKSIMULATORDEVICE)
					// (MH - 14.08.2003) hmm, that flag doesn't seem to be getting set...
					if (wcsstr(pdnSPInfoEnum->pwszName, L"Network Simulator") != 0)
					{
						xSPGuid = pdnSPInfoEnum->guid;
						break;
					}
					pdnSPInfoEnum++;
				}
			}

			SAFE_DELETE_ARRAY(pdnSPInfo);

			Asura_Assert(xSPGuid != CLSID_DP8SP_TCPIP, "network simulator not available");
		}
	}

    //hr = pDP8AddrLocal->SetSP( s_bUseNetworkSimulator ? &CLSID_NETWORKSIMULATOR_DP8SP_TCPIP : &CLSID_DP8SP_TCPIP );
	hr = pDP8AddrLocal->SetSP( &xSPGuid );
  	if (FAILED(hr)) goto cleanup;

    // Add the port to pDP8AddrLocal, if the port is non-zero.
    // If the port is 0, then DirectPlay will pick a port, 
    // Games will typically hard code the port so the 
    // user need not know it
    if( s_uPort != 0 )
    {
         hr = pDP8AddrLocal->AddComponent( DPNA_KEY_PORT, &s_uPort, sizeof(s_uPort), DPNA_DATATYPE_DWORD );
	 	if (FAILED(hr)) goto cleanup;
	}

    {
        DPN_PLAYER_INFO xPlayerInfo;
        ZeroMemory( &xPlayerInfo, sizeof(xPlayerInfo) );

        xPlayerInfo.dwInfoFlags = DPNINFO_NAME;
        xPlayerInfo.pwszName    = L"Server";

        s_pxServer->SetServerInfo( &xPlayerInfo, NULL, NULL, DPNSETSERVERINFO_SYNC );
    }

	pxSession = Asura_Network::GetSession(0);

	// SNH - 04/08/2003 14:44:23 - the noenums flag stops this server being visible to clients. When the server calls StartGame, 
	//		Platform_StartGame calls SetServerReady (below) which removes this flag.
	DPN_APPLICATION_DESC dpnAppDesc;
    ZeroMemory( &dpnAppDesc, sizeof(DPN_APPLICATION_DESC) );
    dpnAppDesc.dwSize           = sizeof( DPN_APPLICATION_DESC );
    dpnAppDesc.dwFlags          = DPNSESSION_CLIENT_SERVER | DPNSESSION_NOENUMS; 
    dpnAppDesc.guidApplication  = Project_GUID;

    
    dpnAppDesc.pwszSessionName  = SessionName;
	dpnAppDesc.dwMaxPlayers		= Asura_Network::GetMaxNumberOfPlayers();
	
//	if (s_uPasswordHash)
//	{
//		// password is sent as wide string, so encode a sting with the hashed value.
//		// this needs testing to ensure the DirectPlay password comparison doesn't
//		// mess about with the string.
//		u_short* pusPassword = reinterpret_cast<u_short*>(&s_uPasswordHash);
//		u_short ausPassword[3];
//		ausPassword[0] = pusPassword[0];
//		ausPassword[1] = pusPassword[1];
//		ausPassword[2] = 0;
//		dpnAppDesc.pwszPassword	= ausPassword;
//		dpnAppDesc.dwFlags |= DPNSESSION_REQUIREPASSWORD;
//	}

	/// Kevin Lea - 02/10/2002 11:36:16 - Add project session data; we have to cast
	/// away some constness to set the DirectX data structure.
	dpnAppDesc.pvApplicationReservedData = const_cast<void*>(pxSession->GetProjectSessionData());
	dpnAppDesc.dwApplicationReservedDataSize = pxSession->GetProjectSessionDataSize();

    hr = s_pxServer->Host( &dpnAppDesc, &pDP8AddrLocal, 1, NULL, NULL, NULL, 0  );

    Asura_Assertf(SUCCEEDED(hr), ("Error hosting: 0x%lx", hr));
  
cleanup: 
	
	SAFE_RELEASE(pDP8AddrLocal);

	return SUCCEEDED(hr);
}

bool Asura_PC_DirectPlay::IsPlayerBanned( const DPNMSG_INDICATE_CONNECT* pxIndicateConnectMsg )
{
    // (MP - 05.09.2003) TODO
    return false;
}

HRESULT WINAPI Asura_PC_DirectPlay::ServerMessageHandler( PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer )
{
	switch( dwMessageId )
    {
		case DPN_MSGID_INDICATE_CONNECT:
		// Kevin Lea - 15/06/2001 12:17:27 - someone is trying to connect
		{
			if( Asura_Network::GetNumberOfMachines() >= Asura_Network::GetMaxNumberOfMachines() )
			{
				return DPNERR_HOSTREJECTEDCONNECTION;
			}

            DPNMSG_INDICATE_CONNECT* pxMsg = reinterpret_cast<DPNMSG_INDICATE_CONNECT*>( pMsgBuffer );
	
            if( IsPlayerBanned(pxMsg) )
			{
				return DPNERR_HOSTREJECTEDCONNECTION;
			}
            
            if( !Project_ShouldAcceptNewPlayer(pxMsg) )
			{
				return DPNERR_HOSTREJECTEDCONNECTION;
			}

			if (pxMsg->dwUserConnectDataSize != sizeof(Asura_PC_DirectPlayer_UserConnectData))
			{
				return DPNERR_HOSTREJECTEDCONNECTION;
			}

			Asura_PC_DirectPlayer_UserConnectData* pxUserConnectData = reinterpret_cast
				<Asura_PC_DirectPlayer_UserConnectData*>(pxMsg->pvUserConnectData);

			if (!pxUserConnectData)
			{
				return DPNERR_HOSTREJECTEDCONNECTION;
			}

			if (pxUserConnectData->m_uVersionID != Project_GetVersionID())
			{
				return DPNERR_HOSTREJECTEDCONNECTION;
			}
			
			if (s_uPasswordHash && (pxUserConnectData->m_uPasswordHash != s_uPasswordHash))
			{
				Asura_PC_DirectPlay_UserConnectReplyData* pxReplyData = new Asura_PC_DirectPlay_UserConnectReplyData;
				pxReplyData->m_uResultCode = ASURA_NDR_PASSWORD;
				pxMsg->pvReplyData = pxReplyData;
				pxMsg->dwReplyDataSize = sizeof(Asura_PC_DirectPlay_UserConnectReplyData);
				return DPNERR_HOSTREJECTEDCONNECTION;
			}
			
			return DPN_OK;
		}

		case DPN_MSGID_CREATE_PLAYER:
        {
			// Kevin Lea - 15/06/2001 15:50:47 - add a player and set context valuce
		    HRESULT hr;
            PDPNMSG_CREATE_PLAYER pCreatePlayerMsg;
            pCreatePlayerMsg = (PDPNMSG_CREATE_PLAYER)pMsgBuffer;

            // Get the peer info and extract its name
            DWORD dwSize = 0;
            DPN_PLAYER_INFO* pdpPlayerInfo = NULL;
            hr = s_pxServer->GetClientInfo( pCreatePlayerMsg->dpnidPlayer, pdpPlayerInfo, &dwSize, 0 );
           
			if( FAILED(hr) && hr != DPNERR_BUFFERTOOSMALL )
            {
                if( hr == DPNERR_INVALIDPLAYER )
                {
					#ifdef ASURA_PC_SUPPORT_GCDKEY
					if(!Asura_Network::IsDedicatedServer())
					{
						Asura_PC_DirectPlay_PlayerInfo* playerInfo = &PlayerInfo[0];

						playerInfo->IsValid = true;
						playerInfo->NetworkID = pCreatePlayerMsg->dpnidPlayer;
						playerInfo->Index = 0;
						playerInfo->ClientGuid = ASURA_GUID_SERVER;//questionable what this should be
	
						pCreatePlayerMsg->pvPlayerContext = playerInfo;

						Asura_PC_GCDKey::AddPlayer(0);
					}
					#endif
                    // Ignore this message if this is for the host
                    break;
	            }
            }

			pdpPlayerInfo = (DPN_PLAYER_INFO*) new BYTE[ dwSize ];
            ZeroMemory( pdpPlayerInfo, dwSize );
            pdpPlayerInfo->dwSize = sizeof(DPN_PLAYER_INFO);
            hr = s_pxServer->GetClientInfo( pCreatePlayerMsg->dpnidPlayer, pdpPlayerInfo, &dwSize, 0 );
            
			/// Kevin Lea - 12/08/2002 17:31:16 - eventually machines will say how many players they want locally.
			// (MH - 13.08.2003) this was set to 4, I'm going to set it to 1 and that can change when anyone gets
			// round to split-screen clients.
			Asura_Handle iMachineHandle = Asura_Network::AddMachineToGame(1);

			Asura_Assert(iMachineHandle != ASURA_INVALID_HANDLE, "Too many machines! Should have been stopped before now!");
			
			Asura_Guid clientGuid = Asura_Network::GetNewClientGuid(iMachineHandle);
			
	
			{
				Asura_PC_DirectPlay_PlayerInfo* playerInfo = &PlayerInfo[iMachineHandle];

				playerInfo->IsValid = true;
				playerInfo->NetworkID = pCreatePlayerMsg->dpnidPlayer;
				playerInfo->Index = iMachineHandle;
				playerInfo->ClientGuid = clientGuid;
                
// (MP - 02.08.2002) This Asura_String functionality required the use of a
// Windows specific function. I've removed that and inlined what it did just
// below.
//				playerInfo->Name = pdpPlayerInfo->pwszName;
                
                {
                    playerInfo->Name.MakeNull();

                    if (pdpPlayerInfo->pwszName)
					{
						int iLen = wcslen( pdpPlayerInfo->pwszName );
						if( iLen > 0 )
						{
							Asura_Char* szTmp = new Asura_Char[iLen + 1];
							if( szTmp )
							{
								wsprintf( szTmp, "%ls", pdpPlayerInfo->pwszName );
								playerInfo->Name = szTmp;
								delete[] szTmp;
							}
						}
					}
                }
				

				
				SAFE_DELETE_ARRAY( pdpPlayerInfo );

				// Tell DirectPlay to store this pPlayerInfo 
				// pointer in the pvPlayerContext.
				pCreatePlayerMsg->pvPlayerContext = playerInfo;
			}
#if 1
			/// Kevin Lea - 18/12/2001 17:11:05 - send message to client
			{
				Asura_Message* message = Asura_Network::CreateMessage(ASURA_MSG_VALIDCLIENTGUID,sizeof(Asura_MsgData_ValidClientGuid));

				Asura_MsgData_ValidClientGuid* data = (Asura_MsgData_ValidClientGuid*) message->GetData();

				data->Guid = clientGuid;

				message->To = ASURA_GUID_CLIENT;
				message->UseGuaranteedDelivery();

				{
					DPN_BUFFER_DESC buffer;

					Asura_PC_DirectPlay::PackMessageIntoBuffer(message,buffer);

					DWORD flags = DPNSEND_NOLOOPBACK|DPNSEND_NONSEQUENTIAL;
					//if (message->Guaranteed)
					flags|=DPNSEND_GUARANTEED|DPNSEND_PRIORITY_HIGH;

					DPNHANDLE dummy;

					//HRESULT hr = 
					s_pxServer->SendTo
					(
						pCreatePlayerMsg->dpnidPlayer,
						&buffer, 
						1, // number of buffers
						0, // timeout (ms)	// (MH - 16.09.2003) this used to be 1000ms
						0,
						&dummy,
						flags 
					);

				}
								
				Asura_Network::DestroyMessage(message);
			}

			#ifdef ASURA_PC_SUPPORT_GCDKEY
			Asura_PC_GCDKey::AddPlayer(iMachineHandle);
			#endif
#endif
			break;
		}

		case DPN_MSGID_DESTROY_PLAYER:
		{
			PDPNMSG_DESTROY_PLAYER pxDestroyMachineMsg;

			pxDestroyMachineMsg = (PDPNMSG_DESTROY_PLAYER)pMsgBuffer;

			Asura_PC_DirectPlay_PlayerInfo* pxPlayerInfo = reinterpret_cast<Asura_PC_DirectPlay_PlayerInfo*>( pxDestroyMachineMsg->pvPlayerContext );

			if (pxPlayerInfo)
			{
				#ifdef ASURA_PC_SUPPORT_GCDKEY
				Asura_PC_GCDKey::RemovePlayer(pxPlayerInfo->Index);
				#endif
				
				Asura_Network::RemoveMachineFromGame(pxPlayerInfo->Index);
				pxPlayerInfo->IsValid = false;
			}

			break;
		}

        case DPN_MSGID_TERMINATE_SESSION:
        {
            PDPNMSG_TERMINATE_SESSION pTerminateSessionMsg;
            pTerminateSessionMsg = (PDPNMSG_TERMINATE_SESSION)pMsgBuffer;

            break;
        }

        case DPN_MSGID_RECEIVE:
        {
		//	if (Asura_Network::IsReadyForMessages())
			{
				PDPNMSG_RECEIVE pReceiveMsg;
				pReceiveMsg = (PDPNMSG_RECEIVE)pMsgBuffer;

				BYTE* data = pReceiveMsg->pReceiveData;
				u_int uNumBytes = pReceiveMsg->dwReceiveDataSize;
				bool bWasGuaranteed = (pReceiveMsg->dwReceiveFlags & DPNRECEIVE_GUARANTEED) != 0;
		
				UnpackMessageFromBuffer(data, uNumBytes, bWasGuaranteed);
			}

            return DPN_OK;
        }

		case DPN_MSGID_SEND_COMPLETE:
		{
#if _DEBUG
			// SNH - 30/07/2003 11:06:18 - DirectPlay sends one of these for every time Send is called.
			//		The timed-out hResultCode seems to be a good indication of a dropped connection.
			PDPNMSG_SEND_COMPLETE msg = (PDPNMSG_SEND_COMPLETE)pMsgBuffer;

			if (dbg_bPrintSendToClientTimeouts)
			{
				if(FAILED(msg->hResultCode))
				{
					const char* szError = "unknown";
					switch (msg->hResultCode)
					{
					case DPNERR_CONNECTIONLOST: szError = "connection lost"; break;
					case DPNERR_INVALIDFLAGS: szError = "invalid flags"; break;
					case DPNERR_INVALIDPARAM: szError = "invalid param"; break;
					case DPNERR_INVALIDPLAYER: szError = "invalid player"; break;
					case DPNERR_TIMEDOUT: szError = "timed out"; break;
					}

					Asura_OutputToDebugger(("send message to client failed. reason: %s.\n", szError));
				}
			}

			if (dbg_bPrintSendToClientGuaranteedTimeouts)
			{
				// (MH - 01.09.2003) we set user context to be non-zero iff msg was guaranteed
				if (msg->pvUserContext && (DPNERR_TIMEDOUT == msg->hResultCode))
				{
					Asura_OutputToDebugger(("guaranteed message timed out, connection lost?.\n"));
				}
			}
#endif
			break;
		}

		case DPN_MSGID_RETURN_BUFFER:
		{
			// a buffer we allocated is now being returned.
			const DPNMSG_RETURN_BUFFER* pxReturnBufferData = reinterpret_cast
				<const DPNMSG_RETURN_BUFFER*>(pMsgBuffer);
			delete pxReturnBufferData->pvBuffer;

			break;
		}
    }

    return DPN_OK;
}


// SNH - 04/08/2003 14:43:57 - allow this server to be seen by clients
void Asura_PC_DirectPlay::SetServerReady(bool bReady)
{
	Asura_Assert(Asura_Network::IsServer() && Asura_Network::IsNetworkInitialised(), "Not a valid server");

	DWORD dwSize = 0;
	HRESULT hr = s_pxServer->GetApplicationDesc(NULL, &dwSize, 0);
	if(hr != DPNERR_BUFFERTOOSMALL)
	{
		return;
	}

	DPN_APPLICATION_DESC* pAppDesc = (DPN_APPLICATION_DESC*) new BYTE[dwSize];
	if(!pAppDesc)
		return;

	ZeroMemory(pAppDesc, dwSize);
	pAppDesc->dwSize = sizeof(DPN_APPLICATION_DESC);

	hr = s_pxServer->GetApplicationDesc(pAppDesc, &dwSize, 0);
	if(FAILED(hr))
	{
		delete [] pAppDesc;
		return;
	}

	if(bReady)
	{
		// other members of the app desc will hold their previous values, so no need to set them.
		// remove the no enums flag so this session is visible to clients
		pAppDesc->dwFlags &= ~DPNSESSION_NOENUMS;
	}
	else
	{
		pAppDesc->dwFlags |= DPNSESSION_NOENUMS;
	}

	hr = s_pxServer->SetApplicationDesc(pAppDesc, 0);
	
	// free memory.
	delete [] pAppDesc;
}


//void Asura_PC_DirectPlay::UpdateServerPassword(u_int uPasswordHash)
//{
//	Asura_Assert(Asura_Network::IsServer() && Asura_Network::IsNetworkInitialised(), "Not a valid server");
//
//	DWORD dwSize = 0;
//	HRESULT hr = s_pxServer->GetApplicationDesc(NULL, &dwSize, 0);
//	if(hr != DPNERR_BUFFERTOOSMALL)
//	{
//		return;
//	}
//
//	DPN_APPLICATION_DESC* pAppDesc = (DPN_APPLICATION_DESC*) new BYTE[dwSize];
//	if(!pAppDesc)
//		return;
//
//	ZeroMemory(pAppDesc, dwSize);
//	pAppDesc->dwSize = sizeof(DPN_APPLICATION_DESC);
//
//	hr = s_pxServer->GetApplicationDesc(pAppDesc, &dwSize, 0);
//	if(FAILED(hr))
//	{
//		delete [] pAppDesc;
//		return;
//	}
//
//	if (uPasswordHash)
//	{
//		u_short* pusPassword = reinterpret_cast<u_short*>(&s_uPasswordHash);
//		u_short ausPassword[3];
//		ausPassword[0] = pusPassword[0];
//		ausPassword[1] = pusPassword[1];
//		ausPassword[2] = 0;
//		pAppDesc->pwszPassword	= ausPassword;
//		pAppDesc->dwFlags |= DPNSESSION_REQUIREPASSWORD;
//	}
//	else
//	{
//		pAppDesc->pwszPassword = NULL;
//		pAppDesc->dwFlags &= ~DPNSESSION_REQUIREPASSWORD;
//	}
//
//	hr = s_pxServer->SetApplicationDesc(pAppDesc, 0);
//	
//	// free memory.
//	delete [] pAppDesc;
//
//}









    
//-----------------------------------------------------------------------------
// Name: SendCreatePlayerMsg
// Desc: Send the target player a creation message about the player identified
//       in the APP_PLAYER_INFO struct.
//-----------------------------------------------------------------------------
/*
HRESULT SendCreatePlayerMsg( APP_PLAYER_INFO* pPlayerAbout, DPNID dpnidTarget )
{
    GAMEMSG_CREATE_PLAYER msgCreatePlayer;
    msgCreatePlayer.dwType = GAME_MSGID_CREATE_PLAYER;
    msgCreatePlayer.dpnidPlayer = pPlayerAbout->dpnidPlayer;
    strcpy( msgCreatePlayer.strPlayerName, pPlayerAbout->strPlayerName );

    DPN_BUFFER_DESC bufferDesc;
    bufferDesc.dwBufferSize = sizeof(GAMEMSG_CREATE_PLAYER);
    bufferDesc.pBufferData  = (BYTE*) &msgCreatePlayer;

    // DirectPlay will tell via the message handler 
    // if there are any severe errors, so ignore any errors 
    DPNHANDLE hAsync;
    Asura_PC_DirectPlay::s_pxServer->SendTo( dpnidTarget, &bufferDesc, 1,
                         0, NULL, &hAsync, DPNSEND_NOLOOPBACK );

    return S_OK;
}
*/


//
// Asura_PC_DirectPlay_Server.
//

void Asura_PC_DirectPlay_Server::CreateInstance( Asura_PC_DirectPlay_Server** ppxInstance )
{
    Asura_Assert( !*ppxInstance, "" );

    HRESULT iRes;
    Asura_PC_DirectPlay_Server* pxNew;

    iRes = CoInitialize( NULL );
    if( SUCCEEDED(iRes) )
    {
        pxNew = new Asura_PC_DirectPlay_Server();
        iRes = ( pxNew ? S_OK : -1 );

        if( SUCCEEDED(iRes) )
        {
            iRes = CoCreateInstance( CLSID_DirectPlay8Server, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Server, reinterpret_cast<void**>(&pxNew->m_pxDPServer) );
            if( FAILED(iRes) ) { delete pxNew; }
        }

        if( FAILED(iRes) ) { CoUninitialize(); }
    }

    if( SUCCEEDED(iRes) ) { *ppxInstance = pxNew; }
}

void Asura_PC_DirectPlay_Server::DestroyInstance( Asura_PC_DirectPlay_Server** ppxInstance )
{
    if( !*ppxInstance ) { return; }

    IDirectPlay8Server* const pxDPServer = (*ppxInstance)->m_pxDPServer;
 	pxDPServer->CancelAsyncOperation( 0, DPNCANCEL_ALL_OPERATIONS );
    pxDPServer->Close( 0 );
    pxDPServer->Release();
    
    delete *ppxInstance;
    *ppxInstance = NULL;

    CoUninitialize();
}

HRESULT Asura_PC_DirectPlay_Server::SendTo( const DPNID dpnid,
                                            const DPN_BUFFER_DESC *const prgBufferDesc,
                                            const DWORD cBufferDesc,
                                            const DWORD dwTimeOut,
                                            void *const pvAsyncContext,
                                            DPNHANDLE *const phAsyncHandle,
                                            const DWORD dwFlags )
{
#ifdef ASURA_DIRECTPLAY_MESSAGELOGGING
    if( Asura_PC_DirectPlay::MSG_LOG_LEVEL_NONE != Asura_PC_DirectPlay::GetMsgLogLevel() )
    {
        Asura_PC_DirectPlay::LogMsgInfo( prgBufferDesc );
    }
#endif

    return m_pxDPServer->SendTo( dpnid, prgBufferDesc, cBufferDesc, dwTimeOut, pvAsyncContext, phAsyncHandle, dwFlags );
}
