#include "View.h"
#include "CameraBase.h"
#include "SimpleConsoleOverlay.h"
#include "IMGUIControls.h"
#include "keytable.h"
#include "DrawingsGL.h"

#include "Engine.h"
#include "Physics.h"
#include "Model.h"
#include "Controller.h"
#include "EventBase.h"

#include "Game.h"
#include "ShipEntity.h"
#include "AsteroidEntity.h"
#include "AsteroidsEvents.h"
#include "RocketEntity.h"

#include <GL/gl.h>
#include <GL/glu.h>

// #define DRAW_BOUNDARIES

#ifdef DRAW_BOUNDARIES
	#include "coll2d.h"
	#include "DrawingsGL.h"
#endif

using namespace std;

namespace asteroids {

int View::OnInit (int argc, char* argv[]) {
	ViewBase::OnInit (argc, argv);

	/*
	// We want the console
	mConsoleOverlay = boost::shared_ptr<Engine::SimpleConsoleOverlay> (new Engine::SimpleConsoleOverlay);
	// We also want to display the log bar
	mConsoleOverlay->SetDrawLogBar (true);
	mOverlayManager.Register (mConsoleOverlay, GameStateMainMenu);
	*/

	LoadFont("AldotheApache.ttf size=20 color=#000000");

	button_width = 250;
	button_height = 40;

	// This is a simple star field that makes the game so spacy
	int i;
	for (i = 0; i < 200; i++) {
		BackgroundStar star;
		star.position[0] = rand() / float(RAND_MAX) * 1.2;
		star.position[1] = rand() / float(RAND_MAX) * 1.2;
		star.position[2] = rand() / float(RAND_MAX) * 1.2;

		mBackgroundStars.push_back (star);
	}

	// Editor default variables
	mEditorEntityId = 0;
	mEditorState = EditorStateUnknown;

	mGUIShipSprite.LoadFromPNG(Engine::GetResourceFullPath("/data/textures/ship.png"));
	mGUIShipSprite.SetScale (0.1);

	mAsteroidSprite.LoadFromPNG (Engine::GetResourceFullPath("/data/textures/asteroid.png"));
	mShipSprite.LoadFromPNG (Engine::GetResourceFullPath("/data/textures/ship.png"));

	mShipThrustSprite.LoadFromPNG (Engine::GetResourceFullPath("/data/textures/ship_thrust.png"));
	mShipThrustSprite.SetAnimation (4, 8);

	mShipPartsSprite.LoadFromPNG (Engine::GetResourceFullPath("/data/textures/ship_parts.png"));
	mShipPartsSprite.SetSubSpriteCount (10);

	Engine::RegisterListener (this, EventAccelerateStart);
	Engine::RegisterListener (this, EventAccelerateStop);
	Engine::RegisterListener (this, EventShipExplode);
	Engine::RegisterListener (this, EventPlayerDied);
	Engine::RegisterListener (this, EventGameOver);
	Engine::RegisterListener (this, EventLevelComplete);

	PushViewState (ViewStateMainMenu);

	return 0;
}

void View::OnDestroy() {
	mBackgroundStars.clear();
	mShipPartsEntityIds.clear();

	Engine::ViewBase::OnDestroy();
}

bool View::OnReceiveEvent (const Engine::EventBasePtr &event) {
	switch (event->mEventType) {
		case EventAccelerateStart:
		case EventAccelerateStop:
			if (event->mEventType == EventAccelerateStart)
				mShipThrustSprite.ResetAnimation();

			Engine::LogDebug ("Received Acceleration Event: %d", event->mEventType);
			return true;

			break;
		case EventLevelComplete:
			if (GetModel()->GetGameState() == GameStateRunning) {
				PushViewState(ViewStateLevelComplete);
				GetController()->ResetPlayerEntity();
			}
			break;

		case EventGameOver:
			mFadeTimerSecValue = 2.;

			PopViewState();
			PushViewState(ViewStateGameOver);
			GetController()->ResetPlayerEntity();

			break;
		case EventPlayerDied:
			mFadeTimerSecValue = 2.;
			PushViewState(ViewStatePlayerDied);
			GetController()->ResetPlayerEntity();

			break;
		case EventShipExplode: {
			// This event is fired when the ship explodes. Note: this event is not
			// sufficient for EventPlayerDied!
			Engine::LogDebug ("Received PlayerDied Event: %d", event->mEventType);
		
			// insert sprits that contains parts of the ship
			Engine::EntityBase *ship_entity = Engine::GetEntity (event->mEventUnsignedInt);
			vector3d position = ship_entity->mPhysicState->mPosition;
			vector3d orientation = ship_entity->mPhysicState->mOrientation;
			vector3d velocity = ship_entity->mPhysicState->mVelocity;
			vector3d rel_velocity = event->mVector3d;

			unsigned int i;
			mShipPartsEntityIds.clear();

			for (i = 0; i < mShipPartsSprite.GetSubSpriteCount(); i++) {
				Engine::EntityBase* part_sprite_particle = Engine::CreateEntity (GameEntityTypeShipPart);
				part_sprite_particle->mPhysicState->mPosition = position;
				part_sprite_particle->mPhysicState->mOrientation = orientation;
				vector3d part_velocity (
						rel_velocity[0] * (rand()/float(RAND_MAX)) * 1.7,
						0.,
						rel_velocity[2] * (rand()/float(RAND_MAX)) * 1.5
						);
				part_sprite_particle->mPhysicState->mVelocity = part_velocity;

				part_sprite_particle->mPhysicState->mAngleVelocity = (rand()/float(RAND_MAX) - 0.5 ) * 100.;

				mShipPartsEntityIds.push_back(part_sprite_particle->mId);
			}

			// We do not need the entity anymore
			Engine::KillEntity(event->mEventUnsignedInt);

			return true;

			break;
		}

		default: Engine::LogWarning ("Received Event with type %d but don't know what to do with it!", event->mEventType);
						 break;
	}

	return false;
}

/*
 * Module specific functions
 */
void View::UpdateCamera () {
	mCamera->SetEye (
			0.,
			9.5,
			0.
			);
	mCamera->SetPointOfIntrest (
			0.,
			0.,
			0.
			);
	mCamera->SetUp (
			0.,
			0.,
			-1.
			);

	mCamera->Update ();
}

void View::DrawStars() {
	unsigned int i;
	
	float world_width, world_height;
	world_width = static_cast<Model*>(mModel)->GetWorldWidth();	
	world_height = static_cast<Model*>(mModel)->GetWorldHeight();
	vector3d velocity (1., 0., 0.);

	glPushMatrix();
	glTranslatef(-world_width * 0.5, 0, -world_height * 0.5);
	glColor3f (1., 1., 1.);
	glPointSize(2.);
	glBegin(GL_POINTS);
	float z_value;
	for (i = 0; i < mBackgroundStars.size(); i++) {
//		glPointSize (2. + 300. *mBackgroundStars.at(i).position[1]);
		z_value = mBackgroundStars.at(i).position[1] + 0.1;

		glColor3f (z_value, z_value, z_value);
		glVertex3f (mBackgroundStars.at(i).position[0] * world_width,
				-1.,
				mBackgroundStars.at(i).position[2] * world_height);

		mBackgroundStars.at(i).position -= vector3d(Engine::GetFrameDuration() * 0.7 * mBackgroundStars.at(i).position[1] / world_width, 0., 0.);

		// we move the stars a little more such that they are not blende out too early
		// \todo compute proper bounds from Physics world size!
		if (mBackgroundStars.at(i).position[0] < -0.1)
			mBackgroundStars.at(i).position[0] += 1.2;
		if (mBackgroundStars.at(i).position[0] >= 1.1)
			mBackgroundStars.at(i).position[0] -= 1.2;
	}

	glEnd();
	glPopMatrix();
}

void View::Draw() {
	PreDraw();

	mFadeTimerSecValue -= GetModel()->GetFrameDuration();

	// Actual Drawing
	UpdateCamera ();

	if (mDrawGrid)
		DrawGrid ();

	/*
	if (mDrawAxis)
		DrawAxis ();
	*/

	std::map<unsigned int, Engine::EntityBase*>::iterator entity_iterator;
	Model *game_model = static_cast<Model*> (mModel);
	unsigned int game_state = game_model->GetGameState();

	DrawStars ();

	if ( game_state == GameStateRunning || GetViewState() == ViewStateEditor) {
		DrawWorld ();
	}

	DrawUi ();

	// Perform post-Draw actions
	PostDraw();
}

void View::DrawWorld() {
	std::map<unsigned int, Engine::EntityBase*>::iterator entity_iterator;
	Model *game_model = static_cast<Model*> (mModel);

	ViewBase::DrawWorld();

	for (entity_iterator = game_model->mEntities.begin ();
			entity_iterator != game_model->mEntities.end();
			entity_iterator++) {
		Engine::EntityBase* entity = entity_iterator->second;

		// Perform multiple drawing if the entity is at the border
		Physics* game_physics = (Physics*) game_model->mPhysics;
		float world_width = game_physics->GetWorldWidth();
		float world_height = game_physics->GetWorldHeight();

		// if we are in Edit mode and are currently editing the velocity we must
		// make sure that we display it
		if (GetViewState() == ViewStateEditor) {
			if (mEditorState == EditorStateEntityVelocity) {
				DrawVector (entity->mPhysicState->GetPosition(),
						entity->mPhysicState->GetPosition() + entity->mPhysicState->GetVelocity());
			}
		}

		// Drawing at the original position:
		glPushMatrix ();
		glTranslatef (entity->mPhysicState->mPosition[0],
				entity->mPhysicState->mPosition[1],
				entity->mPhysicState->mPosition[2]);

		glRotatef(entity->mPhysicState->mOrientation[0], 0., 0., 1.);
		glRotatef(entity->mPhysicState->mOrientation[1], 0., 1., 0.);
		glRotatef(entity->mPhysicState->mOrientation[2], 1., 0., 0.);

		glColor3f (1., 1., 1.);
		DrawEntity (entity);

		glPopMatrix ();

		// If we move out the right side
		if (entity->mPhysicState->mPosition[0] + entity->mPhysicState->mRadius * 2 
				>= world_width * 0.5) {
			glPushMatrix ();
			glTranslatef (entity->mPhysicState->mPosition[0] - world_width,
					entity->mPhysicState->mPosition[1],
					entity->mPhysicState->mPosition[2]);

			glRotatef(entity->mPhysicState->mOrientation[0], 0., 0., 1.);
			glRotatef(entity->mPhysicState->mOrientation[1], 0., 1., 0.);
			glRotatef(entity->mPhysicState->mOrientation[2], 1., 0., 0.);

			glColor3f (1., 1., 1.);
			DrawEntity (entity);

			glPopMatrix ();
		}

		// if we move out the left side
		if (entity->mPhysicState->mPosition[0] - entity->mPhysicState->mRadius * 2
				< - world_width * 0.5) {
			glPushMatrix ();
			glTranslatef (entity->mPhysicState->mPosition[0] + world_width,
					entity->mPhysicState->mPosition[1],
					entity->mPhysicState->mPosition[2]);

			glRotatef(entity->mPhysicState->mOrientation[0], 0., 0., 1.);
			glRotatef(entity->mPhysicState->mOrientation[1], 0., 1., 0.);
			glRotatef(entity->mPhysicState->mOrientation[2], 1., 0., 0.);

			glColor3f (1., 1., 1.);
			DrawEntity (entity);

			glPopMatrix ();
		}

		// If we move out the bottom side
		if (entity->mPhysicState->mPosition[2] + entity->mPhysicState->mRadius * 2
				>= world_height * 0.5) {

			glPushMatrix ();
			glTranslatef (entity->mPhysicState->mPosition[0],
					entity->mPhysicState->mPosition[1],
					entity->mPhysicState->mPosition[2] - world_height);

			glRotatef(entity->mPhysicState->mOrientation[0], 0., 0., 1.);
			glRotatef(entity->mPhysicState->mOrientation[1], 0., 1., 0.);
			glRotatef(entity->mPhysicState->mOrientation[2], 1., 0., 0.);

			glColor3f (1., 1., 1.);
			DrawEntity (entity);

			glPopMatrix ();
		}

		// if we move out the left side
		if (entity->mPhysicState->mPosition[2] - entity->mPhysicState->mRadius * 2
				< - world_height* 0.5) {
			glPushMatrix ();
			glTranslatef (entity->mPhysicState->mPosition[0],
					entity->mPhysicState->mPosition[1],
					entity->mPhysicState->mPosition[2] + world_height);

			glRotatef(entity->mPhysicState->mOrientation[0], 0., 0., 1.);
			glRotatef(entity->mPhysicState->mOrientation[1], 0., 1., 0.);
			glRotatef(entity->mPhysicState->mOrientation[2], 1., 0., 0.);

			glColor3f (1., 1., 1.);
			DrawEntity (entity);

			glPopMatrix ();
		}
	}
}

/*
 * Userinterface
 */
void View::DrawUi () {
	glClearColor (0.1, 0.1, 0.1, 1.);

	screen_right = static_cast<float> (Engine::GetWindowWidth());
	screen_bottom = static_cast<float> (Engine::GetWindowHeight());

	// we switch to orthographic projection and draw the contents of the 2d 
	// overlay on top of the previous drawings
	glMatrixMode (GL_PROJECTION);
	glPushMatrix ();
	glLoadIdentity ();

	// first we have to get the size of the current viewport to set up the
	// orthographic projection correctly
	GLint viewport[4];
	glGetIntegerv(GL_VIEWPORT, viewport);
	gluOrtho2D (viewport[0], viewport[2], viewport[3], viewport[1]);

	glMatrixMode (GL_MODELVIEW);
	glPushMatrix ();
	glLoadIdentity ();

	unsigned int game_state = GetModel()->GetGameState();

	SelectFont("console.ttf");
	SetFontJustification (Engine::FontJustificationLeft);

	ViewState current_view_state = GetViewState(); 

	SelectFont ("console.ttf size=12");
	Engine::GUI::Label (99999, GetStringViewState(current_view_state), 8, 16);

	switch (current_view_state) {
		case ViewStateMainMenu:
			DrawUiMainMenu();
			break;
		case ViewStateGameRunning:
			DrawUiGameRunning();
			break;
		case ViewStatePaused:
			DrawUiGamePaused();
			break;
		case ViewStatePlayerDied:
			DrawUiPlayerDied();
			break;
		case ViewStateLevelComplete:
			DrawUiLevelComplete();
			break;
		case ViewStateShowHighscore:
			DrawUiHighscore();
			break;
		case ViewStateOptions:
			DrawUiOptions();
			break;
		case ViewStateEnterPlayername:
			DrawUiEnterPlayername();
			break;
		case ViewStateGameOver:
			DrawUiGameOver();
			break;
		case ViewStateEditor:
			DrawUiEditor();
			break;
		default:
			Engine::LogWarning ("Trying to draw unknown ViewState: %s (%d)", 
					GetStringViewState (game_state), game_state);
			break;
	}

	glPopMatrix ();

	glMatrixMode (GL_PROJECTION);
	glPopMatrix ();

	glMatrixMode (GL_MODELVIEW);
}

void View::DrawPageTitle (const std::string& title) {
	SelectFont("console.ttf size=46 color=#808080");
	float width, height;
	DrawGLStringMeasure(title.c_str(), &width, &height);

	float xpos = (screen_right - width) * 0.5 - 40;
	float ypos = 180;
	Engine::GUI::Label (4, title.c_str(), xpos - 2, ypos + 2);

	SelectFont("console.ttf size=46 color=#ffffff");
	Engine::GUI::Label (4, title.c_str(), xpos, ypos);
}

void View::DrawUiMainMenu() {
	DrawPageTitle ("Asteroids");

	SelectFont("console.ttf size=23");
	if (Engine::GUI::Button (1, "New Game", screen_right * 0.5 - 100, 200, button_width, button_height)) {
		PushViewState(ViewStateEnterPlayername);
	}

	if (Engine::GUI::Button (2, "Options", screen_right * 0.5 - 100, 250, button_width, button_height)) {
		PushViewState (ViewStateOptions);
	}

	if (Engine::GUI::Button (3, "Highscores", screen_right * 0.5 - 100, 300, button_width, button_height)) {
		PushViewState(ViewStateShowHighscore);
	}

	if (Engine::GUI::Button (6, "E", screen_right - 48, 20, 32, button_height)) {
		PushViewState(ViewStateEditor);
		GetController()->ResetLevel();
	}

	if (Engine::GUI::Button (4, "Quit", screen_right * 0.5 - 100, 380, button_width, button_height)) {
		Engine::RunCommand("quit");
	}
}

void View::DrawUiGameRunning() {
	// We choose a different font and also draw it aligned to the right as this
	// looks nicer with the points
	SelectFont ("AldotheApache.ttf size=20 color=#ffffff");
	SetFontJustification (Engine::FontJustificationRight);

	std::ostringstream out_stream;
	out_stream << GetModel()->GetPlayerLives() << " x ";
	DrawGLString (screen_right - 64, screen_bottom - 20, out_stream.str().c_str()); 

	mGUIShipSprite.DrawAt2D (screen_right - 32 - 10, screen_bottom - 16);

	out_stream.str("");
	out_stream << GetModel()->GetPoints();
	DrawGLString (screen_right - 30, 40, out_stream.str().c_str()); 

	// revert the font justification
	SetFontJustification (Engine::FontJustificationLeft);

	if (Engine::GUI::CheckKeyPress(SDLK_ESCAPE)) {
		PushViewState(ViewStatePaused);
		GetModel()->SetGameState(GameStatePaused);
	}
}

void View::DrawUiGameOver() {
	DrawPageTitle ("Game Over");

	SelectFont("console.ttf size=23 color=#ffffff");

	if (GetModel()->GetPlayerLives() == 0) {
		Engine::GUI::LabelCentered(5,
				"That was pathetic!",
				screen_right * 0.5,
				screen_bottom * 0.5 - 8);
	} else {
		Engine::GUI::LabelCentered (6, "You earned yourself the",
				screen_right * 0.5,
				screen_bottom * 0.5 - 32);
		Engine::GUI::LabelCentered (7, "You Rock(TM) award.",
				screen_right * 0.5,
				screen_bottom * 0.5 + 0);
		Engine::GUI::LabelCentered (8, "Go tell your friends.",
				screen_right * 0.5,
				screen_bottom * 0.5 + 32);
	}

	if (mFadeTimerSecValue > 0.)
		return;

	if (Engine::GUI::Button (2, "Continue...",
				(screen_right - button_width) * 0.5,
				screen_bottom * 0.5 + 80, button_width, button_height)) {
		// We do not want the background to show the remaining bits of the game
		GetModel()->SetGameState(GameStatePaused);

		PopViewState();
		PushViewState(ViewStateShowHighscore);
	}
}

void View::DrawUiLevelComplete() {
	DrawPageTitle ("Level Complete!");

	SelectFont ("console.ttf size=23");

	if(Engine::GUI::Button (1, "Next level ...", (screen_right - button_width) * 0.5, screen_bottom * 0.5 + 60, button_width, button_height)) {
		PopViewState();

		// we have to take care when we are testing the level to not proceed to
		// the next level...
		if (GetViewState() == ViewStateEditor) {
			GetModel()->SetGameState(GameStatePaused);

			if (mEditorState == EditorStateTest) {
				GetModel()->DoLoadLevel("level_edit_temp.txt");
				mEditorState = EditorStateUnknown;
			}
		} else {
			GetModel()->ProceedToNextLevel();
		}
	}
}

void View::DrawUiGamePaused() {
	DrawPageTitle ("Game Paused");
	SelectFont ("console.ttf size=23");

	if (Engine::GUI::Button (1, "Resume Game", screen_right * 0.5 - 100, 200, button_width, button_height)) {
		PopViewState();
		GetModel()->SetGameState(GameStateRunning);
	}

	if (Engine::GUI::Button (2, "Options", screen_right * 0.5 - 100, 250, button_width, button_height)) {
		PushViewState (ViewStateOptions);
	}

	if (Engine::GUI::Button (3, "Abort Game", screen_right * 0.5 - 100, 300, button_width, button_height)) {
		ResetViewState();

		PushViewState(ViewStateMainMenu);
		GetModel()->SetGameState(GameStatePaused);
	}

	if (Engine::GUI::Button (4, "Quit", screen_right * 0.5 - 100, 380, button_width, button_height)) {
		Engine::RunCommand("quit");
	}
}

void View::DrawUiPlayerDied() {
	DrawPageTitle ("You died!");
	SelectFont ("console.ttf size=23");

	if (mFadeTimerSecValue > 0.)
		return;

	if (Engine::GUI::Button (1, "Continue", screen_right * 0.5 - 100, 380, button_width, button_height)) {
		PopViewState();

		// we have to take care when we are testing the level to not proceed to
		// the next level...
		if (GetViewState() == ViewStateEditor) {
			GetModel()->SetGameState(GameStatePaused);

			if (mEditorState == EditorStateTest) {
				GetModel()->DoLoadLevel("level_edit_temp.txt");
				mEditorState = EditorStateUnknown;
			}
		} else {
			GetModel()->ReloadLevel();
			GetModel()->SetGameState(GameStateRunning);
		}
	}
}

/** \brief Draws an entry in the form <name> .... <points>
 *
 * The amount of dots is also computed within this function. Not necessarily
 * fast, however it works for now.
 */
void View::DrawHighscoreEntry (float x, float y, float entry_width, const std::string &name, unsigned int points) {
	const float width_buffer = 30.;
	float width, height;
	float name_width, points_value_width;

	// Measure and draw the name
	DrawGLStringMeasure (name.c_str(), &name_width, &height);
	name_width = fabsf(name_width);
	Engine::DrawGLString ( x, y, name.c_str());

	// Compute the width of the points value when it is printed out
	std::ostringstream points_value_stream;
	points_value_stream << points;
	DrawGLStringMeasure (points_value_stream.str().c_str(), &points_value_width, &height);
	points_value_width = fabsf(points_value_width);

	// Compute the amount of dots. This is done by iteratively adding a dot '.'
	// to a stream and check whether it has the desired width.
	float dots_width = 0.;
	std::ostringstream dots_stream;

	while (ceil(name_width) + dots_width + points_value_width + width_buffer < entry_width) {
		dots_stream << ".";
		DrawGLStringMeasure (dots_stream.str().c_str(), &dots_width, &height);
		dots_width = fabsf(dots_width);
	}

	// Drawing of the dots and the points value
	Engine::DrawGLString ( x + entry_width - points_value_width - dots_width - 10, y, dots_stream.str().c_str());
	Engine::DrawGLString ( x + entry_width - points_value_width, y, points_value_stream.str().c_str());
}

void View::DrawUiHighscore() {
	DrawPageTitle ("Highscores");
	SelectFont ("console.ttf size=23");


	unsigned int entry_length = 32;
	float char_width, height;
	DrawGLStringMeasure ("M", &char_width, &height);
	height = fabsf(height);
	float entry_width = fabsf(char_width * entry_length);
	float x = screen_right * 0.5 - entry_width * 0.5;
	float y = screen_bottom * 0.5 - 8 - 128;

	// then we do the drawings
	y += 60;
	std::list<Model::HighscoreEntry>::iterator highscore_iter = GetModel()->mHighscoreList.begin();

	SetFontJustification(Engine::FontJustificationLeft);

	unsigned int i = 0;
	while (highscore_iter != GetModel()->mHighscoreList.end()) {
		// Check whether we have to highlight an entry (such as when entering
		// the name)
		if (GetModel()->mNewestHighscoreEntryIndex < GetModel()->mHighscoreList.size()
				&& GetModel()->mNewestHighscoreEntryIndex == i) {
			// we highlight the newest entry
			SelectFont("console.ttf color=#e8d500 size=23");
		} else {
			SelectFont("console.ttf color=#ffffff size=23");
		}
		DrawHighscoreEntry ( x, y, entry_width, highscore_iter->name, highscore_iter->points);

		// go down one line
		y += height * 1.3;

		i++;
		highscore_iter++;
	}

	if (Engine::GUI::Button (1, "Back to Menu", screen_right * 0.5 - 250 * 0.5, y + 16, button_width, button_height)) {
		PopViewState();
	}
}

void View::DrawUiOptions() {
	DrawPageTitle ("Options");
	SelectFont ("console.ttf size=23");

	Engine::GUI::Label (10, "Effects Volume: ", screen_right * 0.5 - 150, 240);

	float effects_volume = Engine::GetEffectsVolume();
	if (Engine::GUI::VerticalSlider (1, screen_right * 0.5 - 100, 250, 250, 16, 0., 1., effects_volume)) {
		Engine::LogDebug ("Setting effects volume to: %f", effects_volume);
		Engine::SetEffectsVolume(effects_volume);
	}

	Engine::GUI::Label (11, "Music Volume: ", screen_right * 0.5 - 150, 300);

	float music_volume = Engine::GetMusicVolume();
	if (Engine::GUI::VerticalSlider (2, screen_right * 0.5 - 100, 310, 250, 16, 0., 1., music_volume)) {
		Engine::LogDebug ("Setting music volume to: %f", music_volume);
		Engine::SetMusicVolume(music_volume);
	}


	if (Engine::GUI::Button (5, "Back", screen_right * 0.5 - 100, 380, button_width, button_height)) {
		PopViewState();
	}
}

void View::DrawUiEnterPlayername() {
	DrawPageTitle ("Asteroids");
	SelectFont ("console.ttf size=23");
	
	// Enter your name
	std::string player_name = GetModel()->GetPlayerName();

	SelectFont("console.ttf size=23");
	Engine::GUI::Label (1, "Enter your name: ", screen_right * 0.5 - 220, 250);

	if (Engine::GUI::LineEdit (2, screen_right * 0.5 + 20, 238, player_name, 16)) {
		GetModel()->SetPlayerName(player_name);
	}

	if (Engine::GUI::Button (3, "Start Game", screen_right - 180 - 20, 500, 180, 40)) {
		PopViewState();
		PushViewState(ViewStateGameRunning);
		GetModel()->OnNewGame();
		GetModel()->SetGameState(GameStateRunning);
	}

	if (Engine::GUI::Button (5, "Back", 20, 500, 180, 40)) {
		PopViewState();
	}
}

void View::DrawUiEditor() {
//	DrawPageTitle ("Editor");
	SelectFont ("console.ttf size=23");

	// The close button
	if (Engine::GUI::Button (1, "X", screen_right - 48, 20, 32, button_height) 
			|| Engine::GUI::CheckKeyPressed(SDLK_ESCAPE)) {

		if (mEditorState == EditorStateTest) {
			mEditorState = EditorStateUnknown;

			GetModel()->DoLoadLevel("level_edit_temp.txt");
			GetModel()->SetGameState(GameStatePaused);
			return;
		} else {
			PopViewState();
		}
	}

	if (mEditorState != EditorStateTest) {
		if (Engine::GUI::Button (2, "Add", 30, 20, 50, button_height)) {
			mEditorState = EditorStateAddEntity;
			Engine::LogDebug ("Editor state now Add");
			return;
		}

		if (Engine::GUI::Button (3, "Del", 85, 20, 50, button_height)) {
			mEditorState = EditorStateDelEntity;
			Engine::LogDebug ("Editor state now Del");
			return;
		}

		if (Engine::GUI::Button (4, "Move", 140, 20, 65, button_height)) {
			mEditorState = EditorStateMoveEntity;
			Engine::LogDebug ("Editor state now Move");
			return;
		}

		if (Engine::GUI::Button (5, "Spd", 210, 20, 50, button_height)) {
			mEditorState = EditorStateEntityVelocity;
			Engine::LogDebug ("Editor state now Add");
			return;
		}

		if (Engine::GUI::Button (6, "Save", 265, 20, 65, button_height)) {
			mEditorState = EditorStateSave;
			Engine::LogDebug ("Editor state now Save");
			return;
		}

		if (Engine::GUI::Button (7, "Load", 335, 20, 65, button_height)) {
			mEditorState = EditorStateLoad;
			Engine::LogDebug ("Editor state now Load");
			return;
		}

		// we only show the Test button when there is actually something to play
		// (i.e. a player entity and at least one asteroid)
		if (GetModel()->GetPlayerEntityId() != 0 
				&& GetModel()->mAsteroids.size() > 0) {
			if (Engine::GUI::Button (8, "Test", 405, 20, 64, button_height)) {
				mEditorState = EditorStateTest;

				GetModel()->DoSaveLevel("level_edit_temp.txt");
				GetModel()->SetGameState(GameStateRunning);
			}
		}
	}

	std::ostringstream mouse_pos_str;
	vector3d mouse_world_pos;
	Controller* controller = GetController();

	controller->GetMouseWorldPosition(mouse_world_pos);
	mouse_pos_str << mouse_world_pos[0] << "," << mouse_world_pos[2];

	if (mEditorState == EditorStateAddEntity) {
		SelectFont ("console.ttf size=12");
		Engine::GUI::Label (9999, "Adding", 128, 16);

		if (Engine::GUI::CheckKeyPressed(MouseButtonLeft)) {
			// if there is no entity so far we create a player, otherwise we create
			// an asteroid

			Engine::EntityBase* entity = NULL;
			if (GetModel()->GetPlayerEntityId() != Engine::NullEntityId) {
				entity = Engine::CreateEntity(GameEntityTypeAsteroid);
				entity->mPhysicState->SetVelocity (vector3d (0., 0., -1.));
			} else {
				entity = Engine::CreateEntity(GameEntityTypeShip);
				GetModel()->SetPlayerEntityId(entity->mId);
				entity->mPhysicState->SetOrientation (vector3d (0., 90., 0.));
			}

			// Now we want to insert an Asteroid at the given position
			entity->mPhysicState->SetPosition (vector3d (mouse_world_pos[0], 0., mouse_world_pos[2]));
		}
	}

	if (mEditorState == EditorStateDelEntity) {
		SelectFont ("console.ttf size=12");
		Engine::GUI::Label (9999, "Deleting", 128, 16);

		if (Engine::GUI::CheckKeyPressed(MouseButtonLeft)) {
			// Check if there is an entity near the given position
			Engine::EntityBase* entity = Engine::GetEntityAt (mouse_world_pos);

			if (entity && entity->mType == GameEntityTypeAsteroid) {
				Engine::LogMessage ("Killing entity with id %u", entity->mId);
				GetModel()->UnregisterEntity (entity->mId);
			}
		}
	}

	if (mEditorState == EditorStateMoveEntity) {
		SelectFont ("console.ttf size=12");
		Engine::GUI::Label (9999, "Moving", 128, 16);

		if (Engine::GUI::CheckKeyPress(MouseButtonLeft)) {
			// Check if there is an entity near the given position
			Engine::EntityBase* asteroid = Engine::GetEntityAt (mouse_world_pos);
			if (asteroid) {
				mEditorEntityId = asteroid->mId;
			}
		}

		if (mEditorEntityId != 0) {
			Engine::EntityBase* asteroid = Engine::GetEntity (mEditorEntityId);
			asteroid->mPhysicState->SetPosition (mouse_world_pos);
		}

		if (!Engine::GUI::CheckKeyPress(MouseButtonLeft)) {
			if (mEditorEntityId != 0) {
				mEditorEntityId = 0;
			}
		}
	}

	if (mEditorState == EditorStateEntityVelocity) {
		SelectFont ("console.ttf size=12");
		Engine::GUI::Label (9999, "Velocity", 128, 16);

		if (mEditorEntityId == 0) {
			if (Engine::GUI::CheckKeyPress(MouseButtonLeft)) {
				// Check if there is an entity near the given position
				Engine::EntityBase* asteroid = Engine::GetEntityAt (mouse_world_pos);
				if (asteroid) {
					mEditorEntityId = asteroid->mId;
				}
			}
		}

		if (mEditorEntityId != 0) {
			Engine::EntityBase* asteroid = Engine::GetEntity (mEditorEntityId);
	
			vector3d new_velocity = mouse_world_pos - asteroid->mPhysicState->GetPosition();
			new_velocity[1] = 0.;
			asteroid->mPhysicState->SetVelocity (new_velocity);

			if (!Engine::GUI::CheckKeyPress(MouseButtonLeft)) {
				if (mEditorEntityId != 0) {
					mEditorEntityId = 0;
				}
			}
		}
	}

	if (mEditorState == EditorStateSave) {
		glColor3f (0.2, 0.2, 0.2);
		Engine::GUI::DrawRoundedBlock (140, 150, screen_right - 280, 200);
		Engine::GUI::Label (9999, "Saving", 128, 16);
		SelectFont ("console.ttf size=23");

		Engine::GUI::Label(51, "Filename: ", 145, 180);
		std::string level_name = GetModel()->GetLevelName();

		glColor3f (1., 1., 1.);
		if (Engine::GUI::LineEdit(52, 145, 210, level_name, 32))
			GetModel()->SetLevelName(level_name);

		if (Engine::GUI::Button (54, "Save", 145, 300, button_width, button_height)) {
			GetModel()->DoSaveLevel((level_name + std::string(".txt")).c_str());
			Engine::LogMessage ("Save");
			mEditorState = EditorStateUnknown;
		}

		if (Engine::GUI::Button (55, "Cancel", screen_right - 140 - 5 - button_width, 300, button_width, button_height))
			mEditorState = EditorStateUnknown;
	}

	if (mEditorState == EditorStateLoad) {
		glColor3f (0.2, 0.2, 0.2);
		Engine::GUI::DrawRoundedBlock (140, 150, screen_right - 280, 200);
		Engine::GUI::Label (9999, "Loading", 128, 16);
		SelectFont ("console.ttf size=23");

		Engine::GUI::Label(51, "Filename: ", 145, 180);
		std::string level_name = GetModel()->GetLevelName();

		glColor3f (1., 1., 1.);
		if (Engine::GUI::LineEdit(52, 145, 210, level_name, 32))
			GetModel()->SetLevelName(level_name);

		if (Engine::FileExists (level_name + std::string(".txt"))) {
			if (Engine::GUI::Button (54, "Load", 145, 300, button_width, button_height)) {
				GetModel()->DoLoadLevel((level_name + std::string(".txt")).c_str());
				Engine::LogMessage ("Load");
				mEditorState = EditorStateUnknown;
			}
		}

		if (Engine::GUI::Button (55, "Cancel", screen_right - 140 - 5 - button_width, 300, button_width, button_height))
			mEditorState = EditorStateUnknown;
	}

	if (Engine::GUI::CheckKeyPressed(MouseButtonRight)
			|| Engine::GUI::CheckKeyPressed(SDLK_ESCAPE) ) {
		mEditorState = EditorStateUnknown;
	}
}

/*
 * Entities
 */
void View::DrawEntity (Engine::EntityBase *entity) {
	if (entity->mType == GameEntityTypeAsteroid)
		DrawAsteroid ((AsteroidEntity*) entity);
	else if (entity->mType == GameEntityTypeShip)
		DrawShip ((ShipEntity*) entity);
	else if (entity->mType == GameEntityTypeRocket)
		DrawRocket ((RocketEntity*) entity);
	else if (entity->mType == GameEntityTypeShipPart)
		DrawShipPart (entity);
	else {
		Engine::LogError ("Cannot draw entity: unknown type '%d'", entity->mType);
	}

}

/// \todo: Update of the animation ??
void View::DrawShip (ShipEntity *ship) {
	if (!ship->mAlive)
		return;

	mShipSprite.SetScale (2. * ship->mPhysicState->mRadius / mShipSprite.GetHeight());
	mShipThrustSprite.SetScale (2. * ship->mPhysicState->mRadius / mShipSprite.GetHeight());

	if (ship->mState == ShipEntity::Accelerating) {
		mShipThrustSprite.UpdateAnimation (Engine::GetFrameDuration());
		mShipThrustSprite.DrawAt(-0.5, 0., 0.);
	}

	mShipSprite.DrawAt(0., 0., 0.);

#ifdef DRAW_BOUNDARIES
	glColor3f (1., 1., 1.);
	DrawCircle (ship->mPhysicState->mRadius, 20);	
#endif
}

void View::DrawAsteroid (AsteroidEntity *asteroid) {
	mAsteroidSprite.SetScale (2. * asteroid->mPhysicState->mRadius / mAsteroidSprite.GetWidth());
	mAsteroidSprite.DrawAt(0., 0., 0.);

#ifdef DRAW_BOUNDARIES
	glColor3f (1., 1., 1.);
	DrawCircle (asteroid->mPhysicState->mRadius, 20);
#endif	
}

void View::DrawRocket (RocketEntity *rocket) {
	glColor3f (1., 1., 1.);
	glBegin (GL_QUADS);
	glVertex3f (-0.25, 0., 0.05);
	glVertex3f (0.05, 0., 0.05);
	glVertex3f (0.05, 0., -0.05);
	glVertex3f (-0.25, 0., -0.05);
	glEnd ();
}

void View::DrawShipPart (Engine::EntityBase *entity) {
	unsigned int i;
	mShipPartsSprite.SetScale (1. / mShipSprite.GetHeight());

	for (i = 0; i < mShipPartsEntityIds.size(); i++) {
		if (mShipPartsEntityIds.at(i) == entity->mId) {
			mShipPartsSprite.DrawSubAt (i, 0., 0., 0.);
		}
	}
#ifdef DRAW_BOUNDARIES
	glColor3f (1., 1., 1.);
	DrawCircle (entity->mPhysicState->mRadius, 20);
#endif
}

}
