//
// Asura_Platform_NetTransport_System.cpp
//
// PC version. 
//
// Created by MH - 19.07.2004
//
// Copyright (C) 2003 Rebellion, All Rights Reserved.
//

#include "Core/Asura.h"

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

#ifdef ASURA_SUPPORT_EXTERNAL_NETWORK

// Asura includes
#include "Core/Asura_Timers.h"
#include "Debugging/Asura_Assert.h"
#include "Debugging/Asura_Logfile.h"
#include "Network/Asura_LanGameFinder.h"
#include "Network/Asura_Network.h"
#include "Network/Asura_NetConnection.h"
#include "Network/Asura_NetSocket.h"
#include "Network/Asura_NetSocket_BSD.h"
#include "Network/Asura_NetTransport_System.h"

// Asura PC
#ifdef ASURA_PC_SUPPORT_STEAMWORKS
#include "Network/Steamworks/Asura_PC_SteamworksClient.h"
#include "Network/Steamworks/Asura_PC_SteamworksServer.h"
#include "Network/Steamworks/Asura_PC_NetSocketSteamworks.h"
#include "Network/Steamworks/Asura_PC_Steamworks.h"
#endif

// library includes
#include <winsock.h>

#if 0
#ifdef ASURA_PC_SUPPORT_STEAMWORKS
void RejectAsuraConnection ( const u_int uIP, const unsigned short usPort, const u_int uRejectReason )
{
	if( uIP == Asura_PC_Steamworks::GetLoopbackAddress() )
	{
		return;
	}

	Asura_NetAddress xAddress( uIP );

	const Asura_NetSocket* pxSocket = Asura_NetTransport_System::GetSocket();
	if( !pxSocket )
	{
		Asura_Assert( false, "Failed to find socket" );
		return;
	}
	Asura_NetConnection* pxConnection = pxSocket->FindConnection( xAddress, usPort );

	if( !pxConnection )
	{
		Asura_Assertf( false, ( "Failed to find net connection for address %s", Asura_NetTransport_System::GetStringFromAddress( xAddress, usPort ) ) );
		return;
	}

	Asura_Network_ConnectionRejectedData xRejectionReason;
	xRejectionReason.m_uNBOReason = ASURA_NTS_CHANGE_BYTE_ORDER_RETVAL( uRejectReason );
	pxConnection->Reject( reinterpret_cast<const char*>(&xRejectionReason), sizeof(xRejectionReason) );

	Asura_OutputToDebugger_Retail( ("connection from %s rejected\n", Asura_NetTransport_System::GetStringFromAddress( xAddress, usPort ), NULL) );
}


void AcceptAsuraConnection ( const u_int uIP, const unsigned short usPort )
{
	if( uIP == Asura_PC_Steamworks::GetLoopbackAddress() )
	{
		return;
	}

	Asura_NetAddress xAddress( uIP );

	const Asura_NetSocket* pxSocket = Asura_NetTransport_System::GetSocket();
	if( !pxSocket )
	{
		Asura_Assert( false, "Failed to find socket" );
		return;
	}
	Asura_NetConnection* pxConnection = pxSocket->FindConnection( xAddress, usPort );

	if( !pxConnection )
	{
		Asura_Assertf( false, ( "Faild to find net connection for address %s", Asura_NetTransport_System::GetStringFromAddress( xAddress, usPort ) ) );
		return;
	}

	// Grab the saved message data from this client connection attempt
	char* pcMessage = pxConnection->GetClientRequestData();

	if( !pcMessage )
	{
		Asura_Assert( false, "Failed to get client request data (which should have been saved)" );
		return;
	}

	const Asura_Network_ConnectData* pxConnectData = reinterpret_cast<const Asura_Network_ConnectData*>( pcMessage );
	const void* pExtraConnectData = pxConnectData + 1;

	// TODO: work out latency (or get it from Asura_NetTransport_System/wherever )
	const u_int uLatency = 1;

	pxConnection->Accept();
	Asura_NetTransport_System::ProcessMachineConnection( pxConnection, pxConnectData, uLatency, pExtraConnectData);

	Asura_OutputToDebugger_Retail( ("connection from %s accepted\n", Asura_NetTransport_System::GetStringFromAddress( xAddress, usPort ), NULL) );
}
#endif
#endif

void Asura_NetTransport_System::Platform_Initialise()
{
}

void Asura_NetTransport_System::Platform_Update()
{
}

void Asura_NetTransport_System::Platform_Shutdown()
{
}

void Asura_NetTransport_System::Platform_StartServer(bool bInternetGame)
{
	#if 0
	#ifdef ASURA_PC_SUPPORT_STEAMWORKS
	// Register our Accept/Reject functions with the steam server
	Asura_PC_SteamworksServer::RegisterCallback_ClientAccept( AcceptAsuraConnection );
	Asura_PC_SteamworksServer::RegisterCallback_ClientReject( RejectAsuraConnection );
	#endif
	#endif
}

void Asura_NetTransport_System::Platform_StopServer()
{
}

bool Asura_NetTransport_System::Platform_SendEnumHostsBroadcast()
{
	return Asura_LanGameFinder::SendEnumHostsBroadcast();
}

void Asura_NetTransport_System::Platform_ProcessEnumHostsRequest( Asura_NetAddress xAddress, u_short usPort, const char* pcData, u_int uDataLength )
{
	Asura_LanGameFinder::ProcessEnumHostsRequest(xAddress, usPort, pcData, uDataLength);
}

void Asura_NetTransport_System::Platform_SendEnumHostsResponse( Asura_NetAddress xAddress, u_short usPort)
{
	Asura_LanGameFinder::SendEnumHostsResponse(xAddress, usPort);
}

void Asura_NetTransport_System::Platform_ProcessEnumHostsResponse( Asura_NetAddress xAddress, u_short usPort, const char* pcData, int iDataSize )
{
	Asura_LanGameFinder::ProcessEnumHostsResponse(xAddress, usPort, pcData, iDataSize);
}

void Asura_NetTransport_System::Platform_Client_ClientConnected(Asura_NetConnection* pxConnection)
{
	// KOR - This empty function was originally used for initiating the peer-to-peer voice message
	// exchange, which was moved to the Platform_StartGame (see below) to stop it overflowing during load.
	// It may come in useful later or on other platforms though.
}

void Asura_NetTransport_System::Platform_Client_ClientDisconnected(Asura_NetConnection* pxConnection)
{
	// Do nothing
}

void Asura_NetTransport_System::Platform_StartGame()
{
}

bool Asura_NetTransport_System::Platform_HandleMessage( Asura_NetAddress xAddress, u_short usPort, const char* pcMessage, int iLength)
{
	return false;
}

u_int Asura_NetTransport_System::Platform_GetNetAdaptorIP( int iAdapter ) 
{ 	
	char ac[80];
	if (gethostname(ac, sizeof(ac)) == SOCKET_ERROR)
	{
		Asura_Assertf(false, ("WINSOCK : Error (%d) retriving the Local Host Name",  WSAGetLastError()));
		return 0;
	}
	Asura_OutputToDebugger(("WINSOCK : Local Host Name : \"%s\"\n", ac));

	struct hostent *phe = gethostbyname(ac);

    if (phe == 0) 
	{
		Asura_Assertf(false, ("WINSOCK : Error (%d) in Host Name Lookup",  WSAGetLastError()));
		return 0;
	}
	
	Asura_OutputToDebugger(("WINSOCK : Known IP Addresses :\n"));
		
	in_addr addr;
        
    for (int i = 0; phe->h_addr_list[i] != 0; ++i) 
	{
        in_addr temp;

        memcpy(&temp, phe->h_addr_list[i], sizeof(temp));

        Asura_OutputToDebugger(("- Adapter [%d] : IP %s\n", i, inet_ntoa(temp)));

		if (i == iAdapter)
			addr = temp;
    }
	Asura_OutputToDebugger(("WINSOCK : Using Adapter [%d] : IP %s\n", iAdapter, inet_ntoa(addr)));

	return addr.s_addr;
}

const char* Asura_NetTransport_System::Platform_GetStringFromAddress(Asura_NetAddress xAddress, unsigned short usPort)
{
	#ifdef ASURA_PC_SUPPORT_STEAMWORKS
	if( Asura_PC_Steamworks::IsSteamworksEnabled() )
	{
		return Asura_PC_NetSocketSteamworks::GetStringFromAddress( xAddress, usPort );
	}
	else
	#endif
	{
		return Asura_NetSocket_BSD::GetStringFromAddress( xAddress.m_uAddress, usPort );
	}
}

void Asura_NetTransport_System::Platform_GetAddressFromString(const char* szAddress, Asura_NetAddress* pxAddress, unsigned short* pusPort)
{
	#ifdef ASURA_PC_SUPPORT_STEAMWORKS
	if( Asura_PC_Steamworks::IsSteamworksEnabled() )
	{
		Asura_PC_NetSocketSteamworks::GetAddressFromString( szAddress, pxAddress, pusPort );
	}
	else
	#endif
	{
		Asura_NetSocket_BSD::GetAddressFromString( szAddress, pxAddress ? &pxAddress->m_uAddress : 0, pusPort );
	}
}

Asura_NetSocket* Asura_NetTransport_System::Platform_AllocateNetSocket( u_int uMaxMachines )
{
	#ifdef ASURA_PC_SUPPORT_STEAMWORKS
	if( Asura_PC_Steamworks::IsSteamworksEnabled() )
	{
		return new Asura_PC_NetSocketSteamworks( uMaxMachines );
	}
	else
	#endif
	{
		return new Asura_NetSocket_BSD( uMaxMachines );
	}
}

bool Asura_Network_SessionInfo::Platform_IsSameHost(Asura_Network_SessionInfo* pxSession)
{
	return ((m_xHostAddr == pxSession->m_xHostAddr) && (m_usHostPort == pxSession->m_usHostPort));
}

#endif //#ifdef ASURA_SUPPORT_EXTERNAL_NETWORK
