//	GameState.h - Base class for the various game states.
//  ----------------------------------------------------------------------------
//	This file is part of 'NiallsAVLib', base code for any kind of audiovisual
//	apps.
//	Copyright (C) 2012  Niall Moody
//	
//	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/>.
//	----------------------------------------------------------------------------

#ifndef GAMESTATE_H_
#define GAMESTATE_H_

#include "InterpolatedValue.h"
#include "ResourceManager.h"
#include "c0xHeaders.h"
#include "TwoFloats.h"

#include <string>
#include <map>

class Application;
class GlobalData;
class Sounder;
class Drawer;

typedef shared_ptr<GlobalData> GlobalDataPtr;
typedef shared_ptr<Sounder> SounderPtr;
typedef shared_ptr<Drawer> DrawerPtr;

//------------------------------------------------------------------------------
///	Base class for the various game states.
class GameState
{
  public:
	///	Constructor.
	GameState(Application& app, SounderPtr& sound);
	///	Destructor.
	virtual ~GameState();

	///	Called frequently to update the state.
	/*!
		This method is assumed to run on a fixed 1/60 second timestep. Depending
		on vsync, cpu speed etc. it may be called multiple times for a single
		(visual) frame (i.e. draw() call), or only every alternate frame. When
		coding your draw() call, make sure you use the timestepInterp parameter
		to interpolate between drawing positions etc. That way drawing should
		appear as smooth as is possible across a wide range of different
		systems.

		Depending on the backend, this may be called alongside the draw() call,
		or in a separate thread.
	 */
	virtual void update() {};
	///	Called to draw the state.
	/*!
		\param d The Drawer which can be used to draw things.
		\param timestepInterp This is used to accommodate the fixed timestep
		used in update(). It should be used to interpolate between the previous
		draw positions etc. and the current ones. Effectively, draw() will
		always be 1 frame behind update().

		\sa http://gafferongames.com/game-physics/fix-your-timestep/
	 */
	virtual void draw(DrawerPtr& d, float timestepInterp) = 0;

	///	Called when a key down event is received.
	/*!
		\param action The action associated with the key the user pressed. \sa KeyManager.
		\param keyPressed The actual key the user pressed, in unicode.
		\param keyModifier Bitfield of any modifier keys held down while the
		user pressed the key (0:none, 1:Ctrl, 2:Shift, 3:Alt, 4:Meta).
	 */
	virtual void keyDown(const std::wstring& action,
						 const std::wstring& keyPressed,
						 int keyModifier) {};
	///	Called when a key up event is received.
	/*!
		\sa keyDown
	 */
	virtual void keyUp(const std::wstring& action,
					   const std::wstring& keyPressed,
					   int keyModifier) {};

	///	Called when a mouse down event is received.
	/*!
		\param button 1 == left, 2 == middle, 3 == right.
	 */
	virtual void mouseDown(int button, const TwoFloats& pos) {};
	///	Called when a mouse up event is received.
	virtual void mouseUp(int button, const TwoFloats& pos) {};
	///	Called when a mouse move event is received.
	virtual void mouseMove(const TwoFloats& pos) {};
	///	Called when a mouse wheel event is received.
	virtual void mouseWheel(bool dir) {};

	///	Called when a joystick axis changes.
	/*!
		\param action The name of the action mapped to this joystick axis.
		\param value The value of this axis (0->1).
		\param joystick The index of the joystick which sent this message.
		\param axis The index of the axis which changed (0 = up, 1 = right,
		2 = down, 3 = left, 4 = trigger1, 5 = trigger2, 6 = up2, 7 = right2,
		8 = down2, 9 = left2).
	 */
	virtual void joyMove(const std::wstring& action,
						 float value,
						 int joystick,
						 int axis) {};

	///	Returns the name of this state.
	virtual const std::wstring getName() const = 0;

	///	Retursn the size of the drawing area for this application instance.
	const TwoFloats& getDrawingAreaSize() const;

	///	Simple enum representing a key modifier.
	enum KeyModifier
	{
		None = 0,
		Shift,
		Ctrl,
		Alt
	};
  protected:
	///	Used by subclasses to tell Application to move to the next state.
	void nextState(const std::wstring& newState, const std::wstring& extra = L"");
	///	Used by subclasses to tell Application to quit.
	void quit();
	///	Used by subclasses to set the mouse position.
	void setMousePos(const TwoFloats& pos);
	///	Returns the ResourceManager for this application instance.
	const ResourceManager& getResourceManager() const;
	///	Returns the GlobalData for this application instance.
	GlobalDataPtr getGlobalData();
	///	Returns the application instance.
	Application& getApplication() const {return application;};
  private:
	///	The main Application instance for the game.
	Application& application;
};

//------------------------------------------------------------------------------
///	Typedef for a GameState shared_ptr.
typedef shared_ptr<GameState> GameStatePtr;

//------------------------------------------------------------------------------
///	Base class for GameStateCreator.
/*!
	\sa GameStateCreator
 */
class GameStateCreatorBase
{
  public:
	///	Constructor (does nothing).
	GameStateCreatorBase() {};
	///	Destructor (does nothing).
	virtual ~GameStateCreatorBase() {};

	///	Returns a new instance of a GameState subclass.
	virtual GameStatePtr createInstance(Application& app,
										SounderPtr& sounder) const {return GameStatePtr();};
};

//------------------------------------------------------------------------------
///	Used to construct GameStates.
/*!
	All subclasses of GameState should have a static instance of this, or
	Application won't be able to construct them.
 */
template <class T>
class GameStateCreator : public GameStateCreatorBase
{
  public:
	///	Constructor (does nothing).
	GameStateCreator() {};
	///	Destructor (does nothing).
	~GameStateCreator() {};

	///	Returns a new instance of a GameState subclass.
	GameStatePtr createInstance(Application& app, SounderPtr& sounder) const
	{
		return GameStatePtr(new T(app, sounder));
	};
};

#endif
