#ifndef _CONTROLLERBASE_H
#define _CONTROLLERBASE_H

#include "Engine.h"

namespace Engine {

class ModelBase;
class Console;
class Module;

/** \brief The IMGUI state
 *
 * See also http://sol.gfxile.net/imgui/
 */
struct IMGUIState {
	int hotitem;
	int activeitem;

	int kbditem;
	SDLKey last_keysym;
	Uint16 last_unicode;

	int lastwidget;
};

/** \brief Defines the number of keys (keyboard + mous) that we can bind to.
 * 
 * As the keysym enum of SDL has about 320 keys defined and we might have some
 * more we set this define to 400 which should suffice. See also the file
 * keytable.h
 */
#define BINDING_KEYS_LAST 400

/** \brief Converts a string into the corresponding keycode */
int convert_keystring (const char *key_val);
/** \brief Converts a key code value to the string that describes the value */
const char* convert_keycode (const int &keycode);

/** \brief All input is sent here and distributed from here
 *
 *	Distributes and modifies the Model and indirectly the view by modifying the
 *	camera. It also holds the configuration of the keybindings and sends
 *	commands to the CommandQueue.
 */

class ControllerBase : public Module { 
	public:
		/** \brief Processes all inputs and performs all the controlling for the
		 * current frame. */
		void Process ();
		/** \brief Returns the current mouse position in screen coordinates */
		void GetMouseScreenPosition (int *pos_out) {
			pos_out[0] = mMouseScreenPosition[0];
			pos_out[1] = mMouseScreenPosition[1];
		}
		void GetMouseWorldPosition (float *pos_out) {
			pos_out[0] = mMouseWorldPosition[0];
			pos_out[1] = mMouseWorldPosition[1];
			pos_out[2] = mMouseWorldPosition[2];
		}
		bool GetButtonState (unsigned int key) {
			assert (key < BINDING_KEYS_LAST);
			return mButtonStates.test(key);
		}
		void SetButtonState (unsigned int key, bool state) {
			assert (key < BINDING_KEYS_LAST);
			mButtonStates.set (key, state);
		}
		bool BindKey (int key, const char *command);

		/** \brief Activates or deactivates unicode processing and key delays of the keyboard inputs */
		void EnableTextinput (bool textinput_state);

		void IMGUIPrepare () {
			uistate.hotitem = 0;
		}
		void IMGUIClear () {
			uistate.hotitem = 0;
			uistate.kbditem = 0;
		}
		void IMGUIFinish ();

		IMGUIState uistate;

	protected:
		/** \brief Initializes the system */
		virtual int OnInit (int argc, char* argv[]);
		/** \brief Destroys the system (must be called!) */
		virtual void OnDestroy ();
		/** \brief Registering of the commands of the ControllerBase */
		virtual void OnRegisterCommands ();

		/** \brief Processes all Events reported by SDL_PollEvent */
		virtual void ProcessEvents ();

		/** \brief Keyboard processing */
		bool OnKeyDown (const SDL_keysym &keysym);
		/** \brief Keyboard processing */
		bool OnKeyUp (const SDL_keysym &keysym);
		
		/** \brief Mouse processing */
		bool OnMouseButtonDown (Uint8 button, Uint16 xpos, Uint16 ypos);
		/** \brief Mouse processing */
		bool OnMouseButtonUp (Uint8 button, Uint16 xpos, Uint16 ypos);
		/** \brief Mouse processing */
		bool OnMouseMotion (const int xnew, const int ynew);

		/** \brief Resizes the size of the View */
		bool OnVideoResize (int width, int height);

		/** \brief Needs the Model to modify it */
		ModelBase * mModel;
		/** \brief Input might be sent to the Console, hence it is here */
		Console * mConsole;
		/** \brief The View which can get modified by Controller */
		ViewBase *mView;

		/** \brief Stores the current mouse position in screen coordinates */
		int mMouseScreenPosition[2];
		/** \brief Stores the current mouse position on the y=0 plane in world coordinates */
		float mMouseWorldPosition[3];
		
		/** \brief Stores for each button of the mouse whether it is clicked
		 * \TODO [low] move it to a bitset and remove the fixed amount of buttons */
		std::bitset<BINDING_KEYS_LAST> mButtonStates;

		/** \brief Contains all the bindings for the keyboard */
		std::string mBindings[BINDING_KEYS_LAST];

		friend class Engine;
};

}
#endif // _CONTROLLERBASE_H
