/*
	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License version 2 
	as published by the Free Software Foundation.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA


	Copyright (C) 2006  Thierry Berger-Perrin <tbptbp@gmail.com>
*/
/*
	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License version 2
	as published by the Free Software Foundation.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA


	Copyright (C) 2006  Thierry Berger-Perrin <tbptbp@gmail.com>
*/
#ifndef OGL_DRIVER_H
#define OGL_DRIVER_H


#include "specifics.h"

#include "ogl.h"

#include "sys_thread.h"
#include "math_vec.h"	// point_t, meh

#include <vector>	// meh

namespace ui {
	// this is guarded.
	struct inputs_t {
		sys::mutex_t mutex;

		float axis[4];

		struct modifiers_t { uint_t shift : 1, control : 1, alt : 1, altg : 1, menu : 1; } modifiers;

		// discrete events
		enum event_types_t { type_key = 0, type_click = 1 };
		union event_t {
			struct key_t	{ uint64_t type : 4, key : 8; } key;
			struct click_t	{ uint64_t type : 4, button : 9, x : 16, y : 16; } click;
		};
		std::vector<event_t> queue;

		inputs_t() { memset(this, 0, sizeof(inputs_t)); }
	};

	/*
		On doze, only the thread creating a window can receive its message. Weee.
	*/

	struct opaque_t;
	struct window_t: public sys::thread_t {

		inputs_t inputs;

		bool_t valid, should_bail;
		const int inner_width, inner_height;

		opaque_t &opq;

		window_t(const char *display_name, const point_t &res);
		~window_t();


		bool_t init() {
			if (open(inner_width, inner_height)) {
				expose();
				return true;
			}
			else
				return false;
		}

		//int run() { return sys::cpu::set_thread_priority(sys::cpu::thread_priority_pump) && process(); }
		int run() { return process(); }


		// serialized
		bool_t open(const uint_t width, const uint_t height);

		// careful: executes in its own thread
		int process();

		void expose();
		void close();
		void set_title(const char *s);

		void process_click(const int button, const int x, const int y) {
			sys::lock_t lock(inputs.mutex);

			inputs_t::event_t e;
			e.click.type = inputs_t::type_click;
			e.click.button = button;
			e.click.x = x;
			e.click.y = y;
			inputs.queue.push_back(e);
		}

		// immediate (passthrough)
		bool_t process_key(const bool_t keyup, const uint_t key);
		// queued
		void process_key(const char_t key) {
			sys::lock_t lock(inputs.mutex);

			inputs_t::event_t e;
			e.key.type = inputs_t::type_key;
			e.key.key = key;
			inputs.queue.push_back(e);
		}
	};
}

namespace ogl {
	struct context_t {
		#ifdef WINDOWS
			HDC			dc;
			HGLRC		glrc;
		#else
			GLXContext	glrc;
		#endif

		bool_t create(ui::window_t &win);
		void destroy(ui::window_t &win);
		void flip(ui::window_t &win);

		void clear();
	};

	bool_t bootstrap(ui::window_t &, context_t &);
}


#endif
