/*
**	Command & Conquer Generals Zero Hour(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/>.
*/

#ifndef __GENERALS_H__
#define __GENERALS_H__

#ifdef _WIN32
#include <process.h>
#endif
//#include <wstring.h>
//#include <dictionary.h>
//#include <arraylist.h>
#include "matcher.h"
#include "global.h"

#include <string>
#include <bitset>
#include <vector>
#include <map>
#include <hash_map>
typedef std::vector<bool> MapBitSet;

// =====================================================================
// Users
// =====================================================================

// Here are the states a matcher can be in:
typedef enum
{
    STATUS_INVAL = 0,
    STATUS_INCHANNEL,  // Just entered the channel
    STATUS_WORKING,    // Sent info, needs to be matched
    STATUS_MATCHED,    // Been matched, but is still in the channel
} UserStatus;

class GeneralsUser
{
public:
	GeneralsUser(void);
	UserStatus status;

	int points, minPoints, maxPoints;

	int discons, maxDiscons;

	int country;
	int color;

	bool widened;
	time_t timeToWiden;
	time_t matchStart; // when did we request a match?

	// This is a ping to a designated 3rd-party server who just
	// responds to pings.  The idea is that if the game server is
	// behind a firewall, the client will have a 1000ms ping to it,
	// even though he might be very close.  To combat this, we have
	// clients & servers ping some 3rd-party servers & calculate a
	// pesudo-ping based on the sum of pings server-->3rd-->client.
	std::vector<int> pseudoPing;
	int maxPing;

	unsigned int IP;
	int NAT;

	MapBitSet maps;

	int numPlayers;
};

// =====================================================================
// Matcher class
// =====================================================================

typedef std::map<std::string, GeneralsUser*> UserMap;
typedef std::map<int, UserMap> LadderMap;

class GeneralsMatcher : public MatcherClass
{
public:
	GeneralsMatcher();
	virtual ~GeneralsMatcher()
	{}

	virtual void init(void);
	virtual void checkMatches(void);

	virtual void handleDisconnect( const char *reason );
	virtual void handleRoomMessage( const char *nick, const char *message, MessageType messageType );
	virtual void handlePlayerMessage( const char *nick, const char *message, MessageType messageType );
	virtual void handlePlayerJoined( const char *nick );
	virtual void handlePlayerLeft( const char *nick );
	virtual void handlePlayerChangedNick( const char *oldNick, const char *newNick );
	virtual void handlePlayerEnum( bool success, int gameSpyIndex, const char *nick, int flags );

private:
	LadderMap m_ladders;
	UserMap m_nonLadderUsers1v1;
	UserMap m_nonLadderUsers2v2;
	UserMap m_nonLadderUsers3v3;
	UserMap m_nonLadderUsers4v4;
	UserMap m_nonMatchingUsers;

	double computeMatchFitness(const std::string& i1, const GeneralsUser *u1, const std::string& i2, const GeneralsUser *u2);

	GeneralsUser* findUser(const std::string& who);
	GeneralsUser* findUserInLadder(const std::string& who, int ladderID);
	GeneralsUser* findUserInAnyLadder(const std::string& who);
	GeneralsUser* findNonLadderUser(const std::string& who);
	GeneralsUser* findNonMatchingUser(const std::string& who);

	void addUser(const std::string& who);
	void addUserInLadder(const std::string& who, int ladderID, GeneralsUser *user);
	void addUserInAnyLadder(const std::string& who, GeneralsUser *user);
	void addNonLadderUser(const std::string& who, GeneralsUser *user);
	void addNonMatchingUser(const std::string& who, GeneralsUser *user);

	bool removeUser(const std::string& who);
	GeneralsUser* removeUserInLadder(const std::string& who, int ladderID);
	GeneralsUser* removeUserInAnyLadder(const std::string& who);
	GeneralsUser* removeNonLadderUser(const std::string& who);
	GeneralsUser* removeNonMatchingUser(const std::string& who);

	void checkMatchesInUserMap(UserMap& userMap, int ladderID, int numPlayers, bool showPoolSize);

	void dumpUsers(void);

	void sendMatchInfo(std::string name1, std::string name2, std::string name3, std::string name4,
	                   std::string name5, std::string name6, std::string name7, std::string name8,
	                   GeneralsUser *user1, GeneralsUser *user2, GeneralsUser *user3, GeneralsUser *user4,
	                   GeneralsUser *user5, GeneralsUser *user6, GeneralsUser *user7, GeneralsUser *user8,
	                   int numPlayers, int ladderID);

	// Command handlers for above privmsg commands (offset is the
	// offset for the getToken() past the command token)
	bool handleUserInfo(const char *nick, const std::string& msg);
	bool handleUserWiden(const char *nick);

	// Weights for various matching parameters
	int weightLowPing;
	int weightAvgPoints;
	int totalWeight;

	time_t m_nextPoolSizeAnnouncement;
	int m_secondsBetweenPoolSizeAnnouncements;

	//typedef std::vector<std::string> StringVec;
	//StringVec mapFileList;
}
;

// =====================================================================
// TEST Client Matcher class
// =====================================================================

class GeneralsClientMatcher : public MatcherClass
{
public:
	GeneralsClientMatcher();
	virtual ~GeneralsClientMatcher()
	{}

	virtual void init(void);
	virtual void checkMatches(void);

	virtual void handleDisconnect( const char *reason );
	virtual void handleRoomMessage( const char *nick, const char *message, MessageType messageType );
	virtual void handlePlayerMessage( const char *nick, const char *message, MessageType messageType );
	virtual void handlePlayerJoined( const char *nick );
	virtual void handlePlayerLeft( const char *nick );
	virtual void handlePlayerChangedNick( const char *oldNick, const char *newNick );
	virtual void handlePlayerEnum( bool success, int gameSpyIndex, const char *nick, int flags );

private:
}
;

#endif /* __GENERALS_H__ */

