///////////////////////////////////////////////////////////////////////////////
/// @file deNet.hpp
///
/// @brief Destiny3D networking system main header
///
/// @author trajar
///
/// This file is the intellectual property of Novus Delta, LLC.. Usage of the
/// contents of this file is subject to the Destiny3D Member License which
/// can be found at http://www.destiny3d.com.  Any other usage is prohibited.
///
/// This file is distributed "AS IS" without warranty of any kind.  Novus
/// Delta, LLC. does not guarantee the fitness of the contents of this file
/// for any particular purpose.
///
/// Copyright (C) 2001-2003 Novus Delta, LLC. All Rights Reserved.
///
/// <hr>
///                                 Change History
/// <hr>
///
/// @date Jun 2002
/// @author trajar
/// @remarks Creation
///
///////////////////////////////////////////////////////////////////////////////

#ifndef _DENET_HPP
#define _DENET_HPP

#include "deGlobalTypes.hpp"

#if defined(DENET_DLL_EXPORTS) || defined(DESTINY3D_EXPORT_ALL)
#	define DENET_API _declspec(dllexport)
#elif defined(DESTINY3D_STATIC_LINK)
#	define DENET_API
#else
#	define DENET_API _declspec(dllimport)
#endif

// prevents inclusion in Winsock 1.1 structures
#define _WINSOCKAPI_

#pragma warning( disable : 4251 )
#pragma warning( disable : 4786 )

// Include some standard Windows defs
typedef	__int64				INT64;
typedef unsigned char		BYTE;
typedef unsigned long       DWORD;
typedef unsigned short      WORD;
typedef long				HRESULT;
typedef unsigned int		WPARAM;
typedef long				LPARAM;
typedef long				LRESULT;

#define SAFE_DELETE(p)       { if(p) { delete (p);     (p)=NULL; } }
#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p);   (p)=NULL; } }
#define SAFE_RELEASE(p)      { if(p) { (p)->Release(); (p)=NULL; } }

#ifndef	NULL
#define NULL	0
#endif

//-------------------------------------------------
// complie-time flags
//
// - DN_SESSION_TIME_FLOAT
//		+ uses floats when passing session time
//		  < DEFAULT >
//
// - DN_SESSION_TIME_INT64
//		+ uses __int64 when passing session time
//-------------------------------------------------


//-------------------------------------------------
//-------------------------------------------------
#define DN_NONE							0x0000
#define	DN_DEFAULT_PORT					3490
#define DN_INVALID_NETID				(DWORD)(-1)

//-------------------------------------------------
class deConnection;
//-------------------------------------------------

//-------------------------------------------------
// deNetUser typedef
//-------------------------------------------------
typedef DWORD hNetUser;

//-------------------------------------------------
// deNetAddress
//-------------------------------------------------
typedef class DENET_API deNetAddress
{
public:

	deNetAddress(void);
	deNetAddress( DWORD pIP, DWORD pPort, const char * pIPStr, const char * pName );
	~deNetAddress(void);

	const char *		GetAddressIPStr(void)	const	{ return m_strAddress; }
	DWORD				GetAddressIP(void)		const	{ return m_dwAddress; }
	const char *		GetAddressName(void)	const	{ return m_strName; }
	DWORD				GetPort(void)			const	{ return m_dwPort; }

protected:

	DWORD		m_dwPort;
	DWORD		m_dwAddress;
	char		m_strAddress[16];
	char		m_strName[16];

} deNetAddress, *pdeNetAddress;


//-------------------------------------------------
// deConnectionDesc
//-------------------------------------------------
class DENET_API deConnectionDesc
{
public:
	deConnectionDesc(void)
	{
		m_dwFlags			= NULL;
		m_SessionID			= NULL;
		m_hLocalUser		= DN_INVALID_NETID;
		m_hRemoteUser		= DN_INVALID_NETID;
		m_iLocalUserType	= -1;
		m_iRemoteUserType	= -1;
		m_NetVersion		= 0.0f;
	}
	~deConnectionDesc(void) { }

	DWORD			m_dwFlags;
	DWORD			m_SessionID;
	char			m_SessionName[32];
	deNetAddress	m_LocalAddress;
	DWORD			m_hLocalUser;
	int				m_iLocalUserType;
	deNetAddress	m_RemoteAddress;
	DWORD			m_hRemoteUser;
	int				m_iRemoteUserType;
	char			m_AppName[32];
	float			m_NetVersion;
};

//-------------------------------------------------
// deNet errors thrown
//-------------------------------------------------
typedef enum eNetError
{
	CODE_GENERIC_ERROR					= -9999,
	CODE_INVALID_PARAM,
	CODE_UNSUPPORTED_VERSION,
	CODE_WINSOCK_ERROR,
	CODE_TOO_MANY_CONNECTIONS,
	CODE_CONNECTION_REFUSED,
	CODE_INVALID_CONNECTION,
	CODE_MASTER_SERVER_MUST_ASSIGN_NET_ID,
	CODE_UNABLE_TO_CREATE_CONNECTION,
	CODE_RESOURCE_ERROR,
	CODE_NOT_SUPPORTED_BY_OBJECT,
	CODE_INVALID_NET_ID,
	CODE_OK								= 0,

} eNetError;

//-------------------------------------------------
// deConnectionServerTime
//-------------------------------------------------
struct deConnectionServerTime
{
	DWORD			dwFlags;
	WORD			iUpdateID;

#ifdef DN_SESSION_TIME_INT64
	s64				Time;
#else
	float			Time;
#endif
};

//-------------------------------------------------
// deConnectionPing
//-------------------------------------------------
struct deConnectionPing
{
	enum eFlags
	{
		FLAG_KEEPALIVE			= 0x0001,
		FLAG_CONFIRM_NET_ID		= 0x0002,
		FLAG_RETURN_PING		= 0x0004,
	};

	DWORD			dwFlags;
	hNetUser		hNetID;

#ifdef DN_SESSION_TIME_INT64
	s64				fTimeSent;
	s64				fTimeRecieved;
#else
	float			fTimeSent;
	float			fTimeRecieved;
#endif
};

//-------------------------------------------------
// deConnectionDisconnect
//-------------------------------------------------
struct deConnectionDisconnect
{
	enum eReason
	{
		//REASON_UNKNOWN,
		REASON_CONNECT_CLOSED_BY_NETUSER,
		REASON_SERVER_SHUTTING_DOWN,
		REASON_SERVER_ERROR,
	};

	eReason			Reason;
};

//-------------------------------------------------
// deConnectionHandshake
//-------------------------------------------------
struct deConnectionHandshake
{
	hNetUser		hNetID;
	hNetUser		hAssignedID;
	int				iConnectionType;
	int				iUserType;
	bool			bRequestReturnID;
};

//-------------------------------------------------
// deConnectionLost
//-------------------------------------------------
struct deConnectionLost
{
	enum eReason
	{
		//REASON_UNKNOWN,
		REASON_CONN_REMOTE_LOST,
		REASON_CONN_CLOSED,
		REASON_CONN_LOCAL_ERROR,
	};

	deConnection *	pConn;
	eReason			Reason;
};

//-------------------------------------------------
// deConnectionRequest
//-------------------------------------------------
struct deConnectionRequest
{	
	deNetAddress	Address;
	hNetUser		hUserID;
	int				iUserType;
	int				iProviderType;
};

//-------------------------------------------------
// deConnectionReply
//-------------------------------------------------
struct deConnectionReply
{
	enum eReason
	{
		//REASON_UNKNOWN,
		REASON_INVALID_ID,
		REASON_SERVER_FULL,
		REASON_REMOTE_ERROR,
		REASON_LOCAL_ERROR,
		REASON_INVALID_PERMISSIONS
	};

	deNetAddress	ServerAddress;
	int				iServerUserType;
	int				iServerProviderType;
	hNetUser		hServerID;
	hNetUser		hAssignedID;
	bool			bAccepted;
	DWORD			dwReason;
};

//---------------------------------------------------------------------------
// deNet debug funtions
//---------------------------------------------------------------------------
#ifdef	_DEBUG
 // assert includes
 #include	<ASSERT.H>
 #define	deASSERT assert 
 #define	NET_ERROR( a )		deNetDlg( deNetErrorStr( a, __FILE__, __LINE__ ) )
 #define	NET_MSG( a )		deNetDlg( a )
 #define	NET_LOG_START()		deNetLogStart()
 #define	NET_LOG_STOP()		deNetLogStop()
 #define	NET_LOG( a )		deNetLog( a )
 #define	NET_LOG_ERROR( a )	deNetLog( deNetErrorStr( a, __FILE__, __LINE__ ) )
#else
 #define	deASSERT
 #define	NET_ERROR( a )		0L
 #define	NET_MSG( a )		0L
 #define	NET_LOG_START()		0L
 #define	NET_LOG_STOP()		0L
 #define	NET_LOG( a )		0L
 #define	NET_LOG_ERROR( a )	0L
#endif

struct _iobuf;
typedef _iobuf FILE;

const char *	deNetErrorStr( eNetError err, const char * pFile = NULL, int iLine = -1 );
void			deNetDlg( const char * pStr );
void			deNetLog( const char * pStr );
void			deNetLogStart( FILE * pFile = NULL );
void			deNetLogStop( void );
//---------------------------------------------------------------------------


// forward decl
//-------------------------------------------------
class deNetUser;
class deThreadPool;
class deConnection;

//*************************************************************************
//-------------------------------------------------------------------------
// deNet functions
//-------------------------------------------------------------------------
//*************************************************************************

//-------------------------------------------------------------------------
// <function> deNet_SetOnLogHandler( DWORD (* pProcess)( const char * ) )
//-------------------------------------------------------------------------
DENET_API void  deNet_SetOnLogHandler( DWORD (* pProcess)( const char * ) );

//-------------------------------------------------------------------------
// <function> deNet_GetTime
//-------------------------------------------------------------------------
#ifdef DN_SESSION_TIME_INT64
 DENET_API s64 deNet_GetTime( void );
#else
 DENET_API float deNet_GetTime( void );
#endif

//-------------------------------------------------------------------------
// <function> deNet_CreateConnection
//-------------------------------------------------------------------------
DENET_API eNetError deNet_CreateConnection( deConnection ** pOut, int iType, DWORD dwFlags = NULL );

//-------------------------------------------------------------------------
// <function> deNet_SetAppName 
//-------------------------------------------------------------------------
DENET_API eNetError deNet_SetAppName( const char * pName );

//-------------------------------------------------------------------------
// <function> deNet_GetAppName
//-------------------------------------------------------------------------
DENET_API const char * deNet_GetAppName( void );

//-------------------------------------------------------------------------
// <function> deNet_GetVersion
//-------------------------------------------------------------------------
DENET_API DWORD deNet_GetVersion(void);

//-------------------------------------------------------------------------
// <function> deNet_GetPort
//-------------------------------------------------------------------------
DENET_API DWORD	deNet_GetPort(void);

//-------------------------------------------------------------------------
// <function> deNet_GetThreadPool
//-------------------------------------------------------------------------
DENET_API deThreadPool * deNet_GetThreadPool(void);

//-------------------------------------------------------------------------
// <function> deNet_GetMaxConnections
//-------------------------------------------------------------------------
DENET_API DWORD deNet_GetMaxConnections(void);

//-------------------------------------------------------------------------
// <function> deNet_GetMaxConnectionBins
//-------------------------------------------------------------------------
DENET_API WORD deNet_GetMaxConnectionBins(void);

//-------------------------------------------------------------------------
// <function> deNet_Startup
//-------------------------------------------------------------------------
DENET_API eNetError deNet_Startup( DWORD iMaxConnections, DWORD iMaxConnectionBins, DWORD dwPort = DN_DEFAULT_PORT, DWORD dwFlags = NULL );

//-------------------------------------------------------------------------
// <fucntion> deNet_Shutdown
//-------------------------------------------------------------------------
DENET_API eNetError deNet_Shutdown( DWORD dwFlags = NULL );


#endif