/*
**	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: GameWindowManager.h //////////////////////////////////////////////////////////////////////
// Created:    Colin Day, June 2001
// Desc:       The game window manager is the interface for interacting with
//						 the windowing system for purposes of any menus, or GUI 
//						 controls.
///////////////////////////////////////////////////////////////////////////////////////////////////

#pragma once

#ifndef __GAMEWINDOWMANAGER_H_
#define __GAMEWINDOWMANAGER_H_


#include "Common/STLTypedefs.h"
#include "Common/SubsystemInterface.h"
#include "GameClient/WindowLayout.h"
#include "GameClient/KeyDefs.h"
#include "GameClient/Gadget.h"

class GameWindow;

//-------------------------------------------------------------------------------------------------
/** Window layout info is a structure that can be passed to the load function of
	* a window script.  After the script is loaded, this parameter (if present)
	* will contain information about the script file at a global level such
	* as what file version was loaded, global layout callbacks, etc */
//-------------------------------------------------------------------------------------------------
enum { MAX_LAYOUT_FUNC_LEN = 256 };

typedef std::list <GameWindow *> GameWindowList;

class WindowLayoutInfo
{

public:
	WindowLayoutInfo();

	UnsignedInt version;												///< file version that was loaded
	WindowLayoutInitFunc init;									///< init method (if specified)
	WindowLayoutUpdateFunc update;							///< update method (if specified)
	WindowLayoutShutdownFunc shutdown;					///< shutdown method (if specified)
	AsciiString initNameString;									///< init method in flavor of string name
	AsciiString updateNameString;								///< update method in string flavor
	AsciiString  shutdownNameString;						///< shutdown method in string flavor, mmm!
	std::list<GameWindow *> windows;						///< list of top-level windows in the layout
};

//-------------------------------------------------------------------------------------------------
/** There exists a singleton GameWindowManager that defines how we can 
	* interact with the game windowing system */
//-------------------------------------------------------------------------------------------------
class GameWindowManager : public SubsystemInterface
{

friend class GameWindow;

public:

	GameWindowManager( void );
	virtual ~GameWindowManager( void );

	//-----------------------------------------------------------------------------------------------
	virtual void init( void );		///< initialize function
	virtual void reset( void );		///< reset the system
	virtual void update( void );  ///< update method, called once per frame

	virtual GameWindow *allocateNewWindow( void ) = 0;  ///< new game window

	void linkWindow( GameWindow *window );  ///< link into master list
	void unlinkWindow( GameWindow *window );  ///< unlink from master list
	void unlinkChildWindow( GameWindow *window );  ///< remove child from parent list
	void insertWindowAheadOf( GameWindow *window, GameWindow *aheadOf );  ///< add window to list 'ahead of'

	virtual GameWinDrawFunc getPushButtonImageDrawFunc( void ) = 0;
	virtual GameWinDrawFunc getPushButtonDrawFunc( void ) = 0;
	virtual GameWinDrawFunc getCheckBoxImageDrawFunc( void ) = 0;
	virtual GameWinDrawFunc getCheckBoxDrawFunc( void ) = 0;
	virtual GameWinDrawFunc getRadioButtonImageDrawFunc( void ) = 0;
	virtual GameWinDrawFunc getRadioButtonDrawFunc( void ) = 0;
	virtual GameWinDrawFunc getTabControlImageDrawFunc( void ) = 0;
	virtual GameWinDrawFunc getTabControlDrawFunc( void ) = 0;
	virtual GameWinDrawFunc getListBoxImageDrawFunc( void ) = 0;
	virtual GameWinDrawFunc getListBoxDrawFunc( void ) = 0;
	virtual GameWinDrawFunc getComboBoxImageDrawFunc( void ) = 0;
	virtual GameWinDrawFunc getComboBoxDrawFunc( void ) = 0;
	virtual GameWinDrawFunc getHorizontalSliderImageDrawFunc( void ) = 0;
	virtual GameWinDrawFunc getHorizontalSliderDrawFunc( void ) = 0;
	virtual GameWinDrawFunc getVerticalSliderImageDrawFunc( void ) = 0;
	virtual GameWinDrawFunc getVerticalSliderDrawFunc( void ) = 0;
	virtual GameWinDrawFunc getProgressBarImageDrawFunc( void ) = 0;
	virtual GameWinDrawFunc getProgressBarDrawFunc( void ) = 0;
	virtual GameWinDrawFunc getStaticTextImageDrawFunc( void ) = 0;
	virtual GameWinDrawFunc getStaticTextDrawFunc( void ) = 0;
	virtual GameWinDrawFunc getTextEntryImageDrawFunc( void ) = 0;
	virtual GameWinDrawFunc getTextEntryDrawFunc( void ) = 0;

	//---------------------------------------------------------------------------

	virtual GameWinDrawFunc getDefaultDraw( void );  ///< return default draw func
	virtual GameWinSystemFunc getDefaultSystem( void );  ///< return default system func
	virtual GameWinInputFunc getDefaultInput( void );  ///< return default input func
	virtual GameWinTooltipFunc getDefaultTooltip( void );  ///< return default tooltip func

	//---------------------------------------------------------------------------
	// MessageBox creation
	virtual GameWindow *gogoMessageBox(Int x, Int y, Int width, Int height, UnsignedShort buttonFlags,
                        UnicodeString titleString, UnicodeString bodyString,
                        GameWinMsgBoxFunc yesCallback,
                        GameWinMsgBoxFunc noCallback,
                        GameWinMsgBoxFunc okCallback,
                        GameWinMsgBoxFunc cancelCallback );

	virtual GameWindow *gogoMessageBox(Int x, Int y, Int width, Int height, UnsignedShort buttonFlags,
                        UnicodeString titleString, UnicodeString bodyString,
                        GameWinMsgBoxFunc yesCallback,
                        GameWinMsgBoxFunc noCallback,
                        GameWinMsgBoxFunc okCallback,
                        GameWinMsgBoxFunc cancelCallback, Bool useLogo );


	//---------------------------------------------------------------------------
	// gadget creation
	virtual GameWindow *gogoGadgetPushButton( GameWindow *parent, UnsignedInt status,
																						Int x, Int y, Int width, Int height,	
																						WinInstanceData *instData, 
																						GameFont *defaultFont, Bool defaultVisual );
	virtual GameWindow *gogoGadgetCheckbox( GameWindow *parent, UnsignedInt status,
																					Int x, Int y, Int width, Int height, 
																					WinInstanceData *instData,
																					GameFont *defaultFont, Bool defaultVisual );
	virtual GameWindow *gogoGadgetRadioButton( GameWindow *parent, UnsignedInt status,
																						 Int x, Int y, Int width, Int height, 
																						 WinInstanceData *instData, 
																						 RadioButtonData *rData,
																						 GameFont *defaultFont, Bool defaultVisual );
	virtual GameWindow *gogoGadgetTabControl( GameWindow *parent, UnsignedInt status,
																						 Int x, Int y, Int width, Int height, 
																						 WinInstanceData *instData, 
																						 TabControlData *rData,
																						 GameFont *defaultFont, Bool defaultVisual );
	virtual GameWindow *gogoGadgetListBox( GameWindow *parent, UnsignedInt status,
																				 Int x, Int y, Int width, Int height,
																				 WinInstanceData *instData, 
																				 ListboxData *listboxData,
																				 GameFont *defaultFont, Bool defaultVisual );
	virtual GameWindow *gogoGadgetSlider( GameWindow *parent, UnsignedInt status,
																				Int x, Int y, Int width, Int height,
																				WinInstanceData *instData, 
																				SliderData *sliderData,
																				GameFont *defaultFont, Bool defaultVisual );
	virtual GameWindow *gogoGadgetProgressBar( GameWindow *parent, UnsignedInt status,
																						 Int x, Int y, Int width, Int height, 
																						 WinInstanceData *instData,
																						 GameFont *defaultFont, Bool defaultVisual );
	virtual GameWindow *gogoGadgetStaticText( GameWindow *parent, UnsignedInt status,
																						Int x, Int y, Int width, Int height,
																						WinInstanceData *instData, 
																						TextData *textData,
																						GameFont *defaultFont, Bool defaultVisual );
	virtual GameWindow *gogoGadgetTextEntry( GameWindow *parent, UnsignedInt status,
																					 Int x, Int y, Int width, Int height,
																					 WinInstanceData *instData, 
																					 EntryData *entryData,
																					 GameFont *defaultFont, Bool defaultVisual );
	virtual GameWindow *gogoGadgetComboBox( GameWindow *parent, UnsignedInt status,
										                              Int x, Int y, Int width, Int height,
																									WinInstanceData *instData, 
																									ComboBoxData *comboBoxDataTemplate,
																								  GameFont *defaultFont, Bool defaultVisual );

	/** Use this method to assign the default images to gadgets as 
		* they area created */
	virtual void assignDefaultGadgetLook( GameWindow *gadget,
																				GameFont *defaultFont,
																				Bool assignVisual );

	//---------------------------------------------------------------------------
	// Creating windows
	/// create new window(s) from .wnd file ... see definition for what is returned
	virtual GameWindow *winCreateFromScript( AsciiString filename, WindowLayoutInfo *info = NULL );

	/// create new window(s) from .wnd file and wrap in a WindowLayout
	virtual WindowLayout *winCreateLayout( AsciiString filename );

	/// free temporary strings to make the memory leak manager happy.
	virtual void freeStaticStrings(void);

	/// create a new window by setting up parameters and callbacks
	virtual GameWindow *winCreate( GameWindow *parent, UnsignedInt status,
																 Int x, Int y, Int width, Int height,
																 GameWinSystemFunc system,
																 WinInstanceData *instData = NULL );

	//---------------------------------------------------------------------------
	// Manipulating windows in the system
	virtual Int winDestroy( GameWindow *window );  ///< destroy this window
	virtual Int winDestroyAll( void );  ///< destroy all windows in the system
	virtual GameWindow *winGetWindowList( void );  ///< get head of master list

	/// hide all windows in a certain range of id's (inclusinve );
	virtual void hideWindowsInRange( GameWindow *baseWindow, Int first, Int last,
																	 Bool hideFlag );
	/// enable all windows in a range of id's (inclusive)
	virtual void enableWindowsInRange( GameWindow *baseWindow, Int first, Int last,
																		 Bool enableFlag );	

	/// this gets called from winHide() when a window hides itself
	virtual void windowHiding( GameWindow *window );

	virtual void winRepaint( void );  ///< draw GUI in reverse order

	virtual void winNextTab( GameWindow *window );	///< give keyboard focus to the next window in the tab list

	virtual void winPrevTab( GameWindow *window );	///< give keyboard focus to the previous window in the tab list

	virtual void registerTabList( GameWindowList tabList );	///< we have to register a Tab List
	virtual void clearTabList( void );	///< we's gotz ta clear the tab list yo!

	// --------------------------------------------------------------------------
	/// process a single mouse event
	virtual WinInputReturnCode winProcessMouseEvent( GameWindowMessage msg,
														 ICoord2D *mousePos,
														 void *data );
	/// process a singke key event
	virtual WinInputReturnCode winProcessKey( UnsignedByte key, 
																						UnsignedByte state );
	// --------------------------------------------------------------------------

	virtual GameWindow *winGetFocus( void );  ///< return window that has the focus
	virtual Int winSetFocus( GameWindow *window );  ///< set this window as has focus
	virtual void winSetGrabWindow( GameWindow *window );  ///< set the grab window
	virtual GameWindow *winGetGrabWindow( void );  ///< who is currently 'held' by mouse
	virtual void winSetLoneWindow( GameWindow *window );  ///< set the open window

	virtual Bool isEnabled( GameWindow *win );  ///< is window or parents enabled
	virtual Bool isHidden( GameWindow *win );  ///< is parent or parents hidden
	virtual void addWindowToParent( GameWindow *window, GameWindow *parent );
	virtual void addWindowToParentAtEnd( GameWindow *window, GameWindow *parent );

	/// sends a system message to specified window
	virtual WindowMsgHandledType winSendSystemMsg( GameWindow *window, UnsignedInt msg,
																 WindowMsgData mData1, WindowMsgData mData2 );

	/// sends an input message to the specified window
	virtual WindowMsgHandledType winSendInputMsg( GameWindow *window, UnsignedInt msg,
																WindowMsgData mData1, WindowMsgData mData2 );

	/** get the window pointer from id, starting at 'window' and searching
	down the heirarchy.  If 'window' is NULL then all windows will
	be searched */ 
	virtual GameWindow *winGetWindowFromId( GameWindow *window, Int id );
	virtual Int winCapture( GameWindow *window );  ///< captures the mouse
	virtual Int winRelease( GameWindow *window );  ///< release mouse capture
	virtual GameWindow *winGetCapture( void );  ///< current mouse capture settings

	virtual Int winSetModal( GameWindow *window );  ///< put at top of modal stack
	virtual Int winUnsetModal( GameWindow *window );  /**< take window off modal stack, if window is
																										not at top of stack and error will occur */

	//---------------------------------------------------------------------------
	/////////////////////////////////////////////////////////////////////////////
	//---------------------------------------------------------------------------
	//---------------------------------------------------------------------------
	// The following public functions you should implement change the guts
	// for to work with your application.  Rather than draw images, or do string
	// operations with native methods, the game window system will always call
	// these methods to get the work done it needs
	//---------------------------------------------------------------------------
	//---------------------------------------------------------------------------
	/////////////////////////////////////////////////////////////////////////////
	//---------------------------------------------------------------------------

	/// draw image, coord are in screen and should be kepth within that box specified
	virtual void winDrawImage( const Image *image, Int startX, Int startY, Int endX, Int endY, Color color = 0xFFFFFFFF );
	/// draw filled rect, coords are absolute screen coords
	virtual void winFillRect( Color color, Real width, Int startX, Int startY, Int endX, Int endY );
	/// draw rect outline, coords are absolute screen coords
	virtual void winOpenRect( Color color, Real width, Int startX, Int startY, Int endX, Int endY );
	/// draw line, coords are absolute screen coords
	virtual void winDrawLine( Color color, Real width, Int startX, Int startY, Int endX, Int endY );
	/// Make a color representation out of RGBA components
	virtual Color winMakeColor( UnsignedByte red, UnsignedByte green, UnsignedByte blue, UnsignedByte alpha );
	/** Find an image reference and return a pointer to its image, you may
	recreate all Image structs to suit your project */
	virtual const Image *winFindImage( const char *name );
	virtual Int winFontHeight( GameFont *font );  ///< get height of font in pixels
	virtual Int winIsDigit( Int c );  ///< is character a digit
	virtual Int winIsAscii( Int c );  ///< is character a digit
	virtual Int winIsAlNum( Int c );  ///< is character alpha-numeric
	virtual void winFormatText( GameFont *font, UnicodeString text, Color color,
															Int x, Int y, Int width, Int height );
	virtual void winGetTextSize( GameFont *font, UnicodeString text, 
															 Int *width, Int *height, Int maxWidth );
	virtual UnicodeString winTextLabelToText( AsciiString label );  ///< convert localizable text label to real text
	virtual GameFont *winFindFont( AsciiString fontName, Int pointSize, Bool bold );  ///< get a font given a name

	/// @todo just for testing, remov this
	Bool initTestGUI( void );
	
	virtual GameWindow *getWindowUnderCursor( Int x, Int y, Bool ignoreEnabled = FALSE );	///< find the top window at the given coordinates

	//---------------------------------------------------------------------------
	/////////////////////////////////////////////////////////////////////////////
	//---------------------------------------------------------------------------
	//---------------------------------------------------------------------------
	//---------------------------------------------------------------------------
	//---------------------------------------------------------------------------
	/////////////////////////////////////////////////////////////////////////////
	//---------------------------------------------------------------------------

protected:

	void processDestroyList( void );  ///< process windows waiting to be killed

	Int drawWindow( GameWindow *window );  ///< draw this window

	void dumpWindow( GameWindow *window );  ///< for debugging

	GameWindow *m_windowList;			// list of all top level windows
	GameWindow *m_windowTail;			// last in windowList

	GameWindow *m_destroyList;			// list of windows to destroy

	GameWindow *m_currMouseRgn;		// window that mouse is over
	GameWindow *m_mouseCaptor;			// window that captured mouse
	GameWindow *m_keyboardFocus;		// window that has input focus
	ModalWindow *m_modalHead;			// top of windows in the modal stack
	GameWindow *m_grabWindow;			// window that grabbed the last down event
	GameWindow *m_loneWindow;			// Set if we just opened a Lone Window
	GameWindowList m_tabList;			// we have to register a tab list to make a tab list.
	const Image *m_cursorBitmap;
	UnsignedInt m_captureFlags;

};  // end GameWindowManager

// INLINE /////////////////////////////////////////////////////////////////////////////////////////
inline GameWinDrawFunc GameWindowManager::getDefaultDraw( void ) { return GameWinDefaultDraw; }
inline GameWinSystemFunc GameWindowManager::getDefaultSystem( void ) { return GameWinDefaultSystem; }
inline GameWinInputFunc GameWindowManager::getDefaultInput( void )  { return GameWinDefaultInput; }
inline GameWinTooltipFunc GameWindowManager::getDefaultTooltip( void ) { return GameWinDefaultTooltip; }

// EXTERN /////////////////////////////////////////////////////////////////////////////////////////
extern GameWindowManager *TheWindowManager;			///< singleton extern definition
extern UnsignedInt WindowLayoutCurrentVersion;  ///< current version of our window layouts

// this function lets us generically pass button selections to our parent, we may 
// frequently want to do this because we want windows grouped on child windows for
// convenience, but only want one logical system procedure responding to them all
extern WindowMsgHandledType PassSelectedButtonsToParentSystem( GameWindow *window, 
																															 UnsignedInt msg,
																															 WindowMsgData mData1, 
																															 WindowMsgData mData2 );
extern WindowMsgHandledType PassMessagesToParentSystem( GameWindow *window, 
																															 UnsignedInt msg,
																															 WindowMsgData mData1, 
																															 WindowMsgData mData2 );



#endif // __GAMEWINDOWMANAGER_H_

