/*****************************************************************************
 * $Id: mod_base_class.hh,v 1.3 2006/11/25 17:29:33 devel Exp $
 * @file
 * @author	Jim E. Brooks  http://www.jimbrooks.org
 * @brief	Module base class.
 * @remarks	Moving this out of the main header file solved header dependencies.
 *//*
 * LEGAL:	COPYRIGHT (C) 2004 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE (GPL).
 *****************************************************************************/

#ifndef MOD_BASE_CLASS_HH
#define MOD_BASE_CLASS_HH 1

// Rule: Don't put any #includes!
#include "mod_base_tracer.hh" // an exception to the rule, needed by Dlist<Tracer> member

////////////////////////////////////////////////////////////////////////////////
/// @brief Module base class.
/// @remarks Module object construction and starting a module are separated
/// as a Module object is needed early in program initialization before it starts.
class Module
{
PREVENT_COPYING(Module)
// Interface:
public:						Module( void );
public:		virtual			~Module();
protected:	int				Init( int argc, char** argv, const string& appname );
public:		virtual void	Cmdarg( int argc, char** argv );
public:		virtual void	Start( void );
public:		virtual void	End( void );
private:	void			SelfChecks( void );
public:		virtual void	ResetScene( void ) = 0;
public:		virtual int		Animate( void );
public:		virtual void	Tick( void );
public:		void			PollInput( void );
public:		virtual bool	IfEasterEgg( void ) { return false; }
public:		virtual bool	IfRude( void ) { return false; }

// Initialization:
private:	void			StartStopListeners( bool start );

// Much joystick functionality is common to all modules,
// but keyboard assignments are considered module-specific.

// Keyboard:
protected:	virtual void	PollKeyboard( void ) = 0;
protected:	virtual bool	IfAnyKeyWasPressed( void ) = 0;

// Joystick:
// (ModuleJoystick object)

// Configuration:
protected:	virtual bool	SaveState( bool saveView ) = 0;
protected:	virtual bool	LoadState( void ) = 0;
protected:	bool			SaveStateBase( bool saveView, ConfigFile& config );
protected:	bool			LoadStateBase( bool loadView, ConfigFile& config );
protected:	virtual ConfigFile&	GetConfigFile( void ) = 0;
protected:	ConfigFile& 		GetConfigFileBase( const string& appname );
protected:	virtual void	CloseConfigFile( void );
protected:	string			GetInstallDir( const string& execName, char** argv );

// Misc:
public:		virtual bool	IfTexturing( void ) { return mTexturing; }
public:		virtual void	SetTexturing( bool f ) { mTexturing = f; }
public:		const Matrix&	GetPlayerMatrix( void );
public:		void			SetPlayer( int n ) { mPlayer = n==1 ? mPlayer1 : mPlayer2; }
public:		CraftPtrConst	GetPlayerCraft( void ) { return mPlayer == mPlayer1 ? mPlayer1Craft : mPlayer2Craft; }
public:		bool			IsFriendlyCraft( const Craft& craft ) { return &craft == mPlayer1Craft || &craft == mPlayer2Craft; }
public:		Percent			GetControlResponse( void );
public:		void			IncControlResponse( int dir );
public:		void			SetControlResponse( Dyna& dyna, const Percent percent );
public:		const vector<string>& GetTextureDirVec( void ) { return mTextureDirVec; }
public:		bool			IfCollisions( void ) { return mCollisions; }
public:		void			EnableCollisions( bool f ) { mCollisions = f; gEng.EnableCollisions( f ); }
public:		void			ToggleCollisions( void ) { EnableCollisions( ! mCollisions ) ; }

// Data members:
private:	bool			mCollisions;			///< NOTE: Use EnableCollisions() to inform engine!!
protected:	bool			mTexturing;				///< true if texturing is enabled
public:		bool			mDemoMode;
public:		enum { CONTROL_RESPONSE_PERCENT_MIN     =  10 }; ///< 0% is non-sensical
public:		enum { CONTROL_RESPONSE_PERCENT_DEFAULT =  50 }; ///< 50% is normal
public:		enum { CONTROL_RESPONSE_PERCENT_MAX     = 100 };
public:		Percent 		mControlResponseEye;	///< access using ControlResponse() functions
public:		Percent			mControlResponseChase;	///< 0 means default, not 0%
protected:	string			mConfigFilename;		///< empty unless -config <fname> was passed (ConfigFile chooses filename if empty)
protected:	string			mCwd;
public:		Dlist<Craft>	mCraftDlist;
public:		Dlist<DynaModel> mDynaModelTargetDlist;	///< only DynaModels which are targets (collidable/explosive)
public:		Dlist<Tracer>	mTracerDlist;
public:		CraftPtr		mPlayer;				///< current/active player
public:		CraftPtr		mPlayer1Craft;
public:		CraftPtr		mPlayer2Craft;
protected:	CraftPtr		mPlayer1;
protected:	CraftPtr		mPlayer2;
protected:	DynaConfigState mEyeConfigState;
protected:	vector<string>	mTextureDirVec;			///< directories have trailing slash
protected:	InputQueue		mInputQueue;			///< keyboard/joystick input queue
protected:	int				mDefaultWindowWidth;
protected:	int				mDefaultWindowHeight;
#if STATS && COMPILING_MODULE
public:		ModuleStats		mStatsBase;
#endif

protected:
	////////////////////////////////////////////////////////////////////////////////
	/// @brief Command-line args.
	/// Only those args whose values are needed after initialization are defined.
	/// The base Module class and derived-Module classes have separate Cmdarg objects.
	struct ModuleCmdarg
	{
		ModuleCmdarg( void )
		{
			mArgc = 0;
			mArgv = NULL;
			mArgv0 = "";

			mJoy = \
			mJoyAxis3 = \
			mJoyCalibration = \
            mJoyResponse = \
			mCollisions = false;
		}
		int		mArgc;
		char**	mArgv;
		string	mArgv0;
		bool	mJoy;
		bool	mJoyAxis3;
		bool	mJoyCalibration;
		bool	mJoyResponse;
		bool	mCollisions;
	};
	ModuleCmdarg	mCmdargBase;

#if DEBUG
protected:	virtual void	EndDebug( void );
public:		bool			IfAnimating( void ) const { return mAnimating; }
private:	int				mAnimating;  ///< for catching if animation lists disrupted
#endif

#define MODULE_BASE_LISTENERS_FRIEND 1
#include "mod_base_listeners.hh"
#undef  MODULE_BASE_LISTENERS_FRIEND

friend class ModuleJoystick;
};

#endif // MOD_BASE_CLASS_HH
