// EQ2Emulator: Everquest II Server Emulator
// Copyright (C) 2007 EQ2EMulator Development Team
// Licensed under GPL v3 - see <http://www.gnu.org/licenses/>
#ifndef _EQPROTOCOL_H
#define _EQPROTOCOL_H

#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <map>
#include <set>
#include <memory>
#include <cstdint>

// Unix networking headers
#include <netinet/in.h>

// Project headers
#include "EQPacket.h"
#include "Mutex.h"
#include "opcodemgr.h"
#include "misc.h"
#include "Condition.h"
#include "Crypto.h"
#include "zlib.h"
#include "timer.h"

#ifdef WRITE_PACKETS
#include <stdarg.h>
#endif

using namespace std;

// Forward declarations
class OpcodeManager;
class EQStreamFactory;

/**
 * EverQuest stream connection states.
 * Represents the current state of a network stream connection.
 */
typedef enum {
	ESTABLISHED,		// Active connection ready for data
	WAIT_CLOSE,			// Waiting for graceful close
	CLOSING,			// In process of closing
	DISCONNECTING,		// Actively disconnecting
	CLOSED				// Connection fully closed
} EQStreamState;

// Packet flags
#define FLAG_COMPRESSED	0x01		// Packet is compressed
#define FLAG_ENCODED	0x04		// Packet is encoded/encrypted

// Rate limiting and bandwidth constants
#define RATEBASE	1048576			// Base rate: 1 MB
#define DECAYBASE	78642			// Decay rate: RATEBASE/10

// Retransmission timing constants
#ifndef RETRANSMIT_TIMEOUT_MULT
#define RETRANSMIT_TIMEOUT_MULT 3.0	// Timeout multiplier
#endif

#ifndef RETRANSMIT_TIMEOUT_MAX
#define RETRANSMIT_TIMEOUT_MAX 5000	// Maximum retransmit timeout (ms)
#endif

#ifndef AVERAGE_DELTA_MAX
#define AVERAGE_DELTA_MAX 2500		// Maximum average delta (ms)
#endif

#pragma pack(1)

/**
 * Session request packet structure.
 * Sent by client to initiate a new session.
 */
struct SessionRequest {
	uint32 UnknownA;		// Unknown field A
	uint32 Session;			// Requested session ID
	uint32 MaxLength;		// Maximum packet length
};

/**
 * Session response packet structure.
 * Sent by server in response to session request.
 */
struct SessionResponse {
	uint32 Session;			// Assigned session ID
	uint32 Key;				// Encryption/authentication key
	uint8 UnknownA;			// Unknown field A
	uint8 Format;			// Packet format version
	uint8 UnknownB;			// Unknown field B
	uint32 MaxLength;		// Maximum packet length
	uint32 UnknownD;		// Unknown field D
};

/**
 * Client-side session statistics.
 * Deltas are in milliseconds, representing round trip times.
 */
struct ClientSessionStats {
/*000*/	uint16 RequestID;				// Statistics request ID
/*002*/	uint32 last_local_delta;		// Last local round trip time
/*006*/	uint32 average_delta;			// Average round trip time
/*010*/	uint32 low_delta;				// Lowest recorded round trip time
/*014*/	uint32 high_delta;				// Highest recorded round trip time
/*018*/	uint32 last_remote_delta;		// Last remote round trip time
/*022*/	uint64 packets_sent;			// Total packets sent
/*030*/	uint64 packets_recieved;		// Total packets received
/*038*/
};

/**
 * Server-side session statistics.
 * Provides server perspective on connection quality.
 */
struct ServerSessionStats {
	uint16 RequestID;			// Statistics request ID
	uint32 current_time;		// Current server time
	uint32 unknown1;			// Unknown field 1
	uint32 received_packets;	// Packets received by server
	uint32 unknown2;			// Unknown field 2
	uint32 sent_packets;		// Packets sent by server
	uint32 unknown3;			// Unknown field 3
	uint32 sent_packets2;		// Duplicate sent packets count
	uint32 unknown4;			// Unknown field 4
	uint32 received_packets2;	// Duplicate received packets count
};
	
#pragma pack()

// External opcode manager
extern OpcodeManager* EQNetworkOpcodeManager;

/**
 * Types of EverQuest network streams.
 * Each type handles different aspects of the game protocol.
 */
typedef enum {
	UnknownStream = 0,		// Unidentified stream type
	LoginStream,			// Login server authentication
	WorldStream,			// World server communication
	ZoneStream,				// Zone server gameplay
	ChatOrMailStream,		// Combined chat/mail (legacy)
	ChatStream,				// Chat system only
	MailStream,				// Mail system only
	EQ2Stream,				// EverQuest 2 specific stream
} EQStreamType;

/**
 * EverQuest network stream class.
 * Handles reliable UDP communication with sequence numbers, acknowledgments,
 * compression, encryption, and packet combining for EverQuest protocols.
 */
class EQStream {
protected:
	/**
	 * Sequence number ordering enumeration.
	 * Used to determine packet sequence relationships.
	 */
	typedef enum {
		SeqPast,		// Sequence is from the past (duplicate/old)
		SeqInOrder,		// Sequence is the expected next sequence
		SeqFuture		// Sequence is from the future (out of order)
	} SeqOrder;

	// Packet statistics
	uint32 received_packets;		// Total packets received
	uint32 sent_packets;			// Total packets sent
	
	// Remote endpoint information
	uint32 remote_ip;				// Remote IP address
	uint16 remote_port;				// Remote port number
	
	// Packet buffers
	uint8 buffer[8192];				// Main packet buffer
	unsigned char* oversize_buffer;	// Buffer for oversized packets
	uint32 oversize_offset;			// Offset in oversize buffer
	uint32 oversize_length;			// Length of oversize buffer data
	unsigned char* rogue_buffer;	// Buffer for rogue/malformed packets
	uint32 roguebuf_offset;			// Offset in rogue buffer
	uint32 roguebuf_size;			// Size of rogue buffer
	
	// Protocol configuration
	uint8 app_opcode_size;			// Size of application opcodes
	EQStreamType StreamType;		// Type of this stream
	bool compressed;				// Stream supports compression
	bool encoded;					// Stream supports encoding/encryption
	
	// Write buffer for outgoing packets
	unsigned char write_buffer[2048];
	
	// Retransmission timing
	uint32 retransmittimer;			// Current retransmit timer
	uint32 retransmittimeout;		// Retransmit timeout value

	// Session management
	uint16 sessionAttempts;			// Number of session attempts
	uint16 reconnectAttempt;		// Number of reconnect attempts
	bool streamactive;				// Stream is actively connected

	// Session state
	uint32 Session;					// Session ID
	uint32 Key;						// Session encryption key
	uint16 NextInSeq;				// Next expected incoming sequence
	uint16 NextOutSeq;				// Next outgoing sequence number
	uint16 SequencedBase;			// Base sequence for SequencedQueue[0]
	uint32 MaxLen;					// Maximum packet length
	uint16 MaxSends;				// Maximum send attempts
	int8 timeout_delays;			// Number of timeout delays accumulated

	// Thread safety for stream usage
	uint8 active_users;				// Number of active users of this stream
	Mutex MInUse;					// Mutex for usage tracking

#ifdef WRITE_PACKETS
	// Packet logging for debugging
	FILE* write_packets = nullptr;	// File handle for packet dumps
	char GetChar(uchar in);			// Convert byte to printable character
	void WriteToFile(char* pFormat, ...);	// Write formatted data to file
	void WritePackets(const char* opcodeName, uchar* data, int32 size, bool outgoing);
	void WritePackets(EQ2Packet* app, bool outgoing);
	Mutex MWritePackets;			// Mutex for packet writing
#endif

	// Stream connection state
	EQStreamState State;			// Current connection state
	Mutex MState;					// Mutex for state access

	// Timing and general variables
	uint32 LastPacket;				// Timestamp of last packet activity
	Mutex MVarlock;					// General variable lock

	// Combined application packet handling
	EQApplicationPacket* CombinedAppPacket;	// Current combined packet
	Mutex MCombinedAppPacket;		// Mutex for combined packet access

	// Sequence number tracking
	long LastSeqSent;				// Last sequence number sent
	Mutex MLastSeqSent;				// Mutex for last sequence sent
	void SetLastSeqSent(uint32 seq);	// Set last sent sequence number

	// Acknowledgment sequence tracking
	long MaxAckReceived;			// Highest ack sequence received
	long NextAckToSend;				// Next ack sequence to send
	long LastAckSent;				// Last ack sequence sent
	
	// Acknowledgment accessor methods
	long GetMaxAckReceived();
	long GetNextAckToSend();
	long GetLastAckSent();
	void SetMaxAckReceived(uint32 seq);
	void SetNextAckToSend(uint32 seq);
	void SetLastAckSent(uint32 seq);

	Mutex MAcks;					// Mutex for acknowledgment data

	// Outbound packet queues
	queue<EQProtocolPacket*> NonSequencedQueue;		// Non-sequenced packets
	deque<EQProtocolPacket*> SequencedQueue;		// Sequenced packets
	map<uint16, EQProtocolPacket*> OutOfOrderpackets;	// Out-of-order packets
	Mutex MOutboundQueue;							// Mutex for outbound queues

	// Inbound packet queue
	deque<EQApplicationPacket*> InboundQueue;		// Packets waiting processing
	Mutex MInboundQueue;							// Mutex for inbound queue

	// Static configuration
	static uint16 MaxWindowSize;					// Maximum window size for flow control

	// Rate limiting and flow control
	sint32 BytesWritten;							// Bytes written this period
	Mutex MRate;									// Mutex for rate limiting
	sint32 RateThreshold;							// Rate limiting threshold
	sint32 DecayRate;								// Rate decay per time period
	uint32 AverageDelta;							// Average round-trip time

	// Factory reference
	EQStreamFactory* Factory;						// Factory that created this stream

public:
	// EQ2-specific packet combining
	Mutex MCombineQueueLock;			// Mutex for combine queue operations
	bool CheckCombineQueue();			// Check and process combine queue
	deque<EQ2Packet*> combine_queue;	// Queue of packets to combine
	Timer* combine_timer;				// Timer for combine operations

	// Encryption and compression
	Crypto* crypto;						// Cryptographic handler
	int8 EQ2_Compress(EQ2Packet* app, int8 offset = 3);	// Compress EQ2 packet
	z_stream stream;					// zlib compression stream
	uchar* stream_buffer;				// Compression buffer
	int32 stream_buffer_size;			// Size of compression buffer
	bool eq2_compressed;				// Stream uses EQ2 compression
	int8 compressed_offset;				// Offset for compressed data
	
	// Client version management
	int16 client_version;				// Client protocol version
	int16 GetClientVersion() { return client_version; }
	void SetClientVersion(int16 version) { client_version = version; }
	
	// Session attempt management
	void ResetSessionAttempts() { reconnectAttempt = 0; }
	bool HasSessionAttempts() { return reconnectAttempt > 0; }
	
	// Constructors
	EQStream() {
		init();
		remote_ip = 0;
		remote_port = 0;
		State = CLOSED;
		StreamType = UnknownStream;
		compressed = true;
		encoded = false;
		app_opcode_size = 2;
	}
	
	EQStream(sockaddr_in addr);
	// Destructor
	virtual ~EQStream() {
		// Close stream safely
		MOutboundQueue.lock();
		SetState(CLOSED);
		MOutboundQueue.unlock();
		
		// Clean up data structures
		RemoveData();
		
		// Clean up allocated resources
		safe_delete(crypto);
		safe_delete(combine_timer);
		safe_delete(resend_que_timer);
		safe_delete_array(oversize_buffer);
		safe_delete_array(rogue_buffer);
		
		// Clean up combine queue
		MCombineQueueLock.lock();
		for (auto cmb = combine_queue.begin(); cmb != combine_queue.end(); ++cmb) {
			safe_delete(*cmb);
		}
		MCombineQueueLock.unlock();
		
		// Clean up compression stream
		deflateEnd(&stream);
		
		// Clean up out-of-order packets
		for (auto oop = OutOfOrderpackets.begin(); oop != OutOfOrderpackets.end(); ++oop) {
			safe_delete(oop->second);
		}
		
#ifdef WRITE_PACKETS
		if (write_packets) {
			fclose(write_packets);
		}
#endif
	}
	// Factory and initialization
	void SetFactory(EQStreamFactory* f) { Factory = f; }
	void init(bool resetSession = true);
	
	// Configuration
	void SetMaxLen(uint32 length) { MaxLen = length; }
	int8 getTimeoutDelays() { return timeout_delays; }
	void addTimeoutDelay() { timeout_delays++; }
	
	// EQ2-specific packet handling
	void EQ2QueuePacket(EQ2Packet* app, bool attempted_combine = false);
	void PreparePacket(EQ2Packet* app, int8 offset = 0);
	void UnPreparePacket(EQ2Packet* app);
	void EncryptPacket(EQ2Packet* app, int8 compress_offset, int8 offset);
	void FlushCombinedPacket();
	
	// General packet transmission
	void SendPacket(EQApplicationPacket* p);
	void QueuePacket(EQProtocolPacket* p);
	void SendPacket(EQProtocolPacket* p);
	vector<EQProtocolPacket*> convert(EQApplicationPacket* p);
	void NonSequencedPush(EQProtocolPacket* p);
	void SequencedPush(EQProtocolPacket* p);

	// Resend queue management
	Mutex MResendQue;					// Mutex for resend queue
	Mutex MCompressData;				// Mutex for compression operations
	deque<EQProtocolPacket*> resend_que;	// Queue of packets needing resend
	void CheckResend(int eq_fd);			// Check and handle packet resends

	// Acknowledgment and writing
	void AckPackets(uint16 seq);			// Acknowledge received packets
	void Write(int eq_fd);					// Write packets to socket

	// Stream state management
	void SetActive(bool val) { streamactive = val; }
	
	// Low-level packet operations
	void WritePacket(int fd, EQProtocolPacket* p);
	void EncryptPacket(uchar* data, int16 size);
	
	// Session management
	uint32 GetKey() { return Key; }
	void SetKey(uint32 k) { Key = k; }
	void SetSession(uint32 s) { Session = s; }
	void SetLastPacketTime(uint32 t) { LastPacket = t; }

	// Packet processing
	void Process(const unsigned char* data, uint32 length);
	void ProcessPacket(EQProtocolPacket* p, EQProtocolPacket* lastp = nullptr);
	
	// Embedded packet handling
	bool ProcessEmbeddedPacket(uchar* pBuffer, uint16 length, int8 opcode = OP_Packet);
	bool HandleEmbeddedPacket(EQProtocolPacket* p, int16 offset = 2, int16 length = 0);

	// Encryption handling
	EQProtocolPacket* ProcessEncryptedPacket(EQProtocolPacket* p);
	EQProtocolPacket* ProcessEncryptedData(uchar* data, int32 size, int16 opcode);

	// Virtual packet dispatch (override in derived classes)
	virtual void DispatchPacket(EQApplicationPacket* p) { p->DumpRaw(); }

	// Session protocol messages
	void SendSessionResponse();
	void SendSessionRequest();
	void SendDisconnect(bool setstate = true);
	void SendAck(uint16 seq);
	void SendOutOfOrderAck(uint16 seq);

	// Connection health checks
	bool CheckTimeout(uint32 now, uint32 timeout = 30) {
		return (LastPacket && (now - LastPacket) > timeout);
	}
	bool Stale(uint32 now, uint32 timeout = 30) {
		return (LastPacket && (now - LastPacket) > timeout);
	}

	// Inbound queue management
	void InboundQueuePush(EQApplicationPacket* p);
	EQApplicationPacket* PopPacket();		// Pop packet from inbound queue
	void InboundQueueClear();

	// Outbound queue management
	void OutboundQueueClear();
	bool HasOutgoingData();
	
	// Key exchange and RSA
	void SendKeyRequest();
	int16 processRSAKey(EQProtocolPacket* p, uint16 subpacket_length = 0);
	
	// Data cleanup
	void RemoveData() {
		InboundQueueClear();
		OutboundQueueClear();
		if (CombinedAppPacket) {
			delete CombinedAppPacket;
			CombinedAppPacket = nullptr;
		}
	}

	// Usage tracking (thread-safe reference counting)
	bool IsInUse() {
		bool flag;
		MInUse.lock();
		flag = (active_users > 0);
		MInUse.unlock();
		return flag;
	}
	
	void PutInUse() {
		MInUse.lock();
		active_users++;
		MInUse.unlock();
	}
	
	void ReleaseFromUse() {
		MInUse.lock();
		if (active_users > 0) {
			active_users--;
		}
		MInUse.unlock();
	}

	// Sequence number utilities
	static SeqOrder CompareSequence(uint16 expected_seq, uint16 seq);

	// State management
	EQStreamState GetState() { return State; }
	void SetState(EQStreamState state) {
		MState.lock();
		State = state;
		MState.unlock();
	}

	// Remote endpoint access
	uint32 GetRemoteIP() { return remote_ip; }
	uint32 GetrIP() { return remote_ip; }		// Legacy alias
	uint16 GetRemotePort() { return remote_port; }
	uint16 GetrPort() { return remote_port; }	// Legacy alias

	// Static packet reading
	static EQProtocolPacket* Read(int eq_fd, sockaddr_in* from);

	// Connection management
	void Close() { SendDisconnect(); }
	bool CheckActive() { return (GetState() == ESTABLISHED); }
	bool CheckClosed() { return GetState() == CLOSED; }
	
	// Stream configuration
	void SetOpcodeSize(uint8 s) { app_opcode_size = s; }
	void SetStreamType(EQStreamType t);
	EQStreamType GetStreamType() const { return StreamType; }

	// Queue processing
	void ProcessQueue();
	EQProtocolPacket* RemoveQueue(uint16 seq);

	// Rate limiting and flow control
	void Decay();
	void AdjustRates(uint32 average_delta);
	
	// Resend timer
	Timer* resend_que_timer;			// Timer for checking resend queue
};

#endif
