#include <stdio.h>
#include <stdlib.h>
#include <GL/glut.h>
#include <GL/gl.h>
#include <GL/glx.h>
#include <unistd.h>
#include <math.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>

struct timespec ts;
struct timeval starttime,endtime;
char scorestring[50];

float Mouse_X = 0;
float Mouse_Y = 0;

float light_x = 5;
float light_y = 2;
float light_z = -2;

    float x_1, y_1, z_1;
    float x_2, y_2, z_2;
    float rgba_light0[4];
    float pos_light0[4];
    float dir_light0[3];
int light_var = 0;
int win_X = 500;
int win_Y = 500;
double Look_X = 0;
double Look_Y = 0;
double Eye_X = 0;
double Eye_Y = 0;
double Eye_Z = -20;

void special (int key, int x, int y)
{

  switch (key) {
    case GLUT_KEY_UP:
		Eye_Z++;
      break;

    case GLUT_KEY_DOWN:
		Eye_Z--;
      break;

    case GLUT_KEY_RIGHT:
      Eye_X++;
      //printf("increment num1: %lf\n", num1);
      break;

    case GLUT_KEY_LEFT: 
      Eye_X--;
      //printf: %lf\n", num1);
      break;

 }

}

void query_ext(void){
	return;
	//GL_VENDOR, GL_RENDERER, GL_VERSION, GL_SHADING_LANGUAGE_VERSION, or GL_EXTENSIONS.
	//const GLubyte* string;
	char *string;
	size_t string_size = strlen( (const char *)glGetString(GL_EXTENSIONS) ) +
		strlen( (const char *)glGetString(GL_VENDOR) ) +
		strlen( (const char *)glGetString(GL_RENDERER) ) +
		strlen( (const char *)glGetString(GL_VERSION) ) +
		strlen( (const char *)glGetString(GL_SHADING_LANGUAGE_VERSION) ) + 155;
	string = (char *)malloc(string_size * sizeof(char) );
	//string = glGetString(GL_EXTENSIONS);
	(void)sprintf(string, "GL_VENDOR: %s\n GL_RENDERER: %s\n GL_VERSION: %s\n GL_SHADING_LANGUAGE_VERSION: %s\n GL_EXTENSIONS: %s\n", (const char *)glGetString(GL_VENDOR), (const char *)glGetString(GL_RENDERER), (const char *)glGetString(GL_VERSION), (const char *)glGetString(GL_SHADING_LANGUAGE_VERSION), (const char *)glGetString(GL_EXTENSIONS) );
	printf("%s\n", string);
sleep(2);
	free(string);
}

void lights(void);
void grid(void);
void sphere(void);
void Frames(double fps);

void mouse_active (int x,int y){
	static double last_X = 250;
	static double last_Y = 250;
    //printf("a - x: %d y: %d\n", x, y);
    Mouse_X = x;
    Mouse_Y = y;

/*
	if(x == win_X){
		Look_X++;
	}else if(x == 0){
		Look_X--;
	}else{
		Look_X += last_X-Mouse_X;
	}

	Look_Y += last_Y-Mouse_Y;
*/

	printf("x chng: %.02lf y chng: %.02lf\n", last_X-Mouse_X, last_Y-Mouse_Y);
	Look_X += last_X-Mouse_X;
	Look_Y += last_Y-Mouse_Y;

	last_X = Mouse_X;
	last_Y = Mouse_Y;

}

void mouse_passive (int x,int y){
        //printf("p - x: %d y: %d\n", x, y);
    Mouse_X = x;
    Mouse_Y = y;
}

void reshape (int w, int h) {
	Look_X = Look_X * w/win_X;
	Look_Y = Look_Y * h/win_Y;
	win_X = w;
	win_Y = h;
    glViewport (0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
    gluPerspective (60, (GLfloat)w / (GLfloat)h, 1.0, 100.0);
    glMatrixMode (GL_MODELVIEW);
}

void display (void) {
    //static double last_X = 250;
    //static double last_Y = 250;
	static double time1 = 2;
	static double time2 = 0;
	static double fps;
	//gluLookAt ( (Mouse_X)/win_X, (Mouse_Y)/win_Y, 2.0, 0.0, 0.0, -1.0, 0.0, 1.0, 0.0);

/*
	int t1, t2, t3;
for(t1=-100; t1<100; t1++){
for(t2=-100; t2<100; t2++){
for(t3=-100; t3<100; t3++){
glPushMatrix();
    glLoadIdentity();
    glTranslatef ( 0.0, 0.0, t1 );
    glColor3f(1.0, 1.0, 1.0);
    glRasterPos2f(t2, t3);
    glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'S');
glPopMatrix();
}
}
}
*/
float bitcolors[] = {0.6, 0.6, 0.6, 0.0};

//float emcolors[] = {1, 1, 1, 1};

glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//glClearColor (0.0,0.0,0.0,0.0);
glLightModelfv(	GL_LIGHT_MODEL_AMBIENT,(const GLfloat *)bitcolors); 

//glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (const GLfloat *)emcolors);

	//lights();
	sphere();
	grid();
	lights();
	//static double look_x = 0;
	//static double look_y = 0;

	//glPopMatrix();
	//glPushMatrix();
	//lights();
	//sphere();
	//look_x++;
	//look_y++;
	gluLookAt( Eye_X, Eye_Y, Eye_Z, Look_X, Look_Y, 20, 0, .1, 0);
	//printf("x: %.02lf y: %.02lf\n", Mouse_X, Mouse_Y);
	//gluLookAt ( (Mouse_X), (Mouse_Y), 2.0, 0.0, 0.0, -2.0, 0.0, 1.0, 0.0);
	//gluLookAt ( (Mouse_X-win_X/2)/win_X/2, (Mouse_Y-win_Y/2)/win_Y/2*-1, 2.0, 0.0, 0.0, -1.0, 0.0, 1.0, 0.0);
	//glPopMatrix();
	//gluLookAt ( (Mouse_X-win_X/2)/win_X/2, (Mouse_Y-win_Y/2)/win_Y/2*-1, 2.0, 0.0, 0.0, -1.0, 0.0, 1.0, 0.0);
	//glutSwapBuffers();
//	float bitcolors[] = {1.0, 1.0, 1.0};
//glMaterialfv(GL_FRONT_AND_BACK, GL_COLOR_INDEXES, (const GLfloat *)bitcolors);
	time2++;
	//gettimeofday(&endtime, NULL);
	//time1=((double)(endtime.tv_sec*1000000-starttime.tv_sec*1000000+endtime.tv_usec-starttime.tv_usec))/1000000;
	if (time1 > 1){
		gettimeofday(&endtime, NULL);
		time1=((double)(endtime.tv_sec*1000000-starttime.tv_sec*1000000+endtime.tv_usec-starttime.tv_usec))/1000000;
		fps = time2 / time1;
		gettimeofday(&starttime, NULL);
		time2 = 0;
		//printf("FPS: %.02lf\n", fps);
	}else{
		gettimeofday(&endtime, NULL);
		time1=((double)(endtime.tv_sec*1000000-starttime.tv_sec*1000000+endtime.tv_usec-starttime.tv_usec))/1000000;
	}
//sleep(1);
	Frames(fps);
glFlush();
	glutSwapBuffers();
glutPostRedisplay();

}


void Frames(double fps){
	//printf("%lf\n", fps);
	//char scorestring[70];
	int empty, i;
	glPushMatrix();
                glLoadIdentity();
	//glTranslatef(0, 0, 0 );
    //          glTranslatef ( 0.0, 0.0, -25 );
                glColor3f(1.0, 1.0, 1.0);

    glRasterPos3f(3, 8, -15);

                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,' ');
                //glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,' ');
                //glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,' ');
                scorestring[strlen(scorestring)-1]='\0';

                empty = sprintf(scorestring, "%.02lf", fps);

                //printf("%lf\n", fps);
                for(i = 0; scorestring[i] != '\0'; i++)
                {
                        glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,scorestring[i]);

                }
	glPopMatrix();
}

void lights(void){
	//sleep(1);
	/*
	float x1, y1, z1;
	float x2, y2, z2;
	float rgba_light0[4];
	float pos_light0[4];
	float dir_light0[3];
	*/

	rgba_light0[0] = 0.5;
	rgba_light0[1] = 0.5;
	rgba_light0[2] = 0.5;
	rgba_light0[3] = 0.5;

	pos_light0[0] = light_x;
	pos_light0[1] = light_y;
	pos_light0[2] = light_z;
	pos_light0[3] = 0.0;

/*
	if(light_var == 0){
		light_x=-5;
		light_y=2;
		light_z=-2;
		light_var=1;
	}else if(light_var == 1){
        light_x=-5;
        light_y=-2;
        light_z=-2;
        light_var=2;
	}else if(light_var == 2){
        light_x=10;
        light_y=.5;
        light_z=-5;
        light_var=3;
	}else{
        light_x=-5;
        light_y=2;
        light_z=-2;
        light_var=0;
	}
*/

	//light_x+=5;
	//light_y+=5;
	//light_z-=1;

	dir_light0[0]=0;
	dir_light0[1]=0;
	dir_light0[2]=2;

	int i;
	glEnable(GL_LIGHTING);

for (i = 0; i < 8; ++i)
{
    //if (i == 1)
      //  continue;
    glDisable(GL_LIGHT0 + i);
}


	glEnable(GL_LIGHT0);
    //glClearColor (0.0,0.0,0.0,0.0);
//    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    //background color
//	glClearColor(0.15f, 0.15f, 0.0f, 0.1f);

	//glEnable(GL_LIGHTING);
	//glLoadIdentity();
	//glTranslatef(0, 0, -2 );
//glPushMatrix();
	glLightfv(GL_LIGHT0, GL_AMBIENT, (const GLfloat *)rgba_light0);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, (const GLfloat *)rgba_light0);
//	glLightfv(GL_LIGHT0, GL_SPECULAR, (const GLfloat *)rgba_light0);

	glLightfv(GL_LIGHT0, GL_POSITION, (const GLfloat *)pos_light0);
	glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, (const GLfloat *)dir_light0);

}



void grid(void){
	float emcolors[] = {0.0, 0.25, 0.0, 0.0};
	//glEnable(GL_LIGHT0);
/*
	glPushMatrix();

	//glLoadIdentity();
	glTranslatef(0, 0, -.5 );
	//line color
	glColor3f( 0.0, 1.0, 1.0 );
	glutSolidSphere(.5,100,100);

	glPopMatrix();
*/
	//glPushMatrix();
	glLoadIdentity();
	glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (const GLfloat *)emcolors);
	//glColor3f( 0.0, 1.0, 0.0 );
	glBegin(GL_LINES);
	//glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (const GLfloat *)emcolors);
	glColor3f(0.0, 1.0, 0.0);

	//draw horz lines
	x_1=-1;
	y_1=-1;
	z_1=-1;
	x_2=1;
	y_2=-1;
	z_2=-1;

	while(y_1<.1){
		//horz bottom
		glVertex3f(x_1, y_1, z_1);
		glVertex3f(x_2, y_2, z_2);
		//horz top
		glVertex3f(x_1, y_1+2, z_1);
		glVertex3f(x_2, y_2+2, z_2);
		//vert left
		glVertex3f(x_1, y_1, z_1);
		glVertex3f(x_1, y_1+2, z_1);
		//vert right
		glVertex3f(x_2, y_2, z_2);
		glVertex3f(x_2, y_2+2, z_2);

		y_1+=.01;
		y_2+=.01;
		z_1+=-.1;
		z_2+=-.1;
	}

	//glVertex3f(-500, -500, -1);
	//glVertex3f(500, -500, -1);

	//glVertex3f(-.5, -.5, -1);
	//glVertex3f(.5, -.5, -1);

	//glDisable(GL_LIGHTING);
	glEnd();

//int r1, r2, r3;
//for(r1=-10; r1<10; r1++){
//for(r2=-10; r2<10; r2++){
//for(r3=-10; r3<10; r3++){
//glLoadIdentity();
//glRasterPos3f(0, 0, -10);
//glColor3f(1.0, 1.0, 1.0);
//glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'F');
//search
//}
	//glPopMatrix();
}

void sphere(void){
    glPushMatrix();
    //glLoadIdentity();
    //glTranslatef(0, 0, -10 );
    //glColor4f( 0.0, 1.0, 0.0, 0.0 );
    //glutSolidSphere(1,100,100);
    //glPopMatrix();
float emcolors[4];
//= {0.0, 1.0, 0.0, 0.0};


	emcolors[0]=.5; emcolors[1]=0; emcolors[2]=0; emcolors[3]=0;
	glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (const GLfloat *)emcolors);
	glPushMatrix();
	glTranslatef(0, 0, 10 );
	glColor4f( 1.0, 0.0, 0.0, 0.0 );
	glutSolidSphere(1,100,100);
	glPopMatrix();

	
    emcolors[0]=0; emcolors[1]=0; emcolors[2]=.5; emcolors[3]=0;
    glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (const GLfloat *)emcolors);
	glPushMatrix();
    glTranslatef(10, 0, 0 );
    glColor4f( 0.0, 0.0, 1.0, 0.0 );
    glutSolidSphere(1,100,100);
	glPopMatrix();

    emcolors[0]=.5; emcolors[1]=.5; emcolors[2]=.5; emcolors[3]=0;
    glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (const GLfloat *)emcolors);
	glPushMatrix();
    glTranslatef(-10, 0, 0 );
    glColor4f( 1.0, 1.0, 1.0, 0.0 );
    glutSolidSphere(1,100,100);
	glPopMatrix();


    emcolors[0]=0; emcolors[1]=.5; emcolors[2]=0; emcolors[3]=0;
    glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (const GLfloat *)emcolors);
	glPushMatrix();
    glTranslatef(0, 0, -10 );
    glColor4f( 0.0, 1.0, 0.0, 0.0 );
    glutSolidSphere(1,100,100);
    glPopMatrix();


}


int main (int argc, char **argv) {
    glutInit (&argc, argv);
	//query_ext(); 
   glutInitDisplayMode (GLUT_DOUBLE| GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize (500, 500);
    glutInitWindowPosition (100, 100);
    glutCreateWindow ("A basic OpenGL Window");
    glutDisplayFunc (display);
    glutIdleFunc (display);
    glutReshapeFunc (reshape);
    glutMotionFunc(mouse_active);
    glutPassiveMotionFunc(mouse_passive); 
	query_ext();
	glutSpecialFunc(special);
    glutMainLoop ();
	return 0;
}