#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/gl.h>
#include <GL/glu.h>
#include "GL/glut.h"
#ifdef HAVE_FREEGLUT
#include "GL/freeglut_ext.h"
#endif
#endif

#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include "maqview.h"

static int main_window = 0;
static ViewPanel **main_vps  = NULL;
static int n_vp = 0;
static int win_width   = 800;
static int win_height  = 600;

static char msg_string[] = "\
?                 : Display this help\n\
<Esc>             : exit\n\
<F1>              : Draw bases as characters\n\
<F2>              : Draw bases as squares\n\
p                 : Switch to the previous reference sequence\n\
n                 : Switch to the next reference sequence\n\
r                 : Show/Hide the menu of ref list\n\
<digits> <Enter>  : Move to the position pointed by <digits>\n\
h / <Left>        : Move left by one base\n\
l / <Right>       : Move right by one base\n\
k / <Up>          : Move view window down\n\
j / <Down>        : Move view window up\n\
>                 : Move to next read\n\
<                 : Move to previous read\n\
g / <Home>        : Goto begin\n\
G / <End>         : Goto end\n\
u / <PageUp>      : Move left one page\n\
<Space> / <PageDn>: Move right one page\n\
<Shift> <Arrow>   : Move by 100 bases\n\
<Ctrl> <Arrow>    : Move by 1000 bases\n\
<Ctrl> +          : Add a new view\n\
<Ctrl> -          : Remove the current view\n\
<Enter>           : Toogle on/off automatic rolling on\n\
^b                : Toogle on/off automatic rolling back\n\
+                 : Zoom in\n\
-                 : Zoom out\n\
0                 : Zoom to the default scale\n\
q                 : Toggle display/undisplay mapping qualities\n\
e                 : Toggle display single-end/paired-end mapping qualities\n\
o                 : Open a new view file\n\
c                 : Input command, see README\n\n\
Enter an integer then press <Enter> key to goto the position\n\
Enter an integer then press a key other than <Enter> can speed the integer times\n\
Mouse:\n\
     left button to select;\n\
     middle button temporarily drags the scene;\n\
     right button sets marker\n\
Mouse: move over an entity to show description\n\
\n\
\n\
Please see README for more function,  Press <Enter>/<Esc> to return";

void main_display(){
	glClearColor(0, 0, 0, 0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glColor3f(1, 1, 1);
	drawString(20, win_height - 20, msg_string);
	glutSwapBuffers();
}

void main_reshape(int w, int h){
	int i;
	win_width  = w;
	win_height = h;
	glViewport(0, 0, win_width, win_height);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glOrtho(0, win_width, 0, win_height, -1, 1);
	if(!n_vp) return;
	for(i=0;i<n_vp;i++){
		glutSetWindow(main_vps[i]->win_id);
		main_vps[i]->off_x = 0;
		main_vps[i]->off_y = i * h / n_vp;
		glutPositionWindow(0, i * h / n_vp);
		glutReshapeWindow(w, h / n_vp);
		//main_vps[i]->resize(main_vps[i], w, h / n_vp);
	}
	glutSetWindow(main_vps[0]->win_id);
	glutPostRedisplay();
}

void main_keyboard(unsigned char key, int x, int y){
	ViewPanel *vp;
	vp = getCurrentViewPanel();
	if(vp && vp->keyTyped){
		vp->keyTyped(vp, key, x, y);
	} else {
	}
}

void main_mouse(int button, int state, int x, int y){
	ViewPanel *vp = getCurrentViewPanel();
	if(vp == NULL) return;
	if(state == GLUT_DOWN){
		if(vp->mousePressed) vp->mousePressed(vp, button, x, y);
	} else {
		if(vp->mouseReleased) vp->mouseReleased(vp, button, x, y);
	}
}

void main_special_key(int key, int x, int y){
	ViewPanel *vp = getCurrentViewPanel();
	if(vp == NULL) return;
	if(vp->specialKey) vp->specialKey(vp, key, x, y);
}

ViewPanel* addViewPanel(ViewPanel * parent, const char *map_name, const char *cns_name, int view_style){
	View *view;
	view = createView(map_name, cns_name, win_width, win_height, view_style);
	if(view == NULL){
		fprintf(stderr, "Cannot open view on %s\n", map_name);
		return 0;
	}
	main_vps = (ViewPanel**)realloc(main_vps, sizeof(ViewPanel*) * (++n_vp));
	main_vps[n_vp-1] = createViewPanel(main_window, view, 0, 0, win_width, win_height);
	if(parent){
		main_vps[n_vp-1]->owner = parent;
		observeView(parent->view, main_vps[n_vp-1], main_vps[n_vp-1]->synchronize);
	}
	main_reshape(win_width, win_height);
	return main_vps[n_vp-1];
}

void removeViewPanel(ViewPanel *vp){
	int i;
	if(n_vp < 2) return;
	for(i=0;i<n_vp;i++){
		if(vp == main_vps[i]){
			closeViewPanel(vp);
			memmove(main_vps + i, main_vps + i + 1, (n_vp - i - 1) * sizeof(ViewPanel*));
			n_vp --;
			main_reshape(win_width, win_height);
			break;
		}
	}
}

int check_circle_binding(ViewPanel *vp, View *view){
	int i;
	Observer *ob;
	ob = view->observer;
	for(i=0;i<ob->n_ob;i++){
		if(ob->objects[i] == vp) return 1;
		else {
			if(check_circle_binding(vp, ((ViewPanel*)ob->objects[i])->view)) return 1;
		}
	}
	return 0;
}

void bindViewPanel(ViewPanel *observer, int n){
	if(n < 0 || n > n_vp) return;
	if(check_circle_binding(main_vps[n], observer->view)){
		fprintf(stderr,"Might bring circled binding, break now\n\n");
		return;
	}
	observeView(main_vps[n]->view, observer, observer->synchronize);
	observer->owner = main_vps[n];
}

int maqview_usage(){
	fprintf(stderr, "MaqView 0.2.4(%s) was written by Ruan Jue ,Li Heng and Zhao MengYao\n", "2008.09");
	fprintf(stderr, "Usage: maqview [-c cns_file] [-w width:800] [-h height:600] map_file [ref_name:start_pos]\n");
	return 1;
}

int main(int argc, char **argv){
	int w, h, c;
	int i, n;
	ViewPanel *vp;
	char *map_file, *cns_file;
	char *location;

	glutInit(&argc, argv);
	cns_file = NULL;
	w = win_width;
	h = win_height;
	while((c = getopt(argc, argv, "c:w:h:")) >= 0){
		switch(c){
			case 'c': cns_file   = optarg; break;
			case 'w': win_width  = atoi(optarg); break;
			case 'h': win_height = atoi(optarg); break;
		}
	}
	if(optind == argc) return maqview_usage();
	map_file = argv[optind];

	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	glutInitWindowSize(win_width, win_height);
	glutInitWindowPosition(200, 200);
	main_window = glutCreateWindow("M.A.Q Viewer");

	vp = addViewPanel(NULL, map_file, cns_file, 0);

	if(optind + 1 < argc){
		n = strlen(argv[optind+1]);
		location = (char*)malloc(n + 1);
		memcpy(location, argv[optind+1], n + 1);
		for(i=0;i<n;i++){
			if(location[i] == ':'){
				location[i] = '\0';
				view_locate(vp->view, location, str2num(location + i + 1));
				break;
			}
		}
		free(location);
	}
	atexit(closeViewPanels);
	glutSetWindow(main_window);
	glutReshapeFunc(main_reshape);
	glutDisplayFunc(main_display);
	glutKeyboardFunc(main_keyboard);
	glutSpecialFunc(main_special_key);
//	glutMouseFunc(main_mouse);
//	glutMotionFunc(main_motion);
//	glutPassiveMotionFunc(main_mouseMoved);
	#ifdef __APPLE__
	#else
	#ifdef HAVE_FREEGLUT
//	glutMouseWheelFunc(main_mouseWheel);
	#endif
	#endif
//	glutTimerFunc(100, timer, 0);
	glutMainLoop();
	return 0;
}
