#ifndef _VIEW_H
#define _VIEW_H

#include "ViewBase.h"
#include "OverlayBase.h"
#include "mathlib.h"
#include "Sprite.h"
#include "EntityBase.h"
#include "SimpleConsoleOverlay.h"
#include "AsteroidsEnums.h"

namespace asteroids {

struct ShipEntity;
struct AsteroidEntity;
struct RocketEntity;

struct BackgroundStar {
	vector3d position;
};

/** \brief Performs the actual drawing based on Camera and Model
 *
 * This View also takes care of the drawn user interface. There are different
 * view states that are drawn by the member functions with signatures
 * DrawUi{ViewStateName}(). Different view states can be pushed onto and
 * popped from the mViewStateStack which allows non-linear arrangement 
 * of different ViewStates in menus.
 */
class View : public Engine::ViewBase { 
	public:
		virtual ~View() {};

	protected:
		/** \brief Initializes the system */
		virtual int OnInit (int argc, char* argv[]);
		virtual void OnDestroy ();

		/** \brief Updates the camera for further drawing */
		virtual void UpdateCamera ();

	private:
		void DrawUi();

		void DrawPageTitle(const std::string &title);

		void DrawUiMainMenu();
		void DrawUiGameRunning();
		void DrawUiGameOver();
		void DrawUiLevelComplete();
		void DrawUiGamePaused();
		void DrawUiPlayerDied();
		void DrawHighscoreEntry(float x, float y, float entry_width, const std::string &name, unsigned int points);
		void DrawUiHighscore();
		void DrawUiOptions();
		void DrawUiEnterPlayername();

		virtual void Draw ();
		virtual void DrawWorld ();
		void DrawStars ();

		void DrawEntity (Engine::EntityBase *entity);
		void DrawShip (ShipEntity *ship);
		void DrawAsteroid (AsteroidEntity *asteroid);
		void DrawRocket (RocketEntity *asteroid);
		void DrawShipPart (Engine::EntityBase *entity);

		std::vector<BackgroundStar> mBackgroundStars;
		std::vector<unsigned int> mShipPartsEntityIds;

		/** \brief The ViewState stack that is used for non-linear menus */
		std::stack<ViewState> mViewStateStack;

		/** \brief Pushes the given state onto mViewStateStack */
		void PushViewState (const ViewState state) {
			Engine::LogDebug ("Pushing ViewState %s", GetStringViewState(state));
			mViewStateStack.push(state);

			// Fire the view state change event to properly clear the IMGUI state
			Engine::EventBasePtr changeviewstate_event (new Engine::EventBase());
			changeviewstate_event->mEventType = EventChangeViewState;
			QueueEvent (changeviewstate_event);
		}
		/** \brief Returns the current ViewState */
		ViewState GetViewState () {
			return mViewStateStack.top();
		}
		/** \brief Removes the top element of the current ViewState stack */
		void PopViewState () {
			// Warning: you must not query for an invalid enum with
			// GetStringENUM_NAME!
			std::string popped_name = GetStringViewState(mViewStateStack.top());
			mViewStateStack.pop();

			std::string current_name ("None");
			if (mViewStateStack.size() > 0)
				current_name = GetStringViewState(mViewStateStack.top());

			Engine::LogDebug("Popped ViewState: %s current %s remaining: %u", popped_name.c_str(), current_name.c_str(), mViewStateStack.size());

			// Fire the view state change event to properly clear the IMGUI state
			Engine::EventBasePtr changeviewstate_event (new Engine::EventBase());
			changeviewstate_event->mEventType = EventChangeViewState;
			QueueEvent (changeviewstate_event);
		}
		/** \brief Removes all elements of the ViewState stack */
		void ResetViewState() {
			Engine::LogDebug ("Resetting ViewState stack");
			while (mViewStateStack.size())
				mViewStateStack.pop();

			// Fire the view state change event to properly clear the IMGUI state
			Engine::EventBasePtr changeviewstate_event (new Engine::EventBase());
			changeviewstate_event->mEventType = EventChangeViewState;
			QueueEvent (changeviewstate_event);
		}

		// \todo [high] add Resource Manager!
		Engine::Sprite mGUIShipSprite;
		Engine::Sprite mAsteroidSprite;
		Engine::Sprite mShipSprite;
		Engine::Sprite mShipThrustSprite;
		Engine::Sprite mShipPartsSprite;
		
		float screen_left;
		float screen_right;
		float screen_top;
		float screen_bottom;

		int button_width;
		int button_height;

		/// \brief can be used to perform some fading, etc.
		float mFadeTimerSecValue;

		virtual bool OnReceiveEvent (const Engine::EventBasePtr &event);
};

}

#endif // _VIEW_H
