/*
    This file is part of lspong.
    lspong is a loose representation of the old pong game we all remember and love.
    Copyright (C) 2009  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 <stdio.h>   
#include <stdlib.h>
#include <string.h>
#include <bitmap.h>

#include "config.h"
#ifdef HAVE_LIBPTHREAD
#include <pthread.h>
#endif

#include <GL/glut.h>
#include <GL/gl.h>
//include <unistd.h>
#include <time.h>
#include <sys/time.h>
//define SETTINGS 1
#define RESTART 2
#define PAUSED 3
#define EXIT 4
//#include "test.h"
//#include "calcs.h"

void OpenGLInit(void);

/*
pthread_mutex_t    mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t    mutex1;
pthread_mutex_t    mutex2;
pthread_mutex_t    mutex3;
*/
                        
//void *Calcs_Thread(void *null);

GLuint LoadTextureRAW( const char * filename, int wrap )
{
    GLuint texture;
    int width, height;
    void * data;
    FILE * file;

    // open texture data
    file = fopen( filename, "rb" );
    if ( file == NULL ) return 0;

    // allocate buffer
    width = 256;
    height = 256;
    data = malloc( width * height * 3 );

    // read texture data
    fread( data, width * height * 3, 1, file );
    fclose( file );

    // allocate a texture name
    glGenTextures( 1, &texture );

    // select our current texture
    glBindTexture( GL_TEXTURE_2D, texture );

    // select modulate to mix texture with color for shading
    glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );

    // when texture area is small, bilinear filter the closest mipmap
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                     GL_LINEAR_MIPMAP_NEAREST );
    // when texture area is large, bilinear filter the first mipmap
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

    // if wrap is true, the texture wraps over at the edges (repeat)
    //       ... false, the texture ends at the edges (clamp)
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
                     wrap ? GL_REPEAT : GL_CLAMP );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
                     wrap ? GL_REPEAT : GL_CLAMP );

    // build our texture mipmaps
    gluBuild2DMipmaps( GL_TEXTURE_2D, 3, width, height,
                       GL_RGB, GL_UNSIGNED_BYTE, data );

    // free buffer
    free( data );

    return texture;
}

#define MAX_VERTICES 2000

typedef struct{
   float u,v;  
}mapcoord_type;

/*** The object type ***/
typedef struct {
   vertex_type vertex[MAX_VERTICES];  
   polygon_type polygon[MAX_POLYGONS];  
   mapcoord_type mapcoord[MAX_VERTICES];
   int id_texture;
} obj_type, *obj_type_ptr;


static void Animate(void );
static void ResizeWindow(int w, int h);
int glutCreateMenu(void (*func)(int value));
void glutAddMenuEntry(char *name, int value);
void glutAttachMenu(int button);  
void processMenuEvents(int option);
//static void Setting(void);
	void glutDestroyWindow(int windowID); 
struct timespec ts;
struct timeval starttime,endtime;
//struct tm *local;
//time_t t;


void keyboard (unsigned char key, int x, int y);
//void keyboardUp (unsigned char key, int x, int y);
bool ignoreRepeats = false;
        //int i;
	//int a;
        int coord1 = 0;
        int direction = 1;
	int coord2 = 0;
	int coord3 = -25;
	int coord4 = -22;
	int coord5 = 0;
	int coord6 = -25;
	int coord7 = 22;
	int coord8 = 0;
	int coord9 = -25;
	int angle1 = 0;
	int gamepaws = 0;
	double fps = 0;
	double time1, time2;
	//int red, green, blue, white;
	double score = 0;
	int sleepnsec = 100000000;
	int sleepsec = 0;
	char scorestring[sizeof(double)+33];

#include "calcs.h"
#include "loadbitmap.h"

#ifdef HAVE_LIBPTHREAD
int a;
#include "threads.h"
#endif

void createGLUTMenus() {

	int menu;

	// create the menu and
	// tell glut that "processMenuEvents" will 
	// handle the events
	menu = glutCreateMenu(processMenuEvents);
	
	//add entries to our menu
	//glutAddMenuEntry("Settings",SETTINGS);
	glutAddMenuEntry("Restart",RESTART);
	glutAddMenuEntry("Pause",PAUSED);
	glutAddMenuEntry("Exit",EXIT);
	
	// attach the menu to the right button
	glutAttachMenu(GLUT_RIGHT_BUTTON);
}

void processMenuEvents(int option) {

	switch (option) {

		/*case SETTINGS :
			glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH );
			glutInitWindowPosition( 0, 0 );
			glutInitWindowSize( 800, 600 );
			glutCreateWindow( "Testing 123" );
        		// Initialize OpenGL.
    			//OpenGLInit();
        		// Set up the callback function for resizing windows
    			glutReshapeFunc( ResizeWindow );
			glutDisplayFunc( Setting);
			glutKeyboardFunc (keyboard);
			//glutMainLoop(  );
			break;
		*/
		case RESTART :
                	coord1 = 0;
                	direction = 1;
                	coord2 = 0;
                	coord3 = -25;
                	coord4 = -22;
                	coord5 = 0;
                	coord6 = -25;
        		coord7 = 22;
        		coord8 = 0;
        		coord9 = -25;
                	angle1 = 0;
			score = 0;
        		sleepnsec = 100000000;
        		sleepsec = 0;
			break;
		case PAUSED :
			if (gamepaws == 0){
				gamepaws = 1;
			}else{
				gamepaws = 0;
			}
			break;
		case EXIT :
			exit (0); 
			break;
	}
}


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

  switch (key) { 
    case GLUT_KEY_UP:
      break;

    case GLUT_KEY_DOWN:
      break;

    case GLUT_KEY_RIGHT:
	if ((angle1 != 6) && (coord5 >= -14) && (gamepaws == 0))
	{
		coord5--;
	}
      break;

    case GLUT_KEY_LEFT:
	//printf("left key pressed\n");
	if ((angle1 != 6) && (coord5 <= 14)&& (gamepaws == 0))
	{
		coord5++;

	}
      break;

 }

}
        
void keyboard(unsigned char key, int x, int y)
{
        if (key==27)
        {
                        //27 is the ascii code for the ESC key
        exit (0); //end the program
        }else if (key==13){
                coord1 = 0;
                direction = 1;
                coord2 = 0;
                coord3 = -25;
                coord4 = -22;
                coord5 = 0;
                coord6 = -25;
                coord7 = 22;
                coord8 = 0;
                coord9 = -25;
                angle1 = 0;
		score = 0;
                sleepnsec = 100000000;
                sleepsec = 0;

	}else if (key==112){
        	if (gamepaws == 0)
			gamepaws = 1;
                else
                        gamepaws = 0;

	}
		//if (key==
		//void glutDestroyWindow(int windowID);
}

/*
void keyboard2 (unsigned char key, int x, int y)
{

        if (key==13)
        {
                angle1=0;
        }

    
}
*/

int main( int argc, char** argv )   
{
	//int i;
        //int coord1 = 0;
        //int direction = 1;   
	//int angle1 = 0;
        glutInit(&argc,argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH );

        // Create and position the graphics window
	glutInitWindowPosition( 0, 0 );
	glutInitWindowSize( 1600, 1200 );
	glutCreateWindow( "lspong v0.1.3" );

        // Initialize OpenGL.
	OpenGLInit();
        // Set up the callback function for resizing windows
	glutReshapeFunc( ResizeWindow );
 
        // Callback for graphics image redrawing
	glutDisplayFunc( Animate);

	glutIgnoreKeyRepeat(ignoreRepeats);

	glutSpecialFunc(special);
	glutKeyboardFunc (keyboard);
	//glutKeyboardFunc (keyboard2);

	//glutSpecialFunc(special);
	createGLUTMenus();

	#ifdef HAVE_LIBPTHREAD
	pthread_t thread;
        pthread_attr_t attr;
        pthread_attr_init(&attr);
        //pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
	a = pthread_create(&thread, &attr, Calcs_Thread, NULL);
	#endif

	gettimeofday(&starttime, NULL);
        glutMainLoop(  );

	exit(1);
}

/*
static void Setting(void)
{
	int i = 0;
	char *settings = "Settings will go here.";
	char *settings2 = "Press ESC to close.";
	//settings[strlen(settings)-1]='\0';
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
                glLoadIdentity();
                glTranslatef ( 0.0, 0.0, -25 );
                glColor3f(1.0, 0.0, 0.0);
                glRasterPos2f(0.0, 0.0);
	//while(settings[i] != '/0')
	//{
	//char *c;
	//c=settings;
	while(*settings != '\0') 
	{
    		//glutBitmapCharacter(font, *c);
  		//}
		//}

		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,*settings);
		//i++;
		*settings++;
	}
        while(*settings2 != '\0')
        {
                glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,*settings2);
                //i++;
                *settings2++;
        }

	//glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'Y');

	sleep (3);
	//glutDestroyWindow(2);
        glFlush();
        glutSwapBuffers();   
        glutPostRedisplay();            // Request a re-draw for animation purposes
        glutDestroyWindow(2);

}
*/


int loaded = 0;
GLuint texture;
static void Animate(void)
{


obj_type cube = 
{
   {
      -10, -10, 10, // vertex v0
       10, -10, 10, // vertex v1
       10, -10, -10, // vertex v2
      -10, -10, -10, // vertex v3
      -10, 10, 10, // vertex v4
       10, 10, 10, // vertex v5
       10, 10, -10, // vertex v6 
      -10, 10, -10 // vertex v7
   }, 
   {
        0, 1, 4, // polygon v0,v1,v4
        1, 5, 4, // polygon v1,v5,v4
        1, 2, 5, // polygon v1,v2,v5
        2, 6, 5, // polygon v2,v6,v5
        2, 3, 6, // polygon v2,v3,v6
        3, 7, 6, // polygon v3,v7,v6
        3, 0, 7, // polygon v3,v0,v7
        0, 4, 7, // polygon v0,v4,v7
        4, 5, 7, // polygon v4,v5,v7
        5, 6, 7, // polygon v5,v6,v7
        3, 2, 0, // polygon v3,v2,v0
        2, 1, 0 // polygon v2,v1,v0
   },
   {
        0.0, 0.0, // mapping coordinates for vertex v0
        1.0, 0.0, // mapping coordinates for vertex v1
        1.0, 0.0, // mapping coordinates for vertex v2
        0.0, 0.0, // mapping coordinates for vertex v3
        0.0, 1.0, // mapping coordinates for vertex v4
        1.0, 1.0, // mapping coordinates for vertex v5
        1.0, 1.0, // mapping coordinates for vertex v6 
        0.0, 1.0 // mapping coordinates for vertex v7
   },
   0, // identifier for the texture 
};
	//char scorestring[sizeof(double)+33];
	int i = 0;
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	int empty = 0;
	//int loaded;
	//GLuint texture;


	if(loaded != 1) {
		texture = LoadTextureRAW("test.bmp", 0);
		//loaded = 1;
	}

glEnable(GL_TEXTURE_2D);
cube.id_texture=LoadBitmap("texture1.bmp");
if (cube.id_texture==-1)
{
   MessageBox(NULL,"Image file: texture1.bmp not found", "Zetadeck",MB_OK | MB_ICONERROR);
   exit (0);
}

glBindTexture(GL_TEXTURE_2D, cube.id_texture); 

glBegin(GL_TRIANGLES); 
for (l_index=0;l_index<12;l_index++)
{
   /*** FIRST VERTEX ***/
   glTexCoord2f( cube.mapcoord[ cube.polygon[l_index].a ].u,
                 cube.mapcoord[ cube.polygon[l_index].a ].v);
   glVertex3f( cube.vertex[ cube.polygon[l_index].a ].x,
               cube.vertex[ cube.polygon[l_index].a ].y,
               cube.vertex[ cube.polygon[l_index].a ].z);

   /*** SECOND VERTEX ***/
   glTexCoord2f( cube.mapcoord[ cube.polygon[l_index].b ].u,
                 cube.mapcoord[ cube.polygon[l_index].b ].v);
   glVertex3f( cube.vertex[ cube.polygon[l_index].b ].x,
               cube.vertex[ cube.polygon[l_index].b ].y,
               cube.vertex[ cube.polygon[l_index].b ].z);

   /*** THIRD VERTEX ***/
   glTexCoord2f( cube.mapcoord[ cube.polygon[l_index].c ].u,
                 cube.mapcoord[ cube.polygon[l_index].c ].v);
   glVertex3f( cube.vertex[ cube.polygon[l_index].c ].x,
               cube.vertex[ cube.polygon[l_index].c ].y,
               cube.vertex[ cube.polygon[l_index].c ].z);
}
glEnd();





//std::cout << "the loaded texture ID was " << tex_ID << std::endl;
//glTexCoord2f(0,0 );


/*
glLoadIdentity();
glTranslatef ( 0.0, 0.0, -25 );
//glColor3f(1.0, 0.0, 0.0);
glBegin( GL_QUADS );
glTexCoord2d(0.0,0.0); glVertex2d(0.0,0.0);
glTexCoord2d(10,0.0); glVertex2d(10.0,0.0);
glTexCoord2d(10,10); glVertex2d(10.0,10.0);
glTexCoord2d(0.0,10); glVertex2d(0.0,10.0);
glEnd();

glDisable( GL_TEXTURE_2D );
*/
	#ifndef HAVE_LIBPTHREAD
	Calcs();
	#endif

	if(gamepaws == 0 && angle1 == 6){

		glLoadIdentity();
		glTranslatef ( 0.0, 0.0, -25 );

		glColor3f(1.0, 0.0, 0.0);//print timer in red
		glRasterPos2f(0.0, 0.0);
	
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'Y');
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'o');
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'u');
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,' ');
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'L');
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'o');
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'s');
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'e');
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'!');
		glRasterPos2f(-1.0, -1.0);
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'E');
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'n');
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'t');
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'e');
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'r');
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,' ');
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'t');
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'o');
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,' ');
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'C');
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'o');
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'n');
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'t');
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'i');
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'n');
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'u');
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'e');

	}

         
        glLoadIdentity();    
        glTranslatef ( coord1, coord2, coord3 );     
        glColor3f( 1.0, 1.0, 0.0 );
	glutSolidSphere( 0.50, 300, 300 );


        glLoadIdentity();
        glTranslatef ( coord7, coord8, coord9 );
        glColor3f( 2.0, 2.0, 0.0 );
        glRectf(-0.50f,2.00f, 0.50f, -2.00f);


	glLoadIdentity();
	glTranslatef ( coord4, coord5, coord6 );
	glColor3f( 2.0, 2.0, 0.0 );
	glRectf(-0.50f,2.00f, 0.50f, -2.00f);
	

	glLoadIdentity();
	glTranslatef ( 0.0, 0.0, -25 );
	glColor3f(1.0, 0.0, 0.0);
                glRasterPos2f(5.0, -17.0);
                glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'S');
                glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'c');
                glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'o');
                glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'r');
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'e');
                glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,':');
                glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,' ');
		scorestring[strlen(scorestring)-1]='\0';
		empty = sprintf(scorestring, "%lf", score);
		if( gamepaws == 1)
		{
			strcat(scorestring, " PAUSED, press p to continue");
		}
                for(i = 0; scorestring[i] != '\0'; i++)
                {
                        glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,scorestring[i]);
                    
                }

	
        if((angle1 != 6) && (gamepaws == 0))
        {       

		time2++;
		gettimeofday(&endtime, NULL);
		time1=((double)(endtime.tv_sec*1000000-starttime.tv_sec*1000000+endtime.tv_usec-starttime.tv_usec))/1000000;

		if (time1 >= 1)
		{
		fps = time2 / time1;
        	//printf("time1: %lf\n", time1);
                //fps = time2 / time1;
                gettimeofday(&starttime, NULL);
                time2 = 0;
		}

                glLoadIdentity();
                glTranslatef ( 0.0, 0.0, -25 );
                glColor3f(1.0, 0.0, 0.0);
                glRasterPos2f(17.0, 17.0);
                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, "%lf", fps);
         
                //printf("%lf\n", fps);
                for(i = 0; scorestring[i] != '\0'; i++)
                {
                        glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,scorestring[i]);
        
                }
        }



	glFlush();
	glutSwapBuffers();
	glutPostRedisplay();            // Request a re-draw for animation purposes

	
}


void renderBitmapString(
		float x, 
		float y, 
		float z, 
		void *font, 
		char *string) {  
  char *c;
  glRasterPos3f(x, y,z);
//glColor3f( 1.0, 1.0, 0.0 );
  for (c=string; *c != '\0'; c++) {
    glutBitmapCharacter(font, *c);
  }
//return (0);
}



void OpenGLInit(void)
{       
    glShadeModel( GL_FLAT );
    glClearColor( 0.0, 0.0, 0.0, 0.0 );
    glClearDepth( 1.0 );
    glEnable( GL_DEPTH_TEST );
}

static void ResizeWindow(int w, int h)
{
    float aspectRatio;
        h = (h == 0) ? 1 : h;
        w = (w == 0) ? 1 : w;
        glViewport( 0, 0, w, h );       // View port uses whole window
        aspectRatio = (float)w/(float)h;
        
        // Set up the projection view matrix (not very well!)
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    gluPerspective( 70.0, aspectRatio, 1.0, 30.0 );
        
        // Select the Modelview matrix
    glMatrixMode( GL_MODELVIEW );
}

