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

#include <queue>
#include <map>
#include <string>
#include <memory>

#include "../common/EQStream.h"
#include "../common/Condition.h"
#include "../common/opcodemgr.h"
#include "../common/timer.h"

#define STREAM_TIMEOUT 45000 // Stream timeout in milliseconds

/**
 * Factory class for creating and managing EverQuest network streams.
 * Handles UDP socket communication, stream lifecycle, and packet processing
 * for both login and world server connections.
 */
class EQStreamFactory {
private:
	// Network socket and configuration
	int sock; // UDP socket file descriptor
	int Port; // Port number to listen on
	
	// Thread management flags and mutexes
	bool ReaderRunning;				// Reader thread active flag
	Mutex MReaderRunning;			// Mutex for reader thread flag
	bool WriterRunning;				// Writer thread active flag
	Mutex MWriterRunning;			// Mutex for writer thread flag
	bool CombinePacketRunning;		// Packet combiner thread active flag
	Mutex MCombinePacketRunning;	// Mutex for combiner thread flag
	
	// Thread synchronization
	Condition WriterWork; // Condition variable for writer thread
	
	// Stream management
	EQStreamType StreamType;					// Type of streams this factory creates
	std::queue<EQStream*> NewStreams;			// Queue of new streams waiting for processing
	Mutex MNewStreams;							// Mutex for new streams queue
	std::map<std::string, EQStream*> Streams;	// Active streams mapped by address:port
	Mutex MStreams;								// Mutex for streams map
	
	// Cleanup timer
	Timer* DecayTimer; // Timer for periodic cleanup operations

public:
	// Network configuration
	char* listen_ip_address; // IP address to bind to (nullptr = any)
	
	// Stream lifecycle management
	void CheckTimeout(bool remove_all = false);
	
	// Constructors and destructor
	EQStreamFactory(EQStreamType type) {
		ReaderRunning = false;
		WriterRunning = false;
		CombinePacketRunning = false;
		StreamType = type;
		sock = -1;
		Port = 0;
		listen_ip_address = nullptr;
		DecayTimer = nullptr;
	}
	
	EQStreamFactory(EQStreamType type, int port);
	
	~EQStreamFactory() {
		safe_delete_array(listen_ip_address);
	}
	
	// Stream queue management
	EQStream* Pop();			// Get next new stream from queue
	void Push(EQStream* s);		// Add new stream to queue
	
	// Network operations
	bool loadPublicKey();	// Load encryption keys (if needed)
	bool Open();			// Open socket and start threads
	bool Open(unsigned long port) {
		Port = port;
		return Open();
	}
	void Close(); 			// Close socket and stop threads
	
	// Main thread loops
	void ReaderLoop();			// Main packet reading loop
	void WriterLoop();			// Main packet writing loop
	void CombinePacketLoop();	// Packet combining optimization loop
	
	// Thread control
	void Stop() {
		StopReader();
		StopWriter();
		StopCombinePacket();
	}
	
	void StopReader() {
		MReaderRunning.lock();
		ReaderRunning = false;
		MReaderRunning.unlock();
	}
	
	void StopWriter() {
		MWriterRunning.lock();
		WriterRunning = false;
		MWriterRunning.unlock();
		WriterWork.Signal();
	}
	
	void StopCombinePacket() {
		MCombinePacketRunning.lock();
		CombinePacketRunning = false;
		MCombinePacketRunning.unlock();
	}
	
	void SignalWriter() {
		WriterWork.Signal();
	}
};

#endif
