/*'----------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------
'- Raknet wrapper for BlitzMax. This wrapper was originally developped by Kurix for       -
'- Blitz3D, adapted to RakNet 3 and BlitzMax by RepeatUntil.                              -
'- This wrapper is open source, and could be modified by anyone who would like to         -
'- improve it. This is a project who should benefit the whole Blitz community, so please  -
'- send all improvements to repeatuntil@free.fr (to upload on a web site).                -
'------------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------
'----------------------------------------------------------------------------------------*/


#include "Source/RakPeerInterface.h"
#include "Source/MessageIdentifiers.h"
#include "Source/RakNetworkFactory.h"
#include "Source/RakNetStatistics.h"
#include "Source/BitStream.h"
#include "Source/GetTime.h"
#include "Source/NatPunchthrough.h"

#define RN_API extern "C" __declspec(dllexport)

using namespace RakNet;



/*
RN_API void _stdcall RN_RakVoiceInit(RakVoice* rakVoice, bool sampleTypeIsShort, int speexSampleRate, int bufferSizeBytes)
{
	rakVoice->Init(sampleTypeIsShort, speexSampleRate, bufferSizeBytes);
}
*/


RN_API void _stdcall RN_RegisterAsRemoteProcedureCall(RakPeerInterface *rakPeerInterface, char* uniqueID, void ( *functionPointer ) ( RPCParameters *rpcParms ) )
{
	rakPeerInterface->RegisterAsRemoteProcedureCall(uniqueID, functionPointer);
}

/*
RN_API bool _stdcall RN_RPC(RakPeerInterface *rakPeerInterface, char* uniqueID, char *data, int bitLength, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddress playerId, bool broadcast, bool shiftTimestamp, NetworkID networkID, RakNet::BitStream *replyFromTarget )
{
	rakPeerInterface->RPC(uniqueID, data, bitLength, PacketPriority(priority),PacketReliability(reliability),orderingChannel, playerId, broadcast, shiftTimestamp, networkID,replyFromTarget );
}
*/


/******************************************/
/* MISC FUNCTIONS */
/******************************************/
RN_API long _stdcall RN_GetUNASSIGNED_SYSTEM_ADDRESS()
{
	return long(&UNASSIGNED_SYSTEM_ADDRESS);
}

RN_API long _stdcall RN_GetUNASSIGNED_NETWORK_ID()
{
	return long(&UNASSIGNED_NETWORK_ID);
}

RN_API long _stdcall RN_GetTime()
{
	return GetTime();
}


/* INITIALIZE THE RAKNET PEER INTERFACE */
RN_API RakPeerInterface* _stdcall RN_GetRakPeerInterface()
{
	RakPeerInterface *rakPeerInterface;
	rakPeerInterface=RakNetworkFactory::GetRakPeerInterface();

	return rakPeerInterface;
}


/* DESTROY THE RAKNET PEER INTERFACE */
RN_API int _stdcall RN_DestroyRakPeerInterface(RakPeerInterface *rakPeerInterface)
{
if (rakPeerInterface)
	RakNetworkFactory::DestroyRakPeerInterface(rakPeerInterface);

return 0;
}


/******************/
/* PEER FUNCTIONS */
/******************/

// localPort = 0 -> client
// localPort > 0 -> server
RN_API bool _stdcall RN_Startup(RakPeerInterface *rakPeerInterface, int maxConnections, int _threadSleepTimer, int localPort)
{
	if (rakPeerInterface) {
       SocketDescriptor socketDescriptor(localPort,0); 
       return rakPeerInterface->Startup(maxConnections, _threadSleepTimer, &socketDescriptor, 1);
	} else
		return 0;
}


RN_API void _stdcall RN_InitializeSecurity(RakPeerInterface *rakPeerInterface, char *pubKeyE, char *pubKeyN, char *privKeyP, char *privKeyQ)
{
	rakPeerInterface->InitializeSecurity(pubKeyE, pubKeyN, privKeyP, privKeyQ);
}


RN_API void _stdcall RN_DisableSecurity(RakPeerInterface *rakPeerInterface)
{
	rakPeerInterface->DisableSecurity();
}


RN_API void _stdcall RN_SetMaximumIncomingConnections(RakPeerInterface *rakPeerInterface, int numberAllowed) 
{
	rakPeerInterface->SetMaximumIncomingConnections(numberAllowed);
}


RN_API int _stdcall RN_GetMaximumIncomingConnections(RakPeerInterface *rakPeerInterface)
{
	return rakPeerInterface->GetMaximumIncomingConnections();
}


RN_API void _stdcall RN_SetIncomingPassword(RakPeerInterface *rakPeerInterface, char* passwordData, int passwordDataLength)
{
	rakPeerInterface->SetIncomingPassword(passwordData, passwordDataLength);
}


RN_API void _stdcall RN_GetIncomingPassword(RakPeerInterface *rakPeerInterface, char* passwordData, int *passwordDataLength)
{
	rakPeerInterface->GetIncomingPassword(passwordData, passwordDataLength);
}


RN_API bool _stdcall RN_Connect(RakPeerInterface *rakPeerInterface, char* host, int remotePort, char* passwordData, int passwordDataLength)
{
	return rakPeerInterface->Connect(host, remotePort, passwordData, passwordDataLength);
}


RN_API void _stdcall RN_Shutdown(RakPeerInterface *rakPeerInterface, int blockDuration)
{
	rakPeerInterface->Shutdown(blockDuration);
}


RN_API void _stdcall RN_SetTimeoutTime(RakPeerInterface *rakPeerInterface, int timeMS, SystemAddress target)
{
	rakPeerInterface->SetTimeoutTime(timeMS, target);
}


RN_API bool _stdcall RN_IsActive(RakPeerInterface *rakPeerInterface)
{
	return rakPeerInterface->IsActive();
}


RN_API bool _stdcall RN_GetConnectionList(RakPeerInterface *rakPeerInterface, SystemAddress *remoteSystems, unsigned short *numberOfSystems) 
{
	return rakPeerInterface->GetConnectionList(remoteSystems, numberOfSystems);
}


RN_API bool _stdcall RN_Send(RakPeerInterface *rakPeerInterface,char *data,long length,int priority,int reliability,int orderingChannel,SystemAddress *playerID,bool broadcast)
{
return rakPeerInterface->Send(data,length,PacketPriority(priority),PacketReliability(reliability),orderingChannel,*playerID,broadcast);
}


RN_API bool _stdcall RN_SendBitStream(RakPeerInterface *rakPeerInterface,RakNet::BitStream *bitStream,int priority,int reliability,int orderingChannel,SystemAddress *playerID,bool broadcast)
{
	return rakPeerInterface->Send(bitStream,PacketPriority(priority),PacketReliability(reliability),orderingChannel,*playerID,broadcast);
}


RN_API Packet* _stdcall RN_Receive(RakPeerInterface *rakPeerInterface)
{
     return rakPeerInterface->Receive();
}


RN_API bool _stdcall RN_DeallocatePacket(RakPeerInterface *rakPeerInterface,Packet *packet)
{
	// FREE PACKET IF EXISTS
	if (packet) 
		rakPeerInterface->DeallocatePacket(packet);
	return 0;
}


RN_API int _stdcall RN_GetMaximumNumberOfPeers(RakPeerInterface *rakPeerInterface) 
{
	return rakPeerInterface->GetMaximumNumberOfPeers();
}


RN_API void _stdcall RN_CloseConnection(RakPeerInterface *rakPeerInterface, SystemAddress target, bool sendDisconnectionNotification)
{
	rakPeerInterface->CloseConnection(target, sendDisconnectionNotification);
}

// modifyed --- Kevin Poole ---
SystemAddress Internaladdr;
RN_API SystemAddress * _stdcall RN_GetInternalID(RakPeerInterface *rakPeerInterface) 
{
    Internaladdr = rakPeerInterface->GetInternalID();
	return &Internaladdr;
	
    //return &rakPeerInterface->GetInternalID();
}

// modifyed --- Kevin Poole ---
SystemAddress Externaladdr;
RN_API SystemAddress * _stdcall RN_GetExternalID(RakPeerInterface *rakPeerInterface, SystemAddress target) 
{
    Externaladdr = rakPeerInterface->GetExternalID(target);
	return &Externaladdr;
	
    //return &rakPeerInterface->GetExternalID(target);
}


RN_API void _stdcall RN_PushBackPacket(RakPeerInterface *rakPeerInterface,Packet *packet,bool pushAtHead)
{
	rakPeerInterface->PushBackPacket(packet,pushAtHead);
}


RN_API void _stdcall RN_ApplyNetworkSimulator(RakPeerInterface *rakPeerInterface,double maxSendBPS, int minExtraPing, int extraPingVariance) 
{
	rakPeerInterface->ApplyNetworkSimulator(maxSendBPS, minExtraPing, extraPingVariance);
}


RN_API bool _stdcall RN_IsNetworkSimulatorActive(RakPeerInterface *rakPeerInterface)
{
	return rakPeerInterface->IsNetworkSimulatorActive();
}


RN_API void _stdcall RN_PingPlayer(RakPeerInterface *rakPeerInterface,SystemAddress *playerID)
{
	rakPeerInterface->Ping(*playerID);
}


RN_API void _stdcall RN_PingHost(RakPeerInterface *rakPeerInterface, char* host, int remotePort, bool onlyReplyOnAcceptingConnections)
{
	rakPeerInterface->Ping(host, remotePort, onlyReplyOnAcceptingConnections);
}


RN_API int _stdcall RN_GetAveragePing(RakPeerInterface *rakPeerInterface,SystemAddress *playerID)
{
	return rakPeerInterface->GetAveragePing(*playerID);
}


RN_API int _stdcall RN_GetLastPing(RakPeerInterface *rakPeerInterface,SystemAddress *playerID)
{
	return rakPeerInterface->GetLastPing(*playerID);
}


RN_API int _stdcall RN_GetLowestPing(RakPeerInterface *rakPeerInterface,SystemAddress *playerID)
{
	return rakPeerInterface->GetLowestPing(*playerID);
}


RN_API void _stdcall RN_SetOccasionalPing(RakPeerInterface *rakPeerInterface, bool doPing)
{
	rakPeerInterface->SetOccasionalPing(doPing);
}


RN_API void _stdcall RN_SetOfflinePingResponse(RakPeerInterface *rakPeerInterface,char *data,int length)
{
	rakPeerInterface->SetOfflinePingResponse(data,length);
}


RN_API int _stdcall RN_GetNumberOfAddresses(RakPeerInterface *rakPeerInterface)
{
	return rakPeerInterface->GetNumberOfAddresses();
}


RN_API const char * _stdcall RN_GetLocalIP(RakPeerInterface *rakPeerInterface,int index)
{
	return rakPeerInterface->GetLocalIP(index);
}

RN_API int _stdcall RN_GetIndexFromSystemAddress(RakPeerInterface *rakPeerInterface,SystemAddress *playerID)
{
	return rakPeerInterface->GetIndexFromSystemAddress(*playerID);
}

// modifyed --- Kevin Poole ---
SystemAddress addr;
RN_API SystemAddress *_stdcall RN_GetSystemAddressFromIndex(RakPeerInterface *rakPeerInterface,int index)
{    
    addr = rakPeerInterface->GetSystemAddressFromIndex(index);    
    return &addr;

	//return &rakPeerInterface->GetSystemAddressFromIndex(index);
}


RN_API void _stdcall RN_AddToBanList(RakPeerInterface *rakPeerInterface,char *ip, int milliseconds)
{
	rakPeerInterface->AddToBanList(ip, milliseconds);
}


RN_API void _stdcall RN_RemoveFromBanList(RakPeerInterface *rakPeerInterface,char *ip)
{
	rakPeerInterface->RemoveFromBanList(ip);
}


RN_API void _stdcall RN_ClearBanList(RakPeerInterface *rakPeerInterface)
{
	rakPeerInterface->ClearBanList();
}


RN_API bool _stdcall RN_IsBanned(RakPeerInterface *rakPeerInterface,char *ip)
{
	return rakPeerInterface->IsBanned(ip);
}


RN_API int _stdcall RN_SetMTUSize(RakPeerInterface *rakPeerInterface,int size)
{
	return rakPeerInterface->SetMTUSize(size);
}


RN_API int _stdcall RN_GetMTUSize(RakPeerInterface *rakPeerInterface, SystemAddress target)
{
	return rakPeerInterface->GetMTUSize(target);
}


RN_API void _stdcall RN_AllowConnectionResponseIPMigration(RakPeerInterface *rakPeerInterface,bool allow)
{
	rakPeerInterface->AllowConnectionResponseIPMigration(allow);
}


RN_API void _stdcall RN_AdvertiseSystem(RakPeerInterface *rakPeerInterface,char *host,int remotePort, char *data, int dataLength)
{
	rakPeerInterface->AdvertiseSystem(host,remotePort,data,dataLength);
}


/*
RN_API PluginInterface* _stdcall RN_AttachPluginRakVoice(RakPeerInterface *rakPeerInterface)
{
	RakVoice rakVoice;
	rakPeerInterface->AttachPlugin(&rakVoice);
	return &rakVoice;
}
*/


RN_API void _stdcall RN_DetachPlugin(RakPeerInterface *rakPeerInterface, PluginInterface *messageHandler)
{
	rakPeerInterface->DetachPlugin(messageHandler);
}


RN_API RakNetStatistics * _stdcall RN_ServerGetStatistics(RakPeerInterface *rakPeerInterface,SystemAddress *playerID)
{
	return rakPeerInterface->GetStatistics(*playerID);
}


/********************************************/
/* PACKET ACCESS */
/********************************************/
RN_API unsigned char * _stdcall RN_PacketGetData(Packet *packet)
{
	return (unsigned char *)packet->data;
}

RN_API int _stdcall RN_PacketGetBitSize(Packet *packet)
{
	return packet->bitSize;
}

RN_API SystemAddress * _stdcall RN_PacketGetSystemAddress(Packet *packet)
{
	return &packet->systemAddress;
}

RN_API int _stdcall RN_PacketGetplayerIndex(Packet *packet)
{
	return packet->systemIndex;
}

RN_API int _stdcall RN_PacketGetBinaryAddress(Packet *packet)
{
	return packet->systemAddress.binaryAddress;
}


RN_API int _stdcall RN_PacketGetPort(Packet *packet)
{
	return packet->systemAddress.port;
}

RN_API int _stdcall RN_SystemAddressGetBinaryAddress(SystemAddress *systemAddress)
{
	return systemAddress->binaryAddress;
}

RN_API int _stdcall RN_SystemAddressGetPort(SystemAddress *systemAddress)
{
	return systemAddress->port;
}
/********************************************/
/* BISTREAM FUNCTIONS
/********************************************/
RN_API BitStream * _stdcall RN_BitStreamCreate1(int initialBytesToAllocate)
{
	BitStream *b = new BitStream(initialBytesToAllocate);
	return b;
}

RN_API BitStream * _stdcall RN_BitStreamCreate2(unsigned char *data,int length,bool copydata)
{
	BitStream *b = new BitStream(data,length,copydata);
	return b;
}

RN_API void _stdcall RN_BitStreamReset(BitStream *bitstream)
{
	bitstream->Reset();
}

RN_API void _stdcall RN_BitStreamDestroy(BitStream *bitstream)
{
	delete bitstream;
}

RN_API BitStream * _stdcall RN_BitStreamCreateFromPacket(Packet *packet)
{	
	BitStream *b = new BitStream((unsigned char*)packet->data,packet->length,0);
	return b;
}

// WRITE
RN_API void _stdcall RN_BitStreamWriteBool(BitStream *bitstream,bool input)
{
	bitstream->Write(input);
}

RN_API void _stdcall RN_BitStreamWriteUnsignedChar(BitStream *bitstream,unsigned char input)
{
	bitstream->Write(input);
}

RN_API void _stdcall RN_BitStreamWriteChar(BitStream *bitstream,char input)
{
	bitstream->Write(input);
}

RN_API void _stdcall RN_BitStreamWriteUnsignedShort(BitStream *bitstream,unsigned short input)
{
	bitstream->Write(input);
}

RN_API void _stdcall RN_BitStreamWriteShort(BitStream *bitstream,short input)
{
	bitstream->Write(input);
}

RN_API void _stdcall RN_BitStreamWriteUnsignedInt(BitStream *bitstream,unsigned int input)
{
	bitstream->Write(input);
}

RN_API void _stdcall RN_BitStreamWriteInt(BitStream *bitstream,int input)
{
	bitstream->Write(input);
}

RN_API void _stdcall RN_BitStreamWriteUnsignedLong(BitStream *bitstream,unsigned long input)
{
	bitstream->Write(input);
}

RN_API void _stdcall RN_BitStreamWriteLong(BitStream *bitstream,long input)
{
	bitstream->Write(input);
}

RN_API void _stdcall RN_BitStreamWriteFloat(BitStream *bitstream,float input)
{
	bitstream->Write(input);
}

RN_API void _stdcall RN_BitStreamWriteDouble(BitStream *bitstream,double input)
{
	bitstream->Write(input);
}

RN_API void _stdcall RN_BitStreamWrite(BitStream *bitstream,char *input,int numberOfBytes)
{
	bitstream->Write(input,numberOfBytes);
}

// WriteCompressedCOMPRESSED
RN_API void _stdcall RN_BitStreamWriteCompressedUnsignedChar(BitStream *bitstream,unsigned char input)
{
	bitstream->WriteCompressed(input);
}

RN_API void _stdcall RN_BitStreamWriteCompressedChar(BitStream *bitstream,char input)
{
	bitstream->WriteCompressed(input);
}

RN_API void _stdcall RN_BitStreamWriteCompressedUnsignedShort(BitStream *bitstream,unsigned short input)
{
	bitstream->WriteCompressed(input);
}

RN_API void _stdcall RN_BitStreamWriteCompressedShort(BitStream *bitstream,short input)
{
	bitstream->WriteCompressed(input);
}

RN_API void _stdcall RN_BitStreamWriteCompressedUnsignedInt(BitStream *bitstream,unsigned int input)
{
	bitstream->WriteCompressed(input);
}

RN_API void _stdcall RN_BitStreamWriteCompressedInt(BitStream *bitstream,int input)
{
	bitstream->WriteCompressed(input);
}

RN_API void _stdcall RN_BitStreamWriteCompressedUnsignedLong(BitStream *bitstream,unsigned long input)
{
	bitstream->WriteCompressed(input);
}

RN_API void _stdcall RN_BitStreamWriteCompressedLong(BitStream *bitstream,long input)
{
	bitstream->WriteCompressed(input);
}

RN_API void _stdcall RN_BitStreamWriteCompressedFloat(BitStream *bitstream,float input)
{
	bitstream->WriteCompressed(input);
}

RN_API void _stdcall RN_BitStreamWriteCompressedDouble(BitStream *bitstream,double input)
{
	bitstream->WriteCompressed(input);
}

// Read
RN_API bool _stdcall RN_BitStreamReadBool(BitStream *bitstream)
{
	bool input;
	bitstream->Read(input);
	return input;
}

RN_API int _stdcall RN_BitStreamReadUnsignedChar(BitStream *bitstream)
{
	unsigned char input=0;
	bitstream->Read(input);
	return input;
}

RN_API int _stdcall RN_BitStreamReadChar(BitStream *bitstream)
{
	char input;
	bitstream->Read(input);
	return input;
}

RN_API int _stdcall RN_BitStreamReadUnsignedShort(BitStream *bitstream)
{
	unsigned short input;
	bitstream->Read(input);
	return input;
}

RN_API int _stdcall RN_BitStreamReadShort(BitStream *bitstream)
{
	short input;
	bitstream->Read(input);
	return input;
}

RN_API int _stdcall RN_BitStreamReadUnsignedInt(BitStream *bitstream)
{
	unsigned int input;
	bitstream->Read(input);
	return input;
}

RN_API int _stdcall RN_BitStreamReadInt(BitStream *bitstream)
{
	int input;
	bitstream->Read(input);
	return input;
}

RN_API long _stdcall RN_BitStreamReadUnsignedLong(BitStream *bitstream)
{
	unsigned long input;
	bitstream->Read(input);
	return input;
}

RN_API long _stdcall RN_BitStreamReadLong(BitStream *bitstream)
{
	long input;
	bitstream->Read(input);
	return input;
}

RN_API float _stdcall RN_BitStreamReadFloat(BitStream *bitstream)
{
	float input;
	bitstream->Read(input);
	return input;
}

RN_API double _stdcall RN_BitStreamReadDouble(BitStream *bitstream)
{
	double input;
	bitstream->Read(input);
	return input;
}

RN_API char * _stdcall RN_BitStreamRead(BitStream *bitstream,int numberOfBytes)
{
	char *input = new char[numberOfBytes];
	bitstream->Read(input,numberOfBytes);
	return input;		
}

// ReadCompressed COMPRESSED
RN_API int _stdcall RN_BitStreamReadCompressedUnsignedChar(BitStream *bitstream)
{
	unsigned char input;
	bitstream->ReadCompressed(input);
	return input;
}

RN_API int _stdcall RN_BitStreamReadCompressedChar(BitStream *bitstream)
{
	char input;
	bitstream->ReadCompressed(input);
	return input;
}

RN_API int _stdcall RN_BitStreamReadCompressedUnsignedShort(BitStream *bitstream)
{
	unsigned short input;
	bitstream->ReadCompressed(input);
	return input;
}

RN_API int _stdcall RN_BitStreamReadCompressedShort(BitStream *bitstream)
{
	short input;
	bitstream->ReadCompressed(input);
	return input;
}

RN_API int _stdcall RN_BitStreamReadCompressedUnsignedInt(BitStream *bitstream)
{
	unsigned int input;
	bitstream->ReadCompressed(input);
	return input;
}

RN_API int _stdcall RN_BitStreamReadCompressedInt(BitStream *bitstream)
{
	int input;
	bitstream->ReadCompressed(input);
	return input;
}

RN_API long _stdcall RN_BitStreamReadCompressedUnsignedLong(BitStream *bitstream)
{
	unsigned long input;
	bitstream->ReadCompressed(input);
	return input;
}

RN_API long _stdcall RN_BitStreamReadCompressedLong(BitStream *bitstream)
{
	long input;
	bitstream->ReadCompressed(input);
	return input;
}

RN_API float _stdcall RN_BitStreamReadCompressedFloat(BitStream *bitstream)
{
	float input;
	bitstream->ReadCompressed(input);
	return input;
}

RN_API double _stdcall RN_BitStreamReadCompressedDouble(BitStream *bitstream)
{
	double input;
	bitstream->ReadCompressed(input);
	return input;
}

// MISC
RN_API void _stdcall RN_BitStreamResetReadPointer(BitStream *bitstream)
{
	bitstream->ResetReadPointer();
}

RN_API void _stdcall RN_BitStreamAssertStreamEmpty(BitStream *bitstream)
{
	bitstream->AssertStreamEmpty();
}

RN_API void _stdcall RN_BitStreamPrintBits(BitStream *bitstream)
{
	bitstream->PrintBits();
}

RN_API void _stdcall RN_BitStreamIgnoreBits(BitStream *bitstream,int numberOfBits)
{
	bitstream->IgnoreBits(numberOfBits);
}

RN_API void _stdcall RN_BitStreamSetWriteOffset(BitStream *bitstream,int offset)
{
	bitstream->SetWriteOffset(offset);
}

RN_API int _stdcall RN_BitStreamGetNumberOfBitsUsed(BitStream *bitstream)
{
	return bitstream->GetNumberOfBitsUsed();
}

RN_API int _stdcall RN_BitStreamGetNumberOfBytesUsed(BitStream *bitstream)
{
	return bitstream->GetNumberOfBytesUsed();
}

RN_API int _stdcall RN_BitStreamGetReadOffset(BitStream *bitstream)
{
	return bitstream->GetReadOffset();
}

RN_API int _stdcall RN_BitStreamGetNumberOfUnreadBits(BitStream *bitstream)
{
	return bitstream->GetNumberOfUnreadBits();
}

//RN_API int _stdcall RN_BitStreamCopyData(BitStream *bitstream,char **data)
//{
//	return bitstream->CopyData(data);
//}

RN_API void _stdcall RN_BitStreamSetData(BitStream *bitstream,unsigned char *data)
{
	bitstream->SetData(data);
}

RN_API unsigned char * _stdcall RN_BitStreamGetData(BitStream *bitstream)
{
	return bitstream->GetData();
}

RN_API unsigned char * _stdcall RN_BitStreamGetDataPointer(BitStream *bitstream)
{
	return bitstream->GetData();
}

RN_API void _stdcall RN_BitStreamWriteBits(BitStream *bitstream,unsigned char *input, int numberOfBitsToWrite, bool rightAlignedBits)
{
	bitstream->WriteBits(input,numberOfBitsToWrite,rightAlignedBits);
}

RN_API void _stdcall RN_BitStreamWriteAlignedBytes(BitStream *bitstream,unsigned char *input, int numberOfBytesToWrite)
{
	bitstream->WriteAlignedBytes(input,numberOfBytesToWrite);
}

RN_API unsigned char * _stdcall RN_BitStreamReadAlignedBytes(BitStream *bitstream, int numberOfBytesToRead)
{
	unsigned char * input = new unsigned char[numberOfBytesToRead];
	bitstream->ReadAlignedBytes(input,numberOfBytesToRead);
	return input;
}

RN_API void _stdcall RN_BitStreamAlignWriteToByteBoundary(BitStream *bitstream)
{
	bitstream->AlignWriteToByteBoundary();
}

RN_API void _stdcall RN_BitStreamAlignReadToByteBoundary(BitStream *bitstream)
{
	bitstream->AlignReadToByteBoundary();
}

RN_API unsigned char * _stdcall RN_BitStreamReadBits(BitStream *bitstream,int numberOfBitsToRead, bool alignBitsToRight)
{
	unsigned char *output = new unsigned char[numberOfBitsToRead];
	bitstream->ReadBits(output,numberOfBitsToRead,alignBitsToRight);
	return output;
}

RN_API void _stdcall RN_BitStreamWrite0(BitStream *bitstream)
{
	bitstream->Write0();
}

RN_API void _stdcall RN_BitStreamWrite1(BitStream *bitstream)
{
	bitstream->Write1();
}

RN_API bool _stdcall RN_BitStreamReadBit(BitStream *bitstream)
{
	return bitstream->ReadBit();
}

RN_API void _stdcall RN_BitStreamAssertCopyData(BitStream *bitstream)
{
	bitstream->AssertCopyData();
}

RN_API void _stdcall RN_BitStreamSetNumberOfBitsAllocated(BitStream *bitstream,unsigned int lengthInBits)
{
	bitstream->SetNumberOfBitsAllocated(lengthInBits );
}

/* PRIVATE 
RN_API void _stdcall RN_BitStreamWriteCompressed(BitStream *bitstream,unsigned char *input,int size, bool unsignedData)
{
	bitstream->WriteCompressed(input,size,unsignedData);
}
RN_API unsigned char * void _stdcall RN_BitStreamReadCompressed(BitStream *bitstream,int size, bool unsignedData)
{
	unsigned char *input = new unsigned char[size];
	bitstream->ReadCompressed(input,size,unsignedData);
	return input;
}
*/

/**************************************/
/* STATISTICS STRUCT ACCESS */
/**************************************/
RN_API int _stdcall RN_StatisticsGetmessageSendBuffer(RakNetStatistics *stat,int queue)
{
	return stat->messageSendBuffer[queue];
}

RN_API int _stdcall RN_StatisticsGetmessagesSent(RakNetStatistics *stat,int queue)
{
	return stat->messagesSent[queue];
}

RN_API int _stdcall RN_StatisticsGetmessageDataBitsSent(RakNetStatistics *stat,int queue)
{
	return stat->messageDataBitsSent[queue];
}

RN_API int _stdcall RN_StatisticsGetmessageTotalBitsSent(RakNetStatistics *stat,int queue)
{
	return stat->messageTotalBitsSent[queue];
}

RN_API int _stdcall RN_StatisticsGetpacketsContainingOnlyAcknowlegements(RakNetStatistics *stat)
{
	return stat->packetsContainingOnlyAcknowlegements;
}

RN_API int _stdcall RN_StatisticsGetacknowlegementsSent(RakNetStatistics *stat)
{
	return stat->acknowlegementsSent;
}

RN_API int _stdcall RN_StatisticsGetacknowlegementsPending(RakNetStatistics *stat)
{
	return stat->acknowlegementsPending;
}

RN_API int _stdcall RN_StatisticsGetacknowlegementBitsSent(RakNetStatistics *stat)
{
	return stat->acknowlegementBitsSent;
}

RN_API int _stdcall RN_StatisticsGetpacketsContainingOnlyAcknowlegementsAndResends(RakNetStatistics *stat)
{
	return stat->packetsContainingOnlyAcknowlegementsAndResends;
}

RN_API int _stdcall RN_StatisticsGetmessageResends(RakNetStatistics *stat)
{
	return stat->messageResends;
}

RN_API int _stdcall RN_StatisticsGetmessageDataBitsResent(RakNetStatistics *stat)
{
	return stat->messageDataBitsResent;
}

RN_API int _stdcall RN_StatisticsGetmessagesTotalBitsResent(RakNetStatistics *stat)
{
	return stat->messagesTotalBitsResent;
}

RN_API int _stdcall RN_StatisticsGetmessagesOnResendQueue(RakNetStatistics *stat)
{
	return stat->messagesOnResendQueue;
}

RN_API int _stdcall RN_StatisticsGetnumberOfUnsplitMessages(RakNetStatistics *stat)
{
	return stat->numberOfUnsplitMessages;
}

RN_API int _stdcall RN_StatisticsGetnumberOfSplitMessages(RakNetStatistics *stat)
{
	return stat->numberOfSplitMessages;
}

RN_API int _stdcall RN_StatisticsGettotalSplits(RakNetStatistics *stat)
{
	return stat->totalSplits;
}

RN_API int _stdcall RN_StatisticsGetPacketsSent(RakNetStatistics *stat)
{
	return stat->packetsSent;
}

RN_API int _stdcall RN_StatisticsGetencryptionBitsSent(RakNetStatistics *stat)
{
	return stat->encryptionBitsSent;
}

RN_API int _stdcall RN_StatisticsGetTotalBitsSent(RakNetStatistics *stat)
{
	return stat->totalBitsSent;
}

RN_API int _stdcall RN_StatisticsGetsequencedMessagesOutOfOrder(RakNetStatistics *stat)
{
	return stat->sequencedMessagesOutOfOrder;
}

RN_API int _stdcall RN_StatisticsGetsequencedMessagesInOrder(RakNetStatistics *stat)
{
	return stat->sequencedMessagesInOrder;
}

RN_API int _stdcall RN_StatisticsGetorderedMessagesOutOfOrder(RakNetStatistics *stat)
{
	return stat->orderedMessagesOutOfOrder;
}

RN_API int _stdcall RN_StatisticsGetorderedMessagesInOrder(RakNetStatistics *stat)
{
	return stat->orderedMessagesInOrder;
}

RN_API int _stdcall RN_StatisticsGetPacketsReceived(RakNetStatistics *stat)
{
	return stat->packetsReceived;
}

//RN_API int _stdcall RN_StatisticsGetpacketsWithBadCRCRecieved(RakNetStatistics *stat)
//{
//	return stat->packetsWithBadCRCRecieved;
//}

RN_API int _stdcall RN_StatisticsGetBitsReceived(RakNetStatistics *stat)
{
	return stat->bitsReceived;
}

RN_API int _stdcall RN_StatisticsGetbitsWithBadCRCReceived(RakNetStatistics *stat)
{
	return stat->bitsWithBadCRCReceived;
}

RN_API int _stdcall RN_StatisticsGetacknowlegementsReceived(RakNetStatistics *stat)
{
	return stat->acknowlegementsReceived;
}

RN_API int _stdcall RN_StatisticsGetduplicateAcknowlegementsReceived(RakNetStatistics *stat)
{
	return stat->duplicateAcknowlegementsReceived;
}

RN_API int _stdcall RN_StatisticsGetmessagesReceived(RakNetStatistics *stat)
{
	return stat->messagesReceived;
}

RN_API int _stdcall RN_StatisticsGetinvalidMessagesReceived(RakNetStatistics *stat)
{
	return stat->invalidMessagesReceived;
}

RN_API int _stdcall RN_StatisticsGetduplicateMessagesReceived(RakNetStatistics *stat)
{
	return stat->duplicateMessagesReceived;
}

RN_API int _stdcall RN_StatisticsGetmessagesWaitingForReassembly(RakNetStatistics *stat)
{
	return stat->messagesWaitingForReassembly;
}

RN_API int _stdcall RN_StatisticsGetinternalOutputQueueSize(RakNetStatistics *stat)
{
	return stat->internalOutputQueueSize;
}

// Not any more present in RN 2.52
//RN_API int _stdcall RN_StatisticsGetwindowSize(RakNetStatistics *stat)
//{
//	return stat->windowSize;
//}

/*RN_API int _stdcall RN_StatisticsGetlossySize(RakNetStatistics *stat)
{
	return stat->lossySize;
}*/

RN_API int _stdcall RN_StatisticsGetconnectionStartTime(RakNetStatistics *stat)
{
	return stat->connectionStartTime;
}

