/*
**	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: Radar.h //////////////////////////////////////////////////////////////////////////////////
// Author: Colin Day, January 2002
// Desc:   Logical radar implementation
///////////////////////////////////////////////////////////////////////////////////////////////////

#pragma once

#ifndef __RADAR_H_
#define __RADAR_H_

// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "Lib/BaseType.h"
#include "Common/SubsystemInterface.h"
#include "Common/GameMemory.h"
#include "GameClient/Display.h"	// for ShroudLevel
#include "GameClient/Color.h"

// FORWARD REFERENCES /////////////////////////////////////////////////////////////////////////////
class GameWindow;
class Object;
class Player;
class TerrainLogic;

// GLOBAL /////////////////////////////////////////////////////////////////////////////////////////
//
// the following is used for the resolution of the radar "cells" ... this is how accurate
// the radar is and also reflects directly the size of the image we build ... which with
// WW3D must be a square power of two as well
//
enum 
{ 
	RADAR_CELL_WIDTH  = 128,	// radar created at this horz resolution
	RADAR_CELL_HEIGHT = 128   // radar created at this vert resolution
};

//-------------------------------------------------------------------------------------------------
/** These event types determine the colors radar events happen in to make it easier for us
	* to play events with a consistent color scheme */
//-------------------------------------------------------------------------------------------------
enum RadarEventType
{
	RADAR_EVENT_INVALID = 0,
	RADAR_EVENT_CONSTRUCTION,
	RADAR_EVENT_UPGRADE,
	RADAR_EVENT_UNDER_ATTACK,
	RADAR_EVENT_INFORMATION,
	RADAR_EVENT_BEACON_PULSE,
	RADAR_EVENT_INFILTRATION, //for defection, hijacking, hacking, carbombing, and other sneaks
	RADAR_EVENT_BATTLE_PLAN,
	RADAR_EVENT_STEALTH_DISCOVERED,		// we discovered a stealth unit
	RADAR_EVENT_STEALTH_NEUTRALIZED,	// our stealth unit has been revealed
	RADAR_EVENT_FAKE,					//Internally creates a radar event, but doesn't notify the player (unit lost 
														//for example, so we can use the spacebar to jump to the event).
 
 	RADAR_EVENT_NUM_EVENTS  // keep this last
 	
};

// PROTOTYPES /////////////////////////////////////////////////////////////////////////////////////

//-------------------------------------------------------------------------------------------------
/** Radar objects are objects that are on the radar, go figure :) */
//-------------------------------------------------------------------------------------------------
class RadarObject : public MemoryPoolObject,
										public Snapshot
{

	MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( RadarObject, "RadarObject" )

public:
	
	RadarObject( void );
	// destructor prototype defined by memory pool glue

	// color management
	void setColor( Color c ) { m_color = c; }
	inline Color getColor( void ) const { return m_color; }

	inline void friend_setObject( Object *obj ) { m_object = obj; }
	inline Object *friend_getObject( void ) { return m_object; }
	inline const Object *friend_getObject( void ) const { return m_object; }

	inline void friend_setNext( RadarObject *next ) { m_next = next; }
	inline RadarObject *friend_getNext( void ) { return m_next; }
	inline const RadarObject *friend_getNext( void ) const { return m_next; }

	Bool isTemporarilyHidden() const;

protected:

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

	Object *m_object;				///< the object
	RadarObject *m_next;		///< next radar object
	Color m_color;					///< color to draw for this object on the radar

};

//-------------------------------------------------------------------------------------------------
/** Radar priorities.  Keep this in sync with the priority names list below */
//-------------------------------------------------------------------------------------------------
enum RadarPriorityType
{
	RADAR_PRIORITY_INVALID,					// a priority that has not been set (in general it won't show up on the radar)
	RADAR_PRIORITY_NOT_ON_RADAR,		// object specifically forbidden from being on the radar
	RADAR_PRIORITY_STRUCTURE,				// structure level drawing priority
	RADAR_PRIORITY_UNIT,						// unit level drawing priority
	RADAR_PRIORITY_LOCAL_UNIT_ONLY,	// unit priority, but only on the radar if controlled by the local player

	RADAR_PRIORITY_NUM_PRIORITIES		// keep this last
};
#ifdef DEFINE_RADAR_PRIORITY_NAMES
static const char *RadarPriorityNames[] = 
{
	"INVALID",											// a priority that has not been set (in general it won't show up on the radar)
	"NOT_ON_RADAR",									// object specifically forbidden from being on the radar
	"STRUCTURE",										// structure level drawing priority
	"UNIT",													// unit level drawing priority
	"LOCAL_UNIT_ONLY",							// unit priority, but only on the radar if controlled by the local player

	NULL														// keep this last
};
#endif  // DEFINE_RADAR_PRIOTITY_NAMES

//-------------------------------------------------------------------------------------------------
/** Interface for the radar */
//-------------------------------------------------------------------------------------------------
class Radar : public Snapshot,
							public SubsystemInterface
{

public:
	
	Radar( void );
	virtual ~Radar( void );

	virtual void init( void ) { }														///< subsystem initialization
	virtual void reset( void );															///< subsystem reset
	virtual void update( void );														///< subsystem per frame update

	// is the game window parameter the radar window
	Bool isRadarWindow( GameWindow *window ) { return (m_radarWindow == window) && (m_radarWindow != NULL); }

	Bool radarToWorld( const ICoord2D *radar, Coord3D *world );		///< radar point to world point on terrain
	Bool radarToWorld2D( const ICoord2D *radar, Coord3D *world );		///< radar point to world point (x,y only!)
	Bool worldToRadar( const Coord3D *world, ICoord2D *radar );		///< translate world point to radar (x,y)
	Bool localPixelToRadar( const ICoord2D *pixel, ICoord2D *radar );	///< translate pixel (with UL of radar being (0,0)) to logical radar coords
	Bool screenPixelToWorld( const ICoord2D *pixel, Coord3D *world ); ///< translate pixel (with UL of the screen being (0,0)) to world position in the world
	Object *objectUnderRadarPixel( const ICoord2D *pixel );				///< return the object (if any) represented by the pixel coords passed in
	void findDrawPositions( Int startX, Int startY, Int width, Int height, 
													ICoord2D *ul, ICoord2D *lr );					///< make translation for screen area of radar square to scaled aspect ratio preserving points inside the radar area

	// priority inquiry
	Bool isPriorityVisible( RadarPriorityType priority ) const;		///< is the priority passed in a "visible" one on the radar

	// radar events
	void createEvent( const Coord3D *world, RadarEventType type, Real secondsToLive = 4.0f );	///< create radar event at location in world
	void createPlayerEvent( Player *player, const Coord3D *world, RadarEventType type, Real secondsToLive = 4.0f );  ///< create radar event using player colors

	Bool getLastEventLoc( Coord3D *eventPos );							///< get last event loc (if any)
	void tryUnderAttackEvent( const Object *obj );					///< try to make an "under attack" event if it's the proper time
	void tryInfiltrationEvent( const Object *obj );					///< try to make an "infiltration" event if it's the proper time
 	Bool tryEvent( RadarEventType event, const Coord3D *pos );	///< try to make a "stealth" event

	// adding and removing objects from the radar
	void addObject( Object *obj );													///< add object to radar
	void removeObject( Object *obj );												///< remove object from radar
	void examineObject( Object *obj );											///< re-examine object and resort if needed

	// radar options
	void hide( Bool hide ) { m_radarHidden = hide; }				///< hide/unhide the radar
	Bool isRadarHidden( void ) { return m_radarHidden; }		///< is radar hidden
	// other radar option methods here like the ability to show a certain
	// team, show buildings, show units at all, etc

	// forcing the radar on/off regardless of player situation
	void forceOn( Bool force ) { m_radarForceOn = force; }				///< force the radar to be on
	Bool isRadarForced( void ) { return m_radarForceOn; }		///< is radar forced on?

	/// refresh the water values for the radar
	virtual void refreshTerrain( TerrainLogic *terrain );

	/// queue a refresh of the terran at the next available time
	virtual void queueTerrainRefresh( void );

	virtual void newMap( TerrainLogic *terrain );	///< reset radar for new map

	virtual void draw( Int pixelX, Int pixelY, Int width, Int height ) = 0;	///< draw the radar

	/// empty the entire shroud
	virtual void clearShroud() = 0;

	/// set the shroud level at shroud cell x,y
	virtual void setShroudLevel( Int x, Int y, CellShroudStatus setting ) = 0;

protected:

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

	/// internal method for creating a radar event with specific colors
	void internalCreateEvent( const Coord3D *world, RadarEventType type, Real secondsToLive,
														const RGBAColorInt *color1, const RGBAColorInt *color2 );

	void deleteListResources( void );			///< delete list radar resources used
	Bool deleteFromList( Object *obj, RadarObject **list );	///< try to remove object from specific list

	inline Real getTerrainAverageZ() const { return m_terrainAverageZ; }
	inline Real getWaterAverageZ() const { return m_waterAverageZ; }
	inline const RadarObject* getObjectList() const { return m_objectList; }
	inline const RadarObject* getLocalObjectList() const { return m_localObjectList; }

	void clearAllEvents( void );					///< remove all radar events in progress

	// search the object list for an object that maps to the given logical radar coords
	Object *searchListForRadarLocationMatch( RadarObject *listHead, ICoord2D *radarMatch );

	Bool m_radarHidden;										///< true when radar is not visible
	Bool m_radarForceOn;									///< true when radar is forced to be on
	RadarObject *m_objectList;						///< list of objects in the radar
	RadarObject *m_localObjectList;				/** list of objects for the local player, sorted
																					* in exactly the same priority as the regular
																					* object list for all other objects */
//	typedef std::list<Object*> HeroList;
//	HeroList m_heroList;		//< list of pointers to objects with radar icon representations

	Real m_terrainAverageZ;								///< average Z for terrain samples
	Real m_waterAverageZ;									///< average Z for water samples

	//
	// when dealing with world sampling we will sample at these intervals so that
	// the whole map can be accounted for within our RADAR_CELL_WIDTH and
	// RADAR_CELL_HEIGHT resolutions
	//
	Real m_xSample;												
	Real m_ySample;												  

	enum { MAX_RADAR_EVENTS = 64 };
	struct RadarEvent
	{
		RadarEventType type;								///< type of this radar event
		Bool active;												///< TRUE when event is "active", otherwise it's just historical information in the event array to look through
		UnsignedInt createFrame;						///< frame event was created on
		UnsignedInt dieFrame;								///< frame the event will go away on
		UnsignedInt fadeFrame;							///< start fading out on this frame
		RGBAColorInt color1;								///< color 1 for drawing
		RGBAColorInt color2;								///< color 2 for drawing
		Coord3D worldLoc;										///< location of event in the world
		ICoord2D radarLoc;									///< 2D radar location of the event
		Bool soundPlayed;										///< TRUE when we have played the radar sound for this
	};
	RadarEvent m_event[ MAX_RADAR_EVENTS ];///< our radar events
	Int m_nextFreeRadarEvent;							///< index into m_event for where to store the next event
	Int m_lastRadarEvent;									///< index of the most recent radar event

	GameWindow *m_radarWindow;						///< window we display the radar in

	Region3D m_mapExtent;									///< extents of the current map

	UnsignedInt m_queueTerrainRefreshFrame;  ///< frame we requested the last terrain refresh on

};

// EXTERNALS //////////////////////////////////////////////////////////////////////////////////////
extern Radar *TheRadar;  ///< the radar singleton extern

#endif  // __RADAR_H_