#include "Screen.hpp"


#include <Graphics/Graphics.hpp>

#undef ERROR
#undef WARNING
#include "Error.hpp"

#include <vector>

using std::vector;

Screen::Screen() {
	//occupies the entire screen:
	pixel_extents.max = make_vector< float >(Graphics::screen_x, Graphics::screen_y);
	pixel_extents.min = make_vector< float >(0,0);
	extents.max = make_vector(Graphics::aspectf(), 1.0f);
	extents.min =-make_vector(Graphics::aspectf(), 1.0f);
}

float Screen::aspectf() {
	return extents.size().x / extents.size().y;
}

void Screen::update_screen_mouse_relative(SDL_MouseMotionEvent const &motion, Vector2f &mouse) {
	mouse.x += motion.xrel / pixel_extents.size().x * 2.0f * aspectf();
	mouse.y -= motion.yrel / pixel_extents.size().y * 2.0f;
}

void Screen::update_screen_mouse_absolute(SDL_MouseMotionEvent const &motion, Vector2f &mouse) {
	mouse.x =  (motion.x - pixel_extents.min.x) / (pixel_extents.max.x - pixel_extents.min.x) * 2.0f * aspectf() - aspectf();
	mouse.y =  (motion.y - pixel_extents.min.y) / (pixel_extents.max.y - pixel_extents.min.y) *-2.0f + 1.0f;
}

namespace {
	class Layer {
	public:
		Layer(Screen *_screen) : screen(_screen), quit_flag(false) { }
		Screen *screen;
		bool quit_flag;
	};
	vector< Layer > layers;
};

Uint32 min_ms_per_frame = 1000/100;
Uint32 max_ms_per_frame = 1000/15;

static void run() {
	Uint32 env_t = SDL_GetTicks();
	Uint32 env_et = 0;
	SDL_Event event;
	while (!layers.empty() && !layers.back().quit_flag) {

		Screen *current = layers.back().screen;

		//Find elapsed milliseconds, delaying and clamping as needed.
		env_et = SDL_GetTicks() - env_t;
		while (env_et < min_ms_per_frame) {
			SDL_Delay(min_ms_per_frame - env_et);
			env_et = SDL_GetTicks() - env_t;
		}
		env_t += env_et;

		if (env_et > max_ms_per_frame) env_et = max_ms_per_frame;

		//get and process any new events.
		while (SDL_PollEvent(&event)) {
			current->handle_event(event);
			//add alt-escape as a sort of force-quit:
			if (event.type == SDL_KEYDOWN
				&& event.key.keysym.sym == SDLK_ESCAPE
				&& (event.key.keysym.mod & KMOD_ALT)
			 || event.type == SDL_QUIT) {
				layers.clear(); //global quit!
			}
		}
	
		//update the world
		current->update(env_et / 1000.0f);
	
		//draw the world
		current->draw();

		//swap the drawn world to the front buffer
		SDL_GL_SwapBuffers();
	}

	if (!layers.empty() && layers.back().quit_flag) {
		layers.pop_back();
	}
}

void start_screen(Screen *screen) {
	layers.push_back(Layer(screen));
	run();
}

void quit_screen(Screen *me) {
	if (layers.empty()) {
		ERROR( "trying to quit an empty layer." );
		return;
	}
	if (me != layers.back().screen) {
		ERROR( "trying to quit the wrong screen." );
		return;
	}
	layers.back().quit_flag = true;
}
