#include <stdio.h>
#include <X11/X.h>
#include <X11/keysym.h>
#include <GL/gl.h>
#include <GL/glx.h>
#include <time.h>
#include <zoom/init.h>
#include <zoom/render.h>
#include <zoom/player.h>

Display *disp;
Window wnd;
Atom windele;
int running;
int fullscreen = 0;
static int attributeList[] = {GLX_RGBA, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 1, None};
GLXContext gc;

extern int input;


int main();
void GLXinit();

void GLXinit() {
	char *str = "Zoom";
	XTextProperty name;
	XWMHints wmhints;
	XSizeHints shints;
	XClassHint chint;
	XVisualInfo *vi;
	Colormap cmap;
	XSetWindowAttributes swa;
	Pixmap pixmap;
	Cursor cursor;
	XColor color;

	vi = glXChooseVisual(disp, DefaultScreen(disp), attributeList);

	cmap = XCreateColormap(disp, RootWindow(disp, vi->screen), vi->visual, AllocNone);
	swa.colormap = cmap;
	swa.border_pixel = 0;
	swa.event_mask = PointerMotionMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask;

	wnd = XCreateWindow(disp, RootWindow(disp, vi->screen), 0, 0, 640, 480, 0, vi->depth, InputOutput,
				vi->visual, CWBorderPixel|CWColormap|CWEventMask, &swa);

	chint.res_name = "Zoom";
	chint.res_class = "zoom";
	XSetClassHint(disp, wnd, &chint);
	
	shints.flags = PMaxSize | PMinSize;
	shints.min_width = 640;
	shints.min_height = 480;
	shints.max_width = 640;
	shints.max_height = 480;
	XSetWMNormalHints(disp, wnd, &shints);

	if (XStringListToTextProperty(&str, 1, &name) != 0)
        {
		XSetWMName(disp, wnd, &name);
		XFree(name.value);
	}

	windele = XInternAtom(disp, "WM_DELETE_WINDOW", False);
	XSetWMProtocols(disp, wnd, &windele, 1);

	XMapWindow(disp, wnd);

	color.pixel = WhitePixel(disp, vi->screen);
	XQueryColor(disp, cmap, &color);
	pixmap = XCreatePixmap(disp, wnd, 1, 1, 1);
	cursor = XCreatePixmapCursor(disp, pixmap, pixmap, &color, &color, 0, 0);
	XFreePixmap(disp, pixmap);
	XDefineCursor(disp, wnd, cursor);
	XGrabPointer(disp, wnd, False, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, wnd, None, CurrentTime);
	XWarpPointer(disp, None, wnd, 0, 0, 0, 0, 320, 240);

	gc = glXCreateContext(disp, vi, NULL, True);

	glXMakeCurrent(disp, wnd, gc);

	XFree(vi);

	XSync(disp, 0);
}

int main() {
	unsigned long ticks, delta = 0;
	struct timeval tv;
	XEvent event;
	unsigned long frames = 0, tocks = 0;
	

	disp = XOpenDisplay(0);

	GLXinit();

	running = InitGame();

	gettimeofday(&tv, NULL);
	ticks = tv.tv_usec;
	while(running) {
		while(XPending(disp)) {
			XNextEvent(disp, &event);
			switch(event.type) {
				case ClientMessage:
					if(event.xclient.data.l[0] == windele) running = 0;
					break;
				case ButtonPress:
					input |= INPUT_OPEN;
					break;
				case ButtonRelease:
					if(event.xbutton.button == Button2) input &= ~INPUT_OPEN;
					break;
				case MotionNotify:
					if(event.xmotion.x == 320 && event.xmotion.y == 240) break;
					MouseInput(event.xmotion.x - 320, event.xmotion.y - 240);
					XWarpPointer(disp, None, wnd, 0, 0, 0, 0, 320, 240);
					break;
				case KeyPress:
					switch(XKeycodeToKeysym(disp, event.xkey.keycode, 0)) {
						case XK_Up: case XK_w: input |= INPUT_UP; break;
						case XK_Down: case XK_s: input |= INPUT_DOWN; break;
						case XK_Right: case XK_d: input |= INPUT_RIGHT; break;
						case XK_Left: case XK_a: input |= INPUT_LEFT; break;
						case XK_space: input |= INPUT_OPEN; break;
						case XK_Escape: running = 0; break;
					}
					break;
				case KeyRelease:
					switch(XKeycodeToKeysym(disp, event.xkey.keycode, 0)) {
						case XK_Up: case XK_w: input &= ~INPUT_UP; break;
						case XK_Down: case XK_s: input &= ~INPUT_DOWN; break;
						case XK_Right: case XK_d: input &= ~INPUT_RIGHT; break;
						case XK_Left: case XK_a: input &= ~INPUT_LEFT; break;
						case XK_space: input &= ~INPUT_OPEN; break;
					}
			}
		}
		if(!running) break;
		DoInput(delta);
		Render();
		glXSwapBuffers(disp, wnd);
		XSync(disp, 0);
		gettimeofday(&tv, NULL);
		delta = ((tv.tv_usec + 1000000 - ticks)%1000000)/1000;
		ticks = (ticks + delta*1000) % 1000000;
		
		frames++;
		tocks += delta*1000;
		if(tocks > 1000000) {
			fprintf(stderr, "%u\n", frames);
			frames = 0;
			tocks -= 1000000;
		}
	}
	UninitGame();
	XUngrabPointer(disp, CurrentTime);
	XDestroyWindow(disp, wnd);
	glXDestroyContext(disp, gc);
	XCloseDisplay(disp);
	return 0;
}
