#ifndef _ENGINE_H
#define _ENGINE_H

#include <globals.h>

#include <assert.h>

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <bitset>
#include <limits>

#include "Module.h"
#include "EngineEnums.h"

// Some ugly #defines

/** \brief Defines the number of keys that can be defined for an EntityController
 *
 * The current state of the controls for an entity is stored in an std::bitset
 * and each bit tells us whether the key is pressed or not. Unfortunately we
 * have to know the number of bits that are to be reserved in advance so this
 * is hard coded into the library for now.
 */
const int EntityControllerMaxKeyStates = 64;

namespace Engine {

class ModelBase;
class ViewBase;
class ControllerBase;
class PhysicsBase;
class EntityFactoryBase;
class EventManager;
class SoundBase;

class Logging;
class Commands;
class Variables;
class Variable;
class Timer;

/** \brief The outermost class which contains just everything!
 *
 * Engine::Engine takes care of initializing, running and destroying the whole
 * Engine.
 *
 * When Initialize called, the submodules are created by Engine and
 * initializes them. There are two initialization phases:
 * - Basemodules initialization:
 *   The first phase creates the base modules such as Engine::Logging,
 *   Engine::Variables and Engine::Commands and calls Initialize () on them.
 * - ModelViewController initialization:  
 *   In the second phase at first the Submodules for each Engine::ModelBase, Engine::ViewBase and
 *   Engine::ControllerBase are allocated an initialized. Then the Engine::ModelBase,
 *   Engine::View and Engine::ControllerBase Modules are initialized.
 */
class Engine : public Module {
	public:
		Engine () {
			mModel = NULL;
			mView = NULL;
			mController = NULL;
			mLogging = NULL;
			mCommands = NULL;
			mVariables = NULL;
			mEntityFactory = NULL;
			mEventManager = NULL;
			mSoundManager = NULL;
		}

		void MainLoop () {
			OnMainLoop ();
		}

		void SetModel (ModelBase *model) { mModel = model; };
		ModelBase* GetModel () { return mModel; };
		void SetView (ViewBase *view) { mView = view; };
		ViewBase* GetView () { return mView; };
		void SetPhysics (PhysicsBase *physics) { mPhysics = physics; };
		PhysicsBase* GetPhysics () { return mPhysics; };
		void SetEntityFactory (EntityFactoryBase *entityfactory) { mEntityFactory = entityfactory; };

		void SetController (ControllerBase *controller) { mController = controller; };
		ControllerBase* GetController () { return mController; };
		void SetLogging (Logging *logging) { mLogging = logging; };
		void SetCommands (Commands *commands) { mCommands = commands; };
		void SetVariables (Variables *variables) { mVariables = variables; };

		void SetError (const char* str, ...);
		const char* GetError ();
		void SetStatus (const EngineStatus new_status);
		EngineStatus GetStatus ();

		void SetUserDataPath (const std::string &path) { 
			mUserDataPath = path; 
		};
		std::string GetUserDataPath () { return mUserDataPath; };

		void SetGameDataPath (const std::string &path) {
			mGameDataPath = path; 
		};
		std::string GetGameDataPath () { return mGameDataPath; };

		/** \brief Returns the path to a resource by prepending the game data path to
		 *  \brief it
		 */
		std::string GetResourceFullPath (const std::string &resource) {
			return mGameDataPath + resource;
		};

		/** \brief Returns the path to a file by prepending the user data path to it
		*/
		std::string GetUserDirFullPath (const std::string &path) { 
			return mUserDataPath + path; 
		};

	private:
		// Engine must not be created with the standard constructor! 
		// It must be ensured, that the correct EntityFactory is used!
	protected:
		virtual int OnInit (int argc, char* argv[]);
		virtual void OnDestroy ();
		virtual void OnRegisterCommands ();

		void OnMainLoop ();

		ModelBase *mModel;
		ViewBase *mView;
		ControllerBase *mController;
		PhysicsBase *mPhysics;
		EntityFactoryBase *mEntityFactory;
		EventManager *mEventManager;
		SoundBase *mSoundManager;

		Logging *mLogging;
		Commands *mCommands;
		Variables *mVariables;

		std::string mUserDataPath;
		std::string mGameDataPath;

		std::string mErrorString;
		EngineStatus mStatus;
};

}

/*
 * Global visible functions and classes
 */

namespace Engine {
/* Globaly visible classes */
extern Engine* EngineInstance;

/** \brief Sets the Engine::mErrorString to the given message */
void EngineSetError (const char* str, ...);
/** \brief Returns Engine::mErrorString */
const char* EngineGetError ();

/** \brief Sets the current state of the Engine */
void EngineSetStatus (const EngineStatus status);
/** \brief Returns the current state of the Engine */
EngineStatus EngineGetStatus ();

/** \brief Global access functions for the Model */
ModelBase* EngineGetModel ();
/** \brief Global access functions for the View */
ViewBase* EngineGetView ();
/** \brief Global access functions for the Controller */
ControllerBase* EngineGetController ();

/** \brief Returns the path to a resource by prepending the game data path to
 *  \brief it
 */
std::string GetResourceFullPath (const std::string &resource);

/** \brief Returns the path to a file by prepending the user data path to it
 */
std::string GetUserDirFullPath (const std::string &path);

/** \brief Checks whether a given file exists */
bool FileExists (const std::string &path);

}

/* Include the globally visible declarations of the other modules */
#include "LoggingGlobal.h"
#include "VariablesGlobal.h"
#include "CommandsGlobal.h"
#include "ModelBaseGlobal.h"
#include "ViewBaseGlobal.h"
#include "EventBaseGlobal.h"
#include "SoundBaseGlobal.h"

#endif // _ENGINE_H
