/*
    Living Realms is a primate evolution simulator.
    Copyright (C) 2011  Sterling Pickens

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

//#include "Png_Funcs.h"
#include "OpenGL.h"

#define TOGGLE 0
#define PAUSED 1
#define EXIT_AND_SAVE 2
#define EXIT_NO_SAVE 3
#define WIDTH1 3600
#define HEIGHT1 400
#define WIDTH2 3600
#define HEIGHT2 1800
#define GLHEIGHT 1200
#define GLWIDTH 1200

unsigned char *img1;
unsigned char *img2;
char *filename1 = "legend.png";
char *filename2 = "main-test.png";


GLuint Image_Texture1;
GLuint Image_Texture2;

double Eye_X = 0;
double Eye_Y = 0;
double Eye_Z = -6;
char scorestring[32];
struct timeval starttime,endtime;
int Toggle_Image_Type = 1;
int Toggle_Paused = 0;

unsigned char rgb2[10][3] = {
        {255, 0, 0}, //red
        {170, 170, 38}, //puke
        {255, 255, 0}, //yellow
        {255, 127, 0}, //orange
        {127, 0, 127}, //purple
        {0, 127, 127}, //turqois
        {0, 255, 255}, //light blue
        {127, 64, 0}, //brown
        {127, 127, 127}, //grey
        {255, 255, 255} //white
};

//static void GL_Draw_Image(void);
static void processMenuEvents(int option);
static void special(int key, int x, int y);
static void Frames(double fps);
static void BindTexture1(void);
static void BindTexture2(void);

static void createGLUTMenus(void){
	int menu;
	menu = glutCreateMenu(processMenuEvents);
	glutAddMenuEntry("Toggle Show Top 10",TOGGLE);
    glutAddMenuEntry("Pause OpenGL updates",PAUSED);
    glutAddMenuEntry("Save & Exit",EXIT_AND_SAVE);
	glutAddMenuEntry("Exit Without Saving",EXIT_NO_SAVE);
	glutAttachMenu(GLUT_RIGHT_BUTTON);
}

static void processMenuEvents(int option) {
	switch(option){
		case TOGGLE :
			Toggle_Image_Type ^= 1;
			//if(Toggle_Image_Type)
			//	Toggle_Image_Type = 0;
			//else
			//	Toggle_Image_Type = 1;
			break;
		case PAUSED :
			Toggle_Paused ^= 1;
			//printf("not implemented !\n");
			break;
		case EXIT_AND_SAVE :
			printf("Saving and Exiting Program !!\n");
			//pthread_mutex_unlock( &Mutex3 );
			//No_Exit = 0;
			//pthread_mutex_unlock( &Mutex3 );
			free(img1);
			free(img2);
			glDeleteTextures( 1, &Image_Texture1 );
			glDeleteTextures( 1, &Image_Texture2 );
			exit(1);
			//pthread_exit(NULL);
			break;
		case EXIT_NO_SAVE :
			printf("Exiting Program Without Saving!!\n");
			//pthread_mutex_unlock( &Mutex3 );
			//No_Exit = 2;
			//pthread_mutex_unlock( &Mutex3 );
			free(img1); free(img2); glDeleteTextures( 1, &Image_Texture1 );
			glDeleteTextures( 1, &Image_Texture2 );
			//pthread_exit(NULL);
			exit(1);
			break;
	}
}

static void special(int key, int x, int y){
	switch(key){
		case GLUT_KEY_UP:
			Eye_Y-=.1;
			break;
		case GLUT_KEY_DOWN:
			Eye_Y+=.1;
			break;
		case GLUT_KEY_RIGHT:
			Eye_X+=.1;
			break;
		case GLUT_KEY_LEFT: 
			Eye_X-=.1;
			break;
		case GLUT_KEY_PAGE_UP:
			Eye_Z+=Eye_Z/10;
			break;
		case GLUT_KEY_PAGE_DOWN:
			Eye_Z-=Eye_Z/10;
			break;
	}
}

static void Frames(double fps){
	(void)memset(scorestring, '\0', 32);
	int empty = 0;
	empty = sprintf(scorestring, "%.02lf", fps);
	float pos[3] = {-1, 10, -25};
	int i = 0;
    glPushMatrix();
    glLoadIdentity();

/*
	if(!Toggle_Image_Type){
		for(i=0; i<10; i++){
			pos[0]+=0.5;
			glColor3f(rgb2[i][0], rgb2[i][1], rgb2[i][2]);
			glRasterPos3f(pos[0], pos[1], pos[2]);
			glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, 'C');
			glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24,' ');
		}
	}
*/
	pos[0]+=0.1;
	glColor3f(1.0, 0.0, 0.0);
	glRasterPos3f(pos[0], pos[1], pos[2]);
	glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'F');
	glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'P');
	glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'S');
	glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'(');
	glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'c');
	glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'a');
	glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'p');
	glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,' ');
	glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'2');
	glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'0');
	glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,')');
	glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,':');
	glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,' ');
	for(i = 0; scorestring[i] != '\0'; i++){
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, scorestring[i]);
	}
	glPopMatrix();
	//glutSwapBuffers();
	//glutPostRedisplay();
}

//static void FreeTexture( GLuint texture ){
//	glDeleteTextures( 1, &texture );
//}

static void BindTexture1(void){
	glPushMatrix();
    //glLoadIdentity();
    //gluLookAt ( Eye_X, Eye_Y, Eye_Z,  Eye_X, Eye_Y, 0.0, 0.0, 0.1, 0.0);
	//int screenWidth, screenHeight, windowWidth, windowHeight; 
	//screenWidth = glutGet(GLUT_SCREEN_WIDTH); screenHeight = glutGet(GLUT_SCREEN_HEIGHT); 
	//int windowWidth = glutGet(GLUT_WINDOW_WIDTH); int windowHeight = glutGet(GLUT_WINDOW_HEIGHT);
	//glClearColor (0.0,0.0,0.0,1.0);
	//glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glEnable(GL_TEXTURE_2D);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, WIDTH1, HEIGHT1, 0, GL_RGB, GL_UNSIGNED_BYTE, (unsigned char *)img1);
	glBindTexture( GL_TEXTURE_2D, Image_Texture1 );
	glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );

	const float x = 1;
	//const float y = 1;
	const float y = 1;
    glTranslatef(0.0, -0.8182, 0.0 );
    //glScalef(windowWidth/WIDTH1, windowHeight/HEIGHT1, 0.0);
	//glRasterPos3f(-10, 1, -25);
	//glTranslatef(0.0, 0.0, 0.0 );
	glScalef(1.0, 0.8181, 1.0);
	glColor3f(1.0f,1.0f,1.0f);
    glBegin (GL_QUADS);
   	glTexCoord2d(0.0,y); glVertex2d(x,-1.0*y);
    glTexCoord2d(0.0,0.0); glVertex2d(x,y);
    glTexCoord2d(x,0.0); glVertex2d(-1.0*x,y);
    glTexCoord2d(x,y); glVertex2d(-1.0*x,-1.0*y);
    glEnd();

	glDisable(GL_TEXTURE_2D); 
	//glutSwapBuffers();
	//glutPostRedisplay();
	glPopMatrix();

}

static void BindTexture2(void){
	glPushMatrix();
    //glLoadIdentity();
    //gluLookAt ( Eye_X, Eye_Y, Eye_Z,  Eye_X, Eye_Y, 0.0, 0.0, 0.1, 0.0);

	//glClearColor (0.0,0.0,0.0,1.0);
	//glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_TEXTURE_2D);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, WIDTH2, HEIGHT2, 0, GL_RGB, GL_UNSIGNED_BYTE, (unsigned char *)img2);
    glBindTexture( GL_TEXTURE_2D, Image_Texture2 );
    glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );

    const float x = 1;
	const float y = 1;
    //const float y = 1;
    glTranslatef(0.0, 0.1819, 0.0);
    //glScalef(0.0, 0.1818, 0.0);

	//glTranslatef(0.0, 4.0, 0.0 );
	glScalef(1.0, 0.1818, 1.0);
    glColor3f(1.0f,1.0f,1.0f);
    glBegin (GL_QUADS);
    glTexCoord2d(0.0,y); glVertex2d(x,-1.0*y);
    glTexCoord2d(0.0,0.0); glVertex2d(x,y);
    glTexCoord2d(x,0.0); glVertex2d(-1.0*x,y);
    glTexCoord2d(x,y); glVertex2d(-1.0*x,-1.0*y);
    glEnd();

    glDisable(GL_TEXTURE_2D); 
    //glutSwapBuffers();
    //glutPostRedisplay();
	glPopMatrix();
}






static void display(void){
	static struct timespec ts;
    ts.tv_sec = 0; 

    ts.tv_nsec = 50000000; //1/10th of a second

	static double time1 = 2;
	static double frame_c = 0;
	static double fps = 0;
	static uint32_t frame_c_draw = 9;

	if(!Toggle_Paused){

    glClearColor (0.0,0.0,0.0,1.0);
	glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glLoadIdentity();
	gluLookAt ( Eye_X, Eye_Y, Eye_Z,  Eye_X, Eye_Y, 0.0, 0.0, 0.1, 0.0);

/*
	if(Toggle_Image_Type){
		nanosleep (&ts, NULL);
		//Drawl_Image();
	}else{
		frame_c_draw++;
		if( (frame_c_draw % 25) == 0){
			GL_Draw_Image();
			frame_c_draw = 0;
		}else{
			nanosleep (&ts, NULL);
		}
	}
	if(No_Exit != 1){
		glDeleteTextures( 1, &Image_Texture );
		pthread_exit(NULL);
	}
*/

	BindTexture1();

  //  glLoadIdentity();
   // gluLookAt ( Eye_X, Eye_Y, Eye_Z,  Eye_X, Eye_Y, 0.0, 0.0, 0.1, 0.0);

	BindTexture2();
	frame_c++; //frame counter
	if(time1 > 1){
		gettimeofday(&endtime, NULL);
		time1=((double)(endtime.tv_sec*1000000-starttime.tv_sec*1000000+endtime.tv_usec-starttime.tv_usec))/1000000;
		fps = frame_c / time1;
		gettimeofday(&starttime, NULL);
		frame_c = 0;
	}else{
		gettimeofday(&endtime, NULL);
		time1=((double)(endtime.tv_sec*1000000-starttime.tv_sec*1000000+endtime.tv_usec-starttime.tv_usec))/1000000;
	}
	Frames(fps);
	}else{
		sleep(1);
	}
    glutSwapBuffers();
    glutPostRedisplay();

}


static void reshape(int w, int h){
	GLfloat aspect = (GLfloat)WIDTH1 / (GLfloat)(HEIGHT2+HEIGHT1+4.4);
    glViewport (0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
	gluPerspective (60, (GLfloat)w / (GLfloat)h/aspect, 0.0 , 100.0);
    glMatrixMode (GL_MODELVIEW);

}



void Run_GL(void){
    glutInitDisplayMode (GLUT_DOUBLE| GLUT_RGB | GLUT_DEPTH);
	glutInitWindowSize(GLHEIGHT, GLWIDTH);

   glutInitWindowPosition(0, 0);
	glutCreateWindow("test");
    //glutCreateWindow(LR_NAME" "LR_VERSION);
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
	glutIgnoreKeyRepeat(0);
    glutSpecialFunc(special);

	img1 = malloc(HEIGHT1 * WIDTH1 * 3);
	img2 = malloc(HEIGHT2 * WIDTH2 * 3);

	(void)Open_Convert_Legend(img1, filename1);
	(void)Open_Convert_Legend(img2, filename2);

	glGenTextures( 1, &Image_Texture1 );
	glGenTextures( 1, &Image_Texture2 );

	createGLUTMenus();
	glutMainLoop ();
	free(img1);
	free(img2);
	//pthread_exit(NULL);
}

/*
static void GL_Draw_Image(void){
	uint32_t w=0, h=0;
	uint32_t n1=0, n2=0, n3=0;
	uint32_t species_c = 1;
	size_t size_of_species_t = 500;
	uint32_t ten_most[10];
	unsigned char rgb[3] = {0, 0, 0};
	struct Species *ten_s = (struct Species *)malloc(sizeof(struct Species)*10);
	struct Species *species_t = (struct Species *)malloc(sizeof(struct Species) * size_of_species_t);
	uint32_t *species_totals = (uint32_t *)malloc(sizeof(uint32_t) * size_of_species_t);

	species_totals[0] = 9;
	for(h=0; h<HEIGHT; h++){
		for(w=0; w<WIDTH; w++){
			if( IS_SET(Alive, h, w) ){
				(void)memcpy((void *)species_t, (const void *)life[h][w], sizeof(struct Species) );
				species_totals[0] = 0;
				break;
			}
		}
		if(species_totals[0] == 0)
			break;
	}
	for(h=0; h<HEIGHT; h++){
		for(w=0; w<WIDTH; w++){
			if( IS_SET(Alive, h, w) ){
				for(n1=0; n1<species_c; n1++){
					if( Is_Same_Species(&species_t[n1], life[h][w]) ){
						species_totals[n1]++;
						goto Next_Tribe;
					}
				}
				species_c++;
				if(species_c > size_of_species_t){
					size_of_species_t += 500;
					species_t = (struct Species *)realloc(species_t, sizeof(struct Species) * size_of_species_t);
					species_totals = (uint32_t *)realloc(species_totals, sizeof(uint32_t) * size_of_species_t);
					//set all new species_totals = 0;
					for(n3=species_c; n3<size_of_species_t; n3++){
						(void)memset((void *)&species_t[n3], '\0', sizeof(struct Species) );
						species_totals[n3] = 0;
					}
				}
				species_totals[species_c-1] = 1;
				(void)memcpy((void *)&species_t[species_c-1], (const void *)life[h][w], sizeof(struct Species) );
			}
			Next_Tribe:
			;
		}
	}
	for(n1=0; n1<10; n1++)
		ten_most[n1] = 0;
	uint32_t last_highest = 0;
	last_highest--;
	uint32_t highest = 0;

	for(n2=0; n2<10; n2++){
		for(n1=0; n1<species_c; n1++){
			if(species_totals[n1] < last_highest){
				if(species_totals[n1] > highest){
					highest = species_totals[n1];
					ten_most[n2] = highest;
					(void)memcpy((void *)&ten_s[n2], (const void *)&species_t[n1], sizeof(struct Species) );
				}
			}
		}
		last_highest = highest;
		highest = 0;
	}
	n2 = species_c < 10 ? species_c : 10;
	//remove all species from map that aren't in the top 10, and add better coloring

    for(h=0; h<HEIGHT; h++){
        for(w=0; w<WIDTH; w++){
            if(ia->dem[h][w] > stats_t.cur_sealevel){
				if( !IS_SET(Alive, h, w) ){
                    rgb[0] = 0;
                    rgb[1] = 255;
                    rgb[2] = 0;
                }else{
					for(n1=0; n1<n2; n1++){
						if( Is_Same_Species(&ten_s[n1], life[h][w]) ){
							rgb[0] = rgb2[n1][0];
							rgb[1] = rgb2[n1][1];
							rgb[2] = rgb2[n1][2];
							break;
						}
						rgb[0] = 0;
						rgb[1] = 0;
						rgb[2] = 0;
					}
                }
            }else{
				rgb[0] = 0;
				rgb[1] = 0;
				rgb[2] = 255;
			}
            ia->image[h*WIDTH*3+(w*3)]   = rgb[0];
            ia->image[h*WIDTH*3+(w*3+1)] = rgb[1];
            ia->image[h*WIDTH*3+(w*3+2)] = rgb[2];
        }
    }
	free(ten_s);
	free(species_t);
	free(species_totals);
}
*/