#ifndef GTKWINDOW_HXX_
#define GTKWINDOW_HXX_
#include <gtkmm.h>
#include <iostream>
#include "Renderer.hxx"
#include "./camera/PerspectiveCamera.hxx"
#include "./vector/Vec3f.hxx"

class GTKWindow : public Gtk::Window {
private:
	Vec3f pos;
	Vec3f dir;
	Renderer *renderer;
	unsigned int resX;
	unsigned int resY;
	Vec3f* vImage;
	guint8* pixels;
	Gtk::Image *image;
	Glib::RefPtr<Gdk::Pixbuf> img;
	static const float stepsize = 0.05f;

	void RenderFrame() {
		std::cout << "Camera [" << pos << "; " << dir << "]" << std::endl;
		Camera *camera = new PerspectiveCamera(pos,dir,Vec3f(0,1,0),60, resX, resY);
		renderer->RenderFrame(camera,vImage);
	}

public:
	GTKWindow() {
		signal_key_press_event().connect(sigc::mem_fun(*this, &GTKWindow::on_key_pressed));

		show_all_children();
	}

	~GTKWindow() {};

	void SetRenerer(Renderer* renderer) {
		this->renderer = renderer;
	}

	void SetPosition(Vec3f pos) {
		this->pos = pos;
	}

	void SetDirection(Vec3f dir) {
		this->dir = dir;
	}

	void SetImage(Vec3f image[]) {
		this->vImage = image;
	}

	void SetPixels(guint8 *pixels) {
		this->pixels = pixels;
	}

	void Initialize(unsigned int resX, unsigned int resY) {
		this->resX = resX;
		this->resY = resY;

		img = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, false, 8, resX, resY);
		img->fill(0x000000);
		pixels = img->get_pixels();
		image = new Gtk::Image(img);

		this->add(*image);
		image->show();
	}

	// --------------------------------------------------------------------------
	void Repaint() {    
		for (unsigned int y=0; y < resY; y++) {
			for (unsigned int x=0; x < resX; x++) {
				unsigned int pos = y * resX + x;

				Vec3f c = vImage[pos];

				pixels[(resX*resY*3) - (pos * 3)]     = guint8(int(c.x()*255.0f));
				pixels[(resX*resY*3) - (pos * 3) + 1] = guint8(int(c.y()*255.0f));
				pixels[(resX*resY*3) - (pos * 3) + 2] = guint8(int(c.z()*255.0f));
			}
		}

		image->queue_draw();
	}

protected:
	bool on_key_pressed(GdkEventKey* event) {
		if(!event) {
			return false;
		}

		bool repaint = true;

		switch(event->keyval) {
		case GDK_w:
			std::cout << "position +Z" << std::endl;
			pos += Vec3f(0,0,stepsize);
			break;
		case GDK_s:
			std::cout << "position -Z" << std::endl;
			pos -= Vec3f(0,0,stepsize);
			break;
		case GDK_a:
			std::cout << "position -X" << std::endl;
			pos -= Vec3f(stepsize,0,0);
			break;
		case GDK_d:
			std::cout << "position +X" << std::endl;
			pos += Vec3f(stepsize,0,0);
			break;
		case GDK_q:
			std::cout << "position -Y" << std::endl;
			pos -= Vec3f(0,stepsize,0);
			break;
		case GDK_e:
			std::cout << "position +Y" << std::endl;
			pos += Vec3f(0,stepsize,0);
			break;
		case GDK_i:
			std::cout << "direction +Y" << std::endl;
			dir += Vec3f(0,stepsize,0);
			break;
		case GDK_k:
			std::cout << "direction -Y" << std::endl;
			dir -= Vec3f(0,stepsize,0);
			break;
		case GDK_j:
			std::cout << "direction -X" << std::endl;
			dir -= Vec3f(stepsize,0,0);
			break;
		case GDK_l:
			std::cout << "direction +X" << std::endl;
			dir += Vec3f(stepsize,0,0);
			break;
		case GDK_u:
			std::cout << "direction -Z" << std::endl;
			dir -= Vec3f(0,0,stepsize);
			break;
		case GDK_o:
			std::cout << "direction +Z" << std::endl;
			dir += Vec3f(0,0,stepsize);
			break;
		default:
			std::cerr << "unrecognized key" << std::endl;
			repaint = false;
		}

		if(repaint) {
			RenderFrame();
			Repaint();
		}

		// Returning true would stop the event now
		return false;
	}
};

#endif /*GTKWINDOW_HXX_*/