#include <../arch/arch.h>
#include <../arch/common/glctx.h>

vboolean autowarp = false;
#include "dumpevt.c"

#include <GL/glx.h>

typedef struct x11_gl_context_s
{
	ARCH_COMMON_GL_CONTEXT_FIELDS
	XVisualInfo *visual_info;
	GLXContext glx_context;
}	x11_gl_context_t, *x11_gl_context_p;

x11_gl_context_p gl_context = NULL;

void V_GLOBAL
x11_end_frame(x11_gl_context_p gl_context)
{
	x11_display_connection_p cn = &x11_display_connection;
	glXSwapBuffers(cn->dpy, gl_context->wnd->wnd);
}

V_LOCAL void
x11_shutdown_gl(x11_gl_context_p gl_context)
{
	x11_display_connection_p cn = &x11_display_connection;
	if(gl_context->glx_context)
	{
		glXMakeCurrent(cn->dpy, None, NULL);
		glXDestroyContext(cn->dpy, gl_context->glx_context);
		gl_context->glx_context = NULL;
	}
	if(gl_context->visual_info)
	{
		XFree(gl_context->visual_info);
		gl_context->visual_info = NULL;
	}
	ARCH_CLEAR_COMMON_GL_CONTEXT_FIELDS(gl_context);
}

vboolean
x11_init_gl(char *caption,
	int x, int y, int width, int height,
	vboolean fullscreen,
	vboolean can_resize,
	vboolean need_depth, vboolean need_stencil, vboolean need_dst_alpha)
{
	ARCH_CALLER_NAME(vglInit)
	GLfloat aspect;
	int visinfo_class;
	int attrib[64], *aptr = attrib;
	x11_display_connection_p cn;
	if(gl_context)
		x11_shutdown_gl(gl_context);
	else
		gl_context = (x11_gl_context_p)memAllocZ(sizeof(x11_gl_context_t));
	if(!gl_context)
		return false;
	cn = x11_open_connection();
	if(!cn)
		return false;
	*aptr++ = GLX_RGBA;
	*aptr++ = GLX_DOUBLEBUFFER;
	*aptr++ = GLX_RED_SIZE;
	*aptr++ = 1;
	*aptr++ = GLX_GREEN_SIZE;
	*aptr++ = 1;
	*aptr++ = GLX_BLUE_SIZE;
	*aptr++ = 1;
	*aptr = None;
	if(need_depth)
	{
		*aptr++ = GLX_DEPTH_SIZE;
		*aptr++ = 1;
		*aptr = None;
	}
	if(need_stencil)
	{
		*aptr++ = GLX_STENCIL_SIZE;
		*aptr++ = 1;
		*aptr = None;
	}
	if(need_dst_alpha)
	{
		*aptr++ = GLX_ALPHA_SIZE;
		*aptr++ = 1;
		*aptr = None;
	}
	gl_context->visual_info = glXChooseVisual(cn->dpy, cn->scrnum, attrib);
	if(!gl_context->visual_info)
	{
		ARCH_ERROR("glXChooseVisual() failed");
		goto err_exit;
	}
#if defined(__cplusplus) || defined(c_plusplus)
	visinfo_class = gl_context->visual_info->c_class;
#else
	visinfo_class = gl_context->visual_info->class;
#endif
	if(visinfo_class != DirectColor && visinfo_class != TrueColor)
	{
		ARCH_ERROR("DirectColor or TrueColor visual required");
		goto err_exit;
	}
	gl_context->glx_context =
		glXCreateContext(cn->dpy, gl_context->visual_info, NULL, True);
	if(!gl_context->glx_context)
	{
		ARCH_ERROR("glXCreateContext() failed");
		goto err_exit;
		return false;
	}
	gl_context->wnd = archWinOpenNP(NULL, gl_context->visual_info,
		caption, x, y, width, height, !fullscreen, can_resize);
	if(!gl_context->wnd)
		goto err_exit;
	archWinShow(gl_context->wnd, true);
	XFlush(cn->dpy);
	if(!glXMakeCurrent(cn->dpy, gl_context->wnd->wnd, gl_context->glx_context))
	{
		ARCH_ERROR("glXMakeCurrent() failed");
		goto err_exit;
		return false;
	}
	x11_close_connection(); /* decrease cn->ref_count */
	gl_context->vendor = strDup((char_p)glGetString(GL_VENDOR));
	gl_context->renderer = strDup((char_p)glGetString(GL_RENDERER));
	gl_context->version = strDup((char_p)glGetString(GL_VERSION));
	gl_context->extensions = strDup((char_p)glGetString(GL_EXTENSIONS));
	archWinPoll(gl_context->wnd, false);
	aspect = (GLfloat)gl_context->wnd->width /
		(GLfloat)gl_context->wnd->height;
	glViewport(0, 0, gl_context->wnd->width, gl_context->wnd->height);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(-aspect, aspect, -1, 1, 1, 3);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	return true;

err_exit:;
	x11_shutdown_gl(gl_context);
	x11_close_connection();
	memFree(gl_context);
	gl_context = NULL;
	return false;
}

vec_t alpha = 0, beta = 0;

int main(void)
{
	ui_event_t ev;
	arch_window_p w;
	vboolean enable_kb_repeat = false;

	logStartConsoleLog();
	logUpperLevel(LOG_TRACE);

	assert(x11_init_gl("test",300,50,640,480,false,false,false,false,false));
	w = gl_context->wnd;

	glClearColor(0,0.5,0.5,0.5);

	for(;;)
	{
		archWinPoll(w, true);

		while(w->msg_que)
		{
			DEQ_POP_BACK(event,w->msg_que,&ev);
			dump_event(0, &ev);

			if(ev.type == ui_window_expose_event || autowarp)
			{
				glClear(GL_COLOR_BUFFER_BIT);
				glPushMatrix();
				glTranslatef(0, 0, -2);

				if(autowarp)
				{
					glRotatef(alpha += ev.client_dx * 0.1,0,1,0);
					glRotatef(beta += ev.client_dy * 0.1,1,0,0);
				}

				glScalef(0.01, 0.01, 1);
				glBegin(GL_TRIANGLES);
					glColor3f(1, 0, 0);
					glVertex3f(0, -50, 0);
					glColor3f(0, 1, 0);
					glVertex3f(-50, 50, 0);
					glColor3f(0, 0, 1);
					glVertex3f(50, 50, 0);
				glEnd();
				
				glPopMatrix();
				x11_end_frame(gl_context);
				if(!autowarp)
					continue;
			}
			if(ev.type != ui_key_event)
				continue;
			switch(ev.key.scan)
			{
				case sc_escape:
					if(!ev.key.press)
						goto close_win;
					break;
				case sc_s:
					archWinShow(w, false);
					archWinPoll(w, false);
					while(w->msg_que)
					{
						DEQ_POP_BACK(event,w->msg_que,&ev);
						dump_event(0, &ev);
					}
					timeDelay(3000);
					archWinShow(w, true);
					break;
				case sc_p:
					archWinShowPointer(w, true);
					break;
				case sc_o:
					archWinShowPointer(w, false);
					break;
				case sc_a:
					if(ev.key.press)
						archWinAutoRepeat(w,enable_kb_repeat = !enable_kb_repeat);
					break;
				case sc_w:
					if(ev.key.press)
						archWinAutoWarp(w,autowarp = !autowarp);
					break;
				default:
					break;
			}
		}
	}

close_win:;
	x11_shutdown_gl(gl_context);
	memFree(gl_context);
	gl_context = NULL;

	memPrintStats();
	return 0;
}
