//	AppSettings.h - Simple class holding some of the app settings.
//  ----------------------------------------------------------------------------
//	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 APPSETTINGS_H_
#define APPSETTINGS_H_

#include "CmdLineParams.h"
#include "ThreeFloats.h"
#include "KeyManager.h"
#include "c0xHeaders.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;

///	Simple class holding some of the app settings.
/*!
	Some of this class' methods and statics are deliberately unimplemented to
	ensure that any attempt to build an app without them will throw linker
	errors.

	The idea is that this class encapsulates the name and version of the app,
	and offers a place to register your interest in specific command line
	arguments, and register possible GameStates.
 */
class AppSettings : public CmdLineCallback
{
  public:
	///	Constructor.
	AppSettings():
	drawingWidth(1280),
	drawingHeight(720),
	drawingAspect(KeepRatio),
	grabMouse(false)
	{
		loadingColours[0] = ThreeFloats(0.0f);
		loadingColours[1] = ThreeFloats(1.0f, 0.5f, 0.5f);
		loadingColours[2] = ThreeFloats(0.0f, 0.0f, 1.0f);
		loadingColours[3] = ThreeFloats(0.0f);
	};
	///	Destructor.
	~AppSettings() {};

	///	Called to let you e.g. register possible GameStates.
	/*!
		\param cmdLine The CmdLineParams object. This is used to indicate your
		interest in specific command line arguments. To use it:
\code
void AppSettings::initialise(CmdLineParams& cmdLine, Application *app)
{
	cmdLine.registerCallback(L"numCats", L"--numCats", L"-c", true, this);
}
\endcode
		To then access your arguments from your app, you can use the
		isArgumentPresent() and getArgumentValue() methods.
		\param app Used to register any GameStateCreators.
		\param keyManager Used to setup default key mappings.
		\param helpText If you've implemented any additional command line
		switches, write some text here for when the user does '--help'.

		Apps *MUST* implement this method, or your app won't link.
	 */
	void initialise(CmdLineParams& cmdLine,
					Application *app,
					KeyManager& keyManager,
					std::wstring& helpText);

	///	Constructs and return a Drawer to be used throughout the game's life.
	/*!
		\param drawerType A string naming the particular Drawer the user wants
		to use (passed in from the command line). If the string is empty,
		select the most appropriate Drawer (see GLESDrawer::isSupported()).

		Apps *MUST* implement this method, or your app won't link.

		If you're using the GLESDrawer you may want to include a runtime check
		that it's actually supported (via GLESDrawer::isSupported() ), and
		fallback to the GLImmediateDrawer if it's not.
	 */
	DrawerPtr getDrawer(const std::wstring& drawerType);

	///	Constructs and return a Sounder to be used throughout the game's life.
	/*!
		Apps *MUST* implement this method, or your app won't link.
	 */
	SounderPtr getSounder();

	///	Constructs and return a GlobalData to be used throughout the game's life.
	/*!
		Apps *MUST* implement this method, or your app won't link.
	 */
	GlobalDataPtr getGlobalData();

	///	Can be used to determine if the user passed in a particular command line argument.
	bool isArgumentPresent(const std::wstring& name) const
	{
		return (arguments.find(name) != arguments.end());
	};
	///	Returns the value of a particular command line argument.
	const std::wstring getArgumentValue(const std::wstring& name) const
	{
		std::wstring retval;
		std::map<std::wstring, std::wstring>::const_iterator it;

		it = arguments.find(name);
		if(it != arguments.end())
			retval = it->second;

		return retval;
	};

	///	Used to handle command line arguments.
	void cmdLineParameterFound(const std::wstring& name,
							   const std::wstring& value)
	{
		arguments.insert(std::make_pair(name, value));
	};

	///	Enum representing the different ways the screen's aspect ratio can be handled.
	enum AspectRatioType
	{
		KeepRatio = 0,	///<Adds black bars when the screen is a different aspect ratio to the drawing area.
		AlterRatio,		///<Alters the aspect ratio to match the screen. This alters the drawing area's dimensions.
		Stretch			///<Keeps the drawing area's dimensions, and just stretches it to fit the screen.
	};
	///	Sets the dimensions of the drawing area, and how they should be fit in the screen.
	void setDrawingDimensions(int width,
							  int height,
							  AspectRatioType aspect = KeepRatio)
	{
		drawingWidth = width;
		drawingHeight = height;
		drawingAspect = aspect;
	};
	///	Returns the width of the drawing area.
	int getDrawingAreaWidth() const {return drawingWidth;};
	///	Returns the height of the drawing area.
	int getDrawingAreaHeight() const {return drawingHeight;};
	///	Returns the aspect ratio type of the drawing area.
	AspectRatioType getDrawingAreaAspect() const {return drawingAspect;};

	///	Sets the colours to use in the LoadingScreen.
	void setLoadingColours(const ThreeFloats& background,
						   const ThreeFloats& pixelBright,
						   const ThreeFloats& pixelDark,
						   const ThreeFloats& endFade)
	{
		loadingColours[0] = background;
		loadingColours[1] = pixelBright;
		loadingColours[2] = pixelDark;
		loadingColours[3] = endFade;
	};
	///	Returns the colours to use in the LoadingScreen.
	const ThreeFloats * const getLoadingColours() const {return loadingColours;};

	///	Can be used to grab the mouse (useful when running in a window).
	void setGrabMouse(bool val) {grabMouse = val;};
	///	Returns whether or not to grab the mouse.
	bool getGrabMouse() const {return grabMouse;};

	///	The name of the application. *MUST* be implemented.
	static std::wstring applicationName;
	///	The version of the application *MUST* be implemented.
	static std::wstring applicationVersion;
  private:
	///	Any command line arguments passed to cmdLineParameterFound() end up here.
	std::map<std::wstring, std::wstring> arguments;

	///	The width of the drawing area.
	int drawingWidth;
	///	The height of the drawing area.
	int drawingHeight;
	///	How the drawing area is fit into the screen.
	AspectRatioType drawingAspect;

	///	The colours to use for the LoadingScreen.
	ThreeFloats loadingColours[4];

	///	Whether or not to grab the mouse.
	bool grabMouse;
};

#endif
