/*
**	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: Shell.h //////////////////////////////////////////////////////////////////////////////////
// Author: Colin Day, September 2001
// Description: Shell menu representations
//
// Using The Shell:
// ----------------
//
//	The Shell makes use of the window layouts to represent screens.  You can push and
//	pop screens on the stack so that you don't have to keep track of how you got
//  to which screen.
//
//  Here is what happens when you push a layout on the shell stack:
//	1) The layout name is stored as a "pending push"
//	2) The top of the stack has the Shutdown() method run
//	3) The Shutdown() method (or other mechanisms like Update()) will call
//		 Shell::shutdownComplete() when the shutdown process for that layout is "complete"
//  4) Shell::shutdownComplete() sees the "pending push" in the shell
//  5) "Pending push" layout is then loaded from disk and the pending push state is cleared
//  6) The new layout is put on the top of the stack
//  7) The new layout Init() method is called
//
//  Here is what happens when you pop the top of the stack
//	1) The stack sets a "pending pop" as in progress
//	2) The top layout of the stack has the Shutdown() method called
//	3) The Shutdown() method (or other mechanisms like Update()) will call
//		 Shell::shutdownComplete() when the shutdown process for that layout is "complete"
//  4) Shell::shutdownComplete() sees the "pending pop" in the shell
//  5) The "pending pop" layout is then destroyed and removed from the stack
//  6) The new top of the stack has the Init() method run
//
//  Window Layouts and the Shell:
//  -----------------------------
//
//  Window Layouts in the shell need the following functions to work property, these
//	can be assigned from the GUIEdit window layout tool:
//
//		- Init() [OPTIONAL]
//			This is called as a result of a push or pop operation (see above for more info)
//			The window layout is loaded from disk and then this Init() 
//			method is run.  All shell layout Init() methods should show 
//			the layout windows.  At this point you could move windows
//			to starting positions, set a state that the Update() method looks at to 
//			"animate" the windows to the desired positions.
//
//		- Update() [OPTIONAL]
//			This is called once at a rate of "shellUpdateDelay" for EVERY screen on the shell
//			stack.  It does not matter if the screen is on the top, or is hidden, or
//			anything, this is always called.  Each update is run starting with the screen
//			at the top of the stack and progressing to the bottom of the stack.
//			States could be set in the Init() or Shutdown() methods of the layout
//			that the Update() looks at and reacts to appropriately if desired.
//
//		- Shutdown() [REQUIRED]
//			This is called when a layout is popped off the stack, or when a new layout
//			is pushed on top of this one (see above for more detail on what happens
//			during the push/pop process).  You can switch into a "shutdown" state and 
//			animate the layout appropriately in the Update() method for the layout.
//			When shutdown is actually complete you should hide the all windows in
//			the layout and then you are REQUIRED to notify the shell by calling
//			the Shell::shutdownComplete() method.
//
//			Shutdown() is also required to be able to handle the paramater "immediatePop".
//			If this paramater is TRUE it means that when control returns from the
//			shutdown function that the layout will immediately be popped off the
//			stack.  We need to be able to handle this when in code we want to
//			traverse back down the stack rapidly (like when we lose connection to
//			an online service, we might pop all the way back to the login screen)
//
///////////////////////////////////////////////////////////////////////////////////////////////////

#pragma once

#ifndef __SHELL_H_
#define __SHELL_H_

// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////

// FORWARD REFERENCES /////////////////////////////////////////////////////////////////////////////
class WindowLayout;
class AnimateWindowManager;
class GameWindow;
class ShellMenuSchemeManager;

enum AnimTypes;

//-------------------------------------------------------------------------------------------------
/** This is the interface to the shell system to load, display, and
	* manage screen menu shell system layouts */
//-------------------------------------------------------------------------------------------------
class Shell : public SubsystemInterface
{

public:

	Shell( void );
	~Shell( void );

	// Inhertited from subsystem ====================================================================
	virtual void init( void );			
	virtual void reset( void );			
	virtual void update( void );		
	//===============================================================================================

	void showShellMap(Bool useShellMap );										///< access function to turn on and off the shell map

	void hide( Bool hide );																	///< show/hide all shell layouts

	// pseudo-stack operations for manipulating layouts
	void push( AsciiString filename, Bool shutdownImmediate = FALSE );	///< load new screen on top, optionally doing an immediate shutdown
	void pop( void );																				///< pop top layout
	void popImmediate( void );															///< pop now, don't wait for shutdown
	void showShell( Bool runInit = TRUE );									///< init the top of stack
	void hideShell( void );																	///< shutdown the top of stack
	WindowLayout *top( void );															///< return top layout
	
	void shutdownComplete( WindowLayout *layout, Bool impendingPush = FALSE );	///< layout has completed shutdown

	WindowLayout *findScreenByFilename( AsciiString filename );		///< find screen
	inline Bool isShellActive( void ) { return m_isShellActive; }  ///<	Returns true if the shell is active
	
	inline Int getScreenCount(void) { return m_screenCount; }			///< Return the current number of screens

	void registerWithAnimateManager( GameWindow *win, AnimTypes animType, Bool needsToFinish, UnsignedInt delayMS = 0);
	Bool isAnimFinished( void );
	void reverseAnimatewindow( void );
	Bool isAnimReversed( void );

	void loadScheme( AsciiString name );
	ShellMenuSchemeManager *getShellMenuSchemeManager( void ) { return m_schemeManager;	}

	WindowLayout *getSaveLoadMenuLayout( void );		///< create if necessary and return layout for save load menu
	WindowLayout *getPopupReplayLayout( void );			///< create if necessary and return layout for replay save menu
	WindowLayout *getOptionsLayout( Bool create );	///< return layout for options menu, create if necessary and we are allowed to.
	void destroyOptionsLayout( void );							///< destroy the shell's options layout.

protected:

	void linkScreen( WindowLayout *screen );								///< link screen to list
	void unlinkScreen( WindowLayout *screen );							///< remove screen from list

	void doPush( AsciiString layoutFile );									///< workhorse for push action
	void doPop( Bool impendingPush );												///< workhorse for pop action

	enum { MAX_SHELL_STACK = 16 };													///< max simultaneous shell screens
	WindowLayout *m_screenStack[ MAX_SHELL_STACK ];					///< the screen layout stack
	Int m_screenCount;																			///< # of screens in screen stack

	WindowLayout *m_background;															///< The Background layout if the 3d shell isn't running
	Bool m_clearBackground;																	///< Flag if we're going to clear the background or not

	Bool m_pendingPush;																			///< TRUE when a push is pending
	Bool m_pendingPop;																			///< TRUE when a pop is pending
	AsciiString m_pendingPushName;													///< layout name to be pushed
	Bool m_isShellActive;																		///< TRUE when the shell is active
	Bool m_shellMapOn;																			///< TRUE when the shell map is on
	AnimateWindowManager *m_animateWindowManager;						///< The animate Window Manager
	ShellMenuSchemeManager *m_schemeManager;								///< The Shell Scheme Manager

	//
	// we keep a pointer to this layout so that we can simply just hide/unhide this
	// window layout.  Why you ask?  Well, as the result of pressing a button to start
	// a save game load a super large set of operations will happen as the game
	// loads.  One of those operations is the destruction of the menu, which although
	// it just destroys the windows and puts them on a destroyed list, that destroyed
	// list is also processed before we are out of our own window procedure.
	// This is a prime example why it's easier to just deal with windows by hiding and
	// un-hiding them rather than actually creating and destroying them.
	//
	WindowLayout *m_saveLoadMenuLayout;											///< save/load menu layout
	WindowLayout *m_popupReplayLayout;											///< replay save menu layout
	WindowLayout *m_optionsLayout;													///< options menu layout

};  // end class Shell

// INLINING ///////////////////////////////////////////////////////////////////////////////////////

// EXTERNALS //////////////////////////////////////////////////////////////////////////////////////
extern Shell *TheShell;  ///< the shell external interface

#endif // __SHELL_H_

