/*
**	Command & Conquer Renegade(tm)
**	Copyright 2025 Electronic Arts Inc.
**
**	This program is free software: you can redistribute it and/or modify
**	it under the terms of the GNU General Public License as published by
**	the Free Software Foundation, either version 3 of the License, or
**	(at your option) any later version.
**
**	This program is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**	GNU General Public License for more details.
**
**	You should have received a copy of the GNU General Public License
**	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

//
// Filename:     wwpacket.cpp
// Project:      wwnet
// Author:       Tom Spencer-Smith
// Date:         June 1998
// Description:  Adding and extracting data from byte streams
//
//------------------------------------------------------------------------------------
#include "wwpacket.h"

#include "win.h"
#include "systimer.h"
#include "crc.h"
#include "quat.h"
#include "fromaddress.h"
#include "packettype.h"
#include "bitpackids.h"

#define	PACKET_ID_BITS		28		// Enough for about 100 packets per second for about a month.
#define	PACKET_TYPE_BITS	4		// Enough for 16 packet types (we currently have 7 at 9/20/2001 11:33PM)

DEFINE_AUTO_POOL(cPacket, 256)

//
// Class statics
//
#ifdef WRAPPER_CRC
const USHORT	cPacket::PACKET_HEADER_SIZE	= 7;
#else //WRAPPER_CRC
const int		cPacket::CRC_PLACEHOLDER		= 99999;
const USHORT	cPacket::PACKET_HEADER_SIZE	= 11;
#endif //WRAPPER_CRC
int				cPacket::RefCount					= 0;
bool				cPacket::EncoderInit				= true;
const unsigned long cPacket::DefSendTime		= 0xffffffff;

//------------------------------------------------------------------------------------
cPacket::cPacket() :
   Type(UNDEFINED_TYPE),
   Id(UNDEFINED_ID),
   SenderId(UNDEFINED_ID),
	SendTime(DefSendTime),
	FirstSendTime(DefSendTime),
   ResendCount(-1),			// so that first send doesn't count as a resend
	NumSends(1)
{
	//cEncoderList::Set_Compression_Enabled(false);

	RefCount++;

	if (EncoderInit) {
		Init_Encoder();
	}
}

//---------------- --------------------------------------------------------------------
cPacket::~cPacket()
{
	RefCount--;
}

//------------------------------------------------------------------------------------
//
// Assignment operator
//
cPacket& cPacket::operator=(const cPacket& source)
{
	PFromAddressWrapper	= source.PFromAddressWrapper;
   Type						= source.Type;
   Id							= source.Id;
	SenderId					= source.SenderId;
	SendTime					= source.SendTime;
	FirstSendTime			= source.FirstSendTime;
   ResendCount				= source.ResendCount;
#ifndef WRAPPER_CRC
   IsCrcCorrect			= source.IsCrcCorrect;
#endif //WRAPPER_CRC

	BitStreamClass::operator=(source);

	NumSends					= source.NumSends;

   return * this;
}

//------------------------------------------------------------------------------------
void cPacket::Add_Vector3(Vector3 & v)
{
	WWASSERT(v.Is_Valid());

	Add(v.X);
	Add(v.Y);
	Add(v.Z);
}

//------------------------------------------------------------------------------------
void cPacket::Get_Vector3(Vector3 & v)
{
	Get(v.X);
	Get(v.Y);
	Get(v.Z);

	WWASSERT(v.Is_Valid());
}

//------------------------------------------------------------------------------------
void cPacket::Add_Quaternion(Quaternion & q)
{
	WWASSERT(q.Is_Valid());

	Add(q.X);
	Add(q.Y);
	Add(q.Z);
	Add(q.W);
}

//------------------------------------------------------------------------------------
void cPacket::Get_Quaternion(Quaternion & q)
{
	Get(q.X);
	Get(q.Y);
	Get(q.Z);
	Get(q.W);

	WWASSERT(q.Is_Valid());
}

//------------------------------------------------------------------------------------
void cPacket::Set_Type(BYTE type)
{
   WWASSERT(Type == UNDEFINED_TYPE || Type == type);

   WWASSERT(type != UNDEFINED_TYPE);
   Type = type;
}

//------------------------------------------------------------------------------------
void cPacket::Set_Id(int id)
{
   WWASSERT(id != UNDEFINED_ID);
   Id = id;
}

//------------------------------------------------------------------------------------
void cPacket::Set_Sender_Id(int sender_id)
{
   SenderId = sender_id;
}

//------------------------------------------------------------------------------------
void cPacket::Set_Send_Time()
{
	unsigned long time = TIMEGETTIME();
	if (SendTime == DefSendTime) {
		FirstSendTime = time;
	}
	SendTime = time;
}

//------------------------------------------------------------------------------------
void cPacket::Set_Num_Sends(int num_sends)
{
	WWASSERT(num_sends > 0);
	NumSends = num_sends;
}

/*
//------------------------------------------------------------------------------------
BYTE cPacket::Peek_Message_Type() const
{
	//
	// Note that using Get is the only valid way to read data from a packet!
	//

	cPacket temp_packet;
	temp_packet = *this;
	BYTE message_type;
	temp_packet.Get(message_type);
	temp_packet.Flush();

	return message_type;
}
*/


void cPacket::Init_Encoder(void)
{
	EncoderInit = false;
	cEncoderList::Set_Precision(BITPACK_PACKET_ID, PACKET_ID_BITS);
	cEncoderList::Set_Precision(BITPACK_PACKET_TYPE, PACKET_TYPE_BITS);
}


//------------------------------------------------------------------------------------
void cPacket::Construct_Full_Packet(cPacket & full_packet, cPacket & src_packet)
{
   WWASSERT(
		src_packet.Get_Type() >= PACKETTYPE_FIRST &&
		src_packet.Get_Type() <= PACKETTYPE_LAST);
   WWASSERT(src_packet.Get_Id() != UNDEFINED_ID);

#ifndef WRAPPER_CRC
	full_packet.Add(CRC_PLACEHOLDER);
#endif //WRAPPER_CRC
	full_packet.Add(src_packet.Get_Type(), BITPACK_PACKET_TYPE);
   full_packet.Add(src_packet.Get_Id(), BITPACK_PACKET_ID);
   full_packet.Add((BYTE)src_packet.Get_Sender_Id());
	full_packet.Add((USHORT)src_packet.Get_Bit_Length());

	int header_bit_length = full_packet.Get_Bit_Length();
	WWASSERT(header_bit_length == PACKET_HEADER_SIZE * 8);

	memcpy(
		full_packet.Get_Data() + PACKET_HEADER_SIZE,
		src_packet.Get_Data(),
		src_packet.Get_Compressed_Size_Bytes());
	unsigned int whole_bit_length = header_bit_length + src_packet.Get_Bit_Length();
	full_packet.Set_Bit_Length(whole_bit_length);

	//
	// Compute a CRC for all the data following the CRC placeholder
	//
	//ULONG crc = CRC::Memory(
	//	(BYTE *) (full_packet.Get_Data() + sizeof(CRC_PLACEHOLDER)),
	//	full_packet.Get_Max_Size() - sizeof(CRC_PLACEHOLDER));

	// Only CRC the meaningful data in the buffer - not the other 1300ish bytes as well. ST - 9/19/2001 11:18PM
#ifndef WRAPPER_CRC
	ULONG crc = CRC::Memory((BYTE *) (full_packet.Get_Data() + sizeof(CRC_PLACEHOLDER)), (whole_bit_length / 8) - sizeof(CRC_PLACEHOLDER));

	//
	// Overwrite the crc placeholder with the computed crc.
	//
	cPacket temp_packet;
	temp_packet.Add(crc);

	memcpy(
		full_packet.Get_Data(),
		temp_packet.Get_Data(),
		temp_packet.Get_Compressed_Size_Bytes());
#endif //WRAPPER_CRC
}

//------------------------------------------------------------------------------------
void cPacket::Construct_App_Packet(cPacket & packet, cPacket & full_packet)
{
#ifndef WRAPPER_CRC
   int remote_crc;
#endif //WRAPPER_CRC
	BYTE type;
	int packet_id;
	char sender_id;
	USHORT bit_size;

#ifndef WRAPPER_CRC
	full_packet.Get(remote_crc);
#endif //WRAPPER_CRC
	full_packet.Get(type, BITPACK_PACKET_TYPE);
	full_packet.Get(packet_id, BITPACK_PACKET_ID);
	full_packet.Get(sender_id);
	full_packet.Get(bit_size);

#ifdef WRAPPER_CRC
	packet.Set_Type(type);
	packet.Set_Id(packet_id);
	packet.Set_Sender_Id(sender_id);
	packet.Set_Bit_Length(bit_size);
	packet.PFromAddressWrapper = full_packet.PFromAddressWrapper;
	memcpy(packet.Get_Data(), full_packet.Get_Data() + PACKET_HEADER_SIZE, packet.Get_Compressed_Size_Bytes());

#else //WRAPPER_CRC

	if (((bit_size / 8) + PACKET_HEADER_SIZE) < MAX_BUFFER_SIZE) {

		//
		// Only CRC the meaningful data in the buffer - not the other 1300ish bytes as well. ST - 9/19/2001 11:29PM
		//
		int local_crc = CRC::Memory((BYTE *) (full_packet.Get_Data() + sizeof(CRC_PLACEHOLDER)), ((bit_size / 8) + PACKET_HEADER_SIZE) - sizeof(CRC_PLACEHOLDER));

		if (local_crc == remote_crc) {
			packet.Set_Is_Crc_Correct(true);
			packet.Set_Type(type);
			packet.Set_Id(packet_id);
			packet.Set_Sender_Id(sender_id);
			packet.Set_Bit_Length(bit_size);
			packet.PFromAddressWrapper = full_packet.PFromAddressWrapper;

			memcpy(packet.Get_Data(), full_packet.Get_Data() + PACKET_HEADER_SIZE, packet.Get_Compressed_Size_Bytes());
		} else {
			packet.Set_Is_Crc_Correct(false);
		}
	} else {
		packet.Set_Is_Crc_Correct(false);
	}

#endif //WRAPPER_CRC
}













	//ExecuteTime(0),
	//ReturnCode(0),
   //ExecuteTime				= source.ExecuteTime;
   //ReturnCode				= source.ReturnCode;

//------------------------------------------------------------------------------------
/*
void cPacket::Set_Execute_Time(int execute_time)
{
   WWASSERT(execute_time > 0);
   ExecuteTime = execute_time;
}
*/


   /*
   if (!Is_Flushed()) {
		WWDEBUG_SAY(("*** cPacket::~cPacket: !Is_Flushed()\n"));
      DIE;
   }
	*/