/*
**	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/>.
*/

////////////////////////////////////////////////////////////////////////////////
//																																						//
//  (c) 2001-2003 Electronic Arts Inc.																				//
//																																						//
////////////////////////////////////////////////////////////////////////////////

// FILE: Upgrade.h ////////////////////////////////////////////////////////////////////////////////
// Author: Colin Day, March 2002
// Desc:   Upgrade system for players
///////////////////////////////////////////////////////////////////////////////////////////////////

#pragma once

#ifndef __UPGRADE_H_
#define __UPGRADE_H_

// USER INCLUDES //////////////////////////////////////////////////////////////////////////////////
#include "Common/AudioEventRTS.h"
#include "Common/INI.h"
#include "Common/Snapshot.h"

// FORWARD REFERENCES /////////////////////////////////////////////////////////////////////////////
class Player;
class UpgradeTemplate;
enum NameKeyType;
class Image;
enum AcademyClassificationType;

//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
enum UpgradeStatusType
{
	UPGRADE_STATUS_INVALID = 0,
	UPGRADE_STATUS_IN_PRODUCTION,
	UPGRADE_STATUS_COMPLETE
};

//The maximum number of upgrades. 
#define UPGRADE_MAX_COUNT 128

typedef BitFlags<UPGRADE_MAX_COUNT>	UpgradeMaskType;

#define MAKE_UPGRADE_MASK(k) UpgradeMaskType(UpgradeMaskType::kInit, (k))
#define MAKE_UPGRADE_MASK2(k,a) UpgradeMaskType(UpgradeMaskType::kInit, (k), (a))
#define MAKE_UPGRADE_MASK3(k,a,b) UpgradeMaskType(UpgradeMaskType::kInit, (k), (a), (b))
#define MAKE_UPGRADE_MASK4(k,a,b,c) UpgradeMaskType(UpgradeMaskType::kInit, (k), (a), (b), (c))
#define MAKE_UPGRADE_MASK5(k,a,b,c,d) UpgradeMaskType(UpgradeMaskType::kInit, (k), (a), (b), (c), (d))

inline Bool TEST_UPGRADE_MASK( const UpgradeMaskType& m, Int index ) 
{ 
	return m.test( index ); 
}

inline Bool TEST_UPGRADE_MASK_ANY( const UpgradeMaskType& m, const UpgradeMaskType& mask ) 
{ 
	return m.anyIntersectionWith( mask );
}

inline Bool TEST_UPGRADE_MASK_MULTI( const UpgradeMaskType& m, const UpgradeMaskType& mustBeSet, const UpgradeMaskType& mustBeClear )
{
	return m.testSetAndClear( mustBeSet, mustBeClear );
}

inline Bool UPGRADE_MASK_ANY_SET( const UpgradeMaskType& m) 
{ 
	return m.any(); 
}

inline void CLEAR_UPGRADE_MASK( UpgradeMaskType& m ) 
{ 
	m.clear(); 
}

inline void SET_ALL_UPGRADE_MASK_BITS( UpgradeMaskType& m )
{
	m.clear( );
	m.flip( );
}

inline void FLIP_UPGRADE_MASK( UpgradeMaskType& m )
{
	m.flip();
}


//-------------------------------------------------------------------------------------------------
/** A single upgrade *INSTANCE* */
//-------------------------------------------------------------------------------------------------
class Upgrade : public MemoryPoolObject,
								public Snapshot
{

	MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( Upgrade, "Upgrade" )

public:

	Upgrade( const UpgradeTemplate *upgradeTemplate );
	// virtual destructor prototypes provided by memory pool object

	/// get the upgrade template for this instance
	const UpgradeTemplate *getTemplate( void ) const { return m_template; }

	// status access
	UpgradeStatusType getStatus( void ) const { return m_status; }						///< get status
	void setStatus( UpgradeStatusType status ) { m_status = status; }		///< set the status

	// friend access methods
	void friend_setNext( Upgrade *next ) { m_next = next; }
	void friend_setPrev( Upgrade *prev ) { m_prev = prev; }
	Upgrade *friend_getNext( void ) { return m_next; }
	Upgrade *friend_getPrev( void ) { return m_prev; }

protected:

	// snapshot methods
	virtual void crc( Xfer *xfer );
	virtual void xfer( Xfer *xfer );
	virtual void loadPostProcess( void );

	const UpgradeTemplate *m_template;	///< template this upgrade instance is based on
	UpgradeStatusType m_status;							///< status of upgrade
	Upgrade *m_next;				///< next
	Upgrade *m_prev;				///< prev

};

//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
enum UpgradeType
{
	UPGRADE_TYPE_PLAYER = 0,						// upgrade applies to a player as a whole
	UPGRADE_TYPE_OBJECT,								// upgrade applies to an object instance only

	NUM_UPGRADE_TYPES,		// keep this last
};
extern const char *TheUpgradeTypeNames[]; //Change above, change this!

//-------------------------------------------------------------------------------------------------
/** A single upgrade template definition */
//-------------------------------------------------------------------------------------------------
class UpgradeTemplate : public MemoryPoolObject
{

	MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( UpgradeTemplate, "UpgradeTemplate" )

public:

	UpgradeTemplate( void );
	// virtual destructor defined by memory pool object

	Int calcTimeToBuild( Player *player ) const;			///< time in logic frames it will take this player to "build" this UpgradeTemplate
	Int calcCostToBuild( Player *player ) const;			///< calc the cost to build this upgrade

	// field access
	void setUpgradeName( const AsciiString& name ) { m_name = name; }
	const AsciiString& getUpgradeName( void ) const { return m_name; }
	void setUpgradeNameKey( NameKeyType key ) { m_nameKey = key; }
	NameKeyType getUpgradeNameKey( void ) const { return m_nameKey; }
	const AsciiString& getDisplayNameLabel( void ) const { return m_displayNameLabel; }
	UpgradeMaskType getUpgradeMask() const { return m_upgradeMask; }
	UpgradeType getUpgradeType( void ) const { return m_type; }
	const AudioEventRTS* getResearchCompleteSound() const { return &m_researchSound; }
	const AudioEventRTS* getUnitSpecificSound() const { return &m_unitSpecificSound; }
	AcademyClassificationType getAcademyClassificationType() const { return m_academyClassificationType; }

	/// inventory pictures
	void cacheButtonImage();
	const Image* getButtonImage() const { return m_buttonImage; }

	/// INI parsing
	const FieldParse *getFieldParse() const { return m_upgradeFieldParseTable; }

	// friend access methods for the UpgradeCenter ONLY
	void friend_setNext( UpgradeTemplate *next ) { m_next = next; }
	void friend_setPrev( UpgradeTemplate *prev ) { m_prev = prev; }
	UpgradeTemplate *friend_getNext( void ) { return m_next; }
	UpgradeTemplate *friend_getPrev( void ) { return m_prev; }
	const UpgradeTemplate *friend_getNext( void ) const { return m_next; }
	const UpgradeTemplate *friend_getPrev( void ) const { return m_prev; }
	void friend_setUpgradeMask( UpgradeMaskType mask ) { m_upgradeMask = mask; }
	void friend_makeVeterancyUpgrade(VeterancyLevel v);

protected:

	UpgradeType m_type;									///< upgrade type (PLAYER or OBJECT)
	AsciiString m_name;									///< upgrade name
	NameKeyType m_nameKey;							///< name key
	AsciiString m_displayNameLabel;			///< String manager label for UI display name
	Real m_buildTime;										///< database # for how long it takes to "build" this
	Int m_cost;													///< cost for production 
	UpgradeMaskType m_upgradeMask;			///< Unique bitmask for this upgrade template
	AudioEventRTS	m_researchSound;			///< Sound played when upgrade researched.
	AudioEventRTS	m_unitSpecificSound;	///< Secondary sound played when upgrade researched.
	AcademyClassificationType m_academyClassificationType; ///< A value used by the academy to evaluate advice based on what players do.

	UpgradeTemplate *m_next;						///< next
	UpgradeTemplate *m_prev;						///< prev

	AsciiString m_buttonImageName;			///< "Queue" images to show in the build queue
	const Image *m_buttonImage;

	/// INI field table
	static const FieldParse m_upgradeFieldParseTable[];		///< the parse table

};

//-------------------------------------------------------------------------------------------------
/** The upgrade center keeps some basic information about the possible upgrades */
//-------------------------------------------------------------------------------------------------
class UpgradeCenter : public SubsystemInterface
{

public:

	UpgradeCenter( void );
	virtual ~UpgradeCenter( void );

	void init( void );												///< subsystem interface
	void reset( void );												///< subsystem interface
	void update( void ) { }										///< subsystem interface

	UpgradeTemplate *firstUpgradeTemplate( void );	///< return the first upgrade template
	const UpgradeTemplate *findUpgradeByKey( NameKeyType key ) const;		///< find upgrade by name key
	const UpgradeTemplate *findUpgrade( const AsciiString& name ) const;				///< find and return upgrade by name
	const UpgradeTemplate *findVeterancyUpgrade(VeterancyLevel level) const;				///< find and return upgrade by name

	UpgradeTemplate *newUpgrade( const AsciiString& name );				///< allocate, link, and return new upgrade

	/// does this player have all the necessary things to make this upgrade
	Bool canAffordUpgrade( Player *player, const UpgradeTemplate *upgradeTemplate, Bool displayReason = FALSE ) const;
	std::vector<AsciiString> getUpgradeNames( void ) const;	// For WorldBuilder only!!!

	static void parseUpgradeDefinition( INI *ini );

protected:

	UpgradeTemplate *findNonConstUpgradeByKey( NameKeyType key );		///< find upgrade by name key

	void linkUpgrade( UpgradeTemplate *upgrade );			///< link upgrade to list
	void unlinkUpgrade( UpgradeTemplate *upgrade );		///< remove upgrade from list

	UpgradeTemplate *m_upgradeList;										///< list of all upgrades we can have
	Int m_nextTemplateMaskBit;												///< Each instantiated UpgradeTemplate will be given a Int64 bit as an identifier
	Bool buttonImagesCached;

};

// EXTERNALS //////////////////////////////////////////////////////////////////////////////////////
extern UpgradeCenter *TheUpgradeCenter;

#endif  // end __UPGRADE_H_
