#include "gl_gui.h"

static float default_colors[][3] = {
	{0.1, 0.1, 0.1}, //bgColor
	{.7, .7, .7}, //textColor
	{0, 0, 1}, //borderColor
	{ 0, 1, 0 }, //highlightTextColor
	{ 0.4, 0.4, 0.3 } //highlightBgColor
};

void gui_default_window_colors(GContainer *win){
	memcpy(win->bgColor, default_colors[0], 3 * sizeof(float));
	memcpy(win->textColor, default_colors[1], 3 * sizeof(float));
	memcpy(win->borderColor, default_colors[2], 3 * sizeof(float));
	memcpy(win->highlightTextColor, default_colors[3], 3 * sizeof(float));
	memcpy(win->highlightBgColor, default_colors[4], 3 * sizeof(float));
}

void VP_addChild(ViewPanel *vp, void *child, CHILD_REPAINT func){
	int i, j;
	if(child == NULL) return;
	j = -1;
	for(i=0;i<vp->child_size;i++){
		if(vp->childs[i*2] == NULL) j = i*2;
		if(child == vp->childs[i*2]) return;
	}
	if(j >= 0){
		vp->childs[j] = child;
		vp->childs[j+1] = func;
		return;
	}
	if(vp->child_size * 2 >= vp->child_capacity){
		vp->child_capacity = (vp->child_size + 1) * 2;
		vp->childs = (void**)realloc(vp->childs, sizeof(void*) * vp->child_capacity);
	}
	vp->childs[vp->child_size*2] = child;
	vp->childs[vp->child_size*2 + 1] = func;
	vp->child_size ++;
}

void* VP_removeChild(ViewPanel *vp, void *child){
	int i;
	void *func;
	for(i=0;i<vp->child_size;i++){
		if(vp->childs[i*2] == child){
			func = vp->childs[i*2+1];
			vp->childs[i] = NULL;
			return func;
		}
	}
	return NULL;
}

GList *last_glist = NULL;
GList* getCurrentGList(){
	int win_id;
	win_id = glutGetWindow();
	if(win_id > vps_size){
		return last_glist;
	} else if(vp_types[win_id-1] == WINDOW_TYPE_GLIST){
		last_glist = (GList*)vps[win_id-1];
		return (GList*)vps[win_id-1];
	} else {
		return last_glist;
	}
}

void GList_repaint(void *obj){
	GList *list;
	int i;
	list = (GList*)obj;
	glutSetWindow(list->window.win_id);
	glClearColor(list->window.bgColor[0], list->window.bgColor[1], list->window.bgColor[2], 0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
	glColor3fv(list->window.borderColor);
	glBegin(GL_LINE_LOOP);
		glVertex3f(0, 0, 0);
		glVertex3f(list->window.win_width-1, 0, 0);
		glVertex3f(list->window.win_width-1, list->window.win_height-1, 0);
		glVertex3f(0, list->window.win_height-1, 0);
	glEnd();

	for(i=0;i<list->disp_size;i++){
		if(i >0 && i < list->disp_size){
			glColor3fv(list->window.borderColor);
			glBegin(GL_LINES);
				glVertex3f(0, list->cell_height * (list->disp_size - i), 0);
				glVertex3f(list->window.win_width, list->cell_height * (list->disp_size - i), 0);
			glEnd();
		}

		if(i + list->disp_offset >= list->size) continue;
		
		if(i + list->disp_offset == list->selected){
			/*
			glColor3fv(list->window.highlightBgColor);
			glRectf(0, list->cell_height * (list->disp_size - i), list->window.win_width, list->cell_height * (list->disp_size - i - 1));
			*/
			glColor3fv(list->window.highlightTextColor);
		} else {
			glColor3fv(list->window.textColor);
		}
		
		drawString((list->cell_width - strlen(list->options[i + list->disp_offset]) * 8) / 2,
				(list->cell_height - 13) / 2 + list->cell_height * (list->disp_size - i - 1),
				list->options[i + list->disp_offset]);
	}
	glutSwapBuffers();
}

void GList_display(){
	GList *list;
	list = getCurrentGList();
	GList_repaint(list);
}

void GList_resize(int w, int h){
	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glOrtho(0, w, 0, h, -w, w);
}

void GList_mouse(int button, int state, int x, int y){
	GList *list;
	list = getCurrentGList();
	if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN){
		list->selected = y / list->cell_height;
		if(list->valueChanged) list->valueChanged(list, list->selected);
		glutPostRedisplay();
	}
}

GList* createGList(int id, ViewPanel *vp, float x, float y, float cell_w, float cell_h, int n_disp){
	GList *list;
	list = (GList*)malloc(sizeof(GList));
	list->window.parent      = vp;
	list->window.visible     = 1;
	list->window.win_x       = x;
	list->window.win_y       = y;
	list->window.border_size = 1;
	list->window.win_width   = cell_w;
	list->window.win_height  = cell_h * n_disp;

	gui_default_window_colors(&list->window);

	list->window.win_id = glutCreateSubWindow(vp->win_id, x, y, list->window.win_width, list->window.win_height);

	glEnable(GL_DEPTH_TEST);
	glutDisplayFunc(GList_display);
	glutReshapeFunc(GList_resize);
	glutMouseFunc(GList_mouse);

	register_window(list->window.win_id, list, WINDOW_TYPE_GLIST);

	list->cell_width  = cell_w;
	list->cell_height = cell_h;

	list->id = id;

	list->selected    = -1;
	list->disp_size   = n_disp;
	list->disp_offset = 0;

	list->size     = 0;
	list->capacity = 6;
	list->options  = (char**)malloc(list->capacity * sizeof(char*));
	
	list->valueChanged = NULL;

	VP_addChild(vp, list, GList_repaint);

	last_glist = list;

	return list;
}

int GList_addOption(GList *list, char *option){
	char *str;
	str = (char*)malloc(sizeof(char) * (strlen(option) + 1));
	strcpy(str, option);
	if(list->size > list->capacity){
		list->capacity = list->size * 2;
		list->options = (char**)realloc(list->options, sizeof(char*) * list->capacity);
	}
	list->options[list->size++] = str;
	return list->size - 1;
}

char* GList_getOption(GList *list, int index){
	if(index >= list->size || index < 0) return NULL;
	return list->options[index];
}

void freeGList(GList *list){
	int i;
	VP_removeChild(list->window.parent, list);
	for(i=0;i<list->size;i++){
		free(list->options[i]);
	}
	free(list->options);
	glutDestroyWindow(list->window.win_id);
	free(list);
	if(last_glist == list) last_glist = NULL;
}
