
/* Copyright (c)Christopher L. Pelech, 2014. */

/* This program is freely distributable without licensing fees 
   and is provided without guarantee or warrantee expressed or 
   implied. This program is -not- in the public domain. */

#include <iostream>
#include <stdio.h>
#include <Windows.h>
#include <GL/glut.h>
#include "Tetris.h"
using namespace std;


/******************************************/
/* Global Variables                       */ 
/******************************************/

	//Tetris Test
		Tetris myGame;

	//Light vars
		GLfloat light_diffuse[] = {1.0, 1.0, 1.0, 1.0};  /* Red diffuse light. */
		GLfloat light_position[] = {1.0, 1.0, 1.0, 0.0};  /* Infinite light location. */
	
	//Demo Cube
		GLfloat n[6][3] = {  /* Normals for the 6 faces of a cube. */
				  {-1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 0.0, 0.0},
				  {0.0, -1.0, 0.0}, {0.0, 0.0, 1.0}, {0.0, 0.0, -1.0} };
		GLint faces[6][4] = {  /* Vertex indices for the 6 faces of a cube. */
					{0, 1, 2, 3}, {3, 2, 6, 7}, {7, 6, 5, 4},
					{4, 5, 1, 0}, {5, 6, 2, 1}, {7, 4, 0, 3} };
		GLfloat v[8][3];  /* Will be filled in with X,Y,Z vertexes. */


	
	//Camera values
		float azimth = 0;
		float elevation = 0;
		float zoomDst = 75;

		const GLfloat NEAR_VIEWING_PLANE = 1.0;
		const GLfloat FAR_VIEWING_PLANE = 5000.0;
		const GLfloat FOVY = 60.0;

	//Time values
		int oldTimeSinceStart = 0;
		#define FRAMES_PER_SECOND 60;
		const int TIMER_FUNC_DELAY=1000/FRAMES_PER_SECOND;
	
	//Keyboard vars
		bool* keyStates = new bool[256];
		bool* keySpecialStates = new bool[256];

	//Window Vars
		static int     win_width, win_height;
		int windowWidth = 800;
		int windowHeight = 800;

	//Other Vars
		float speed = 0.25f;
		float Rot_y =0.0f; 

/******************************************/
/* Ligt vars                            */ 
/******************************************/
	void initLightEnvironment( void )
	{	
		float  light0_position[] = { 0.0, 0.0, 0.0, 1.0 };
		float  light0_diffuse[] =  { 0.1, 0.1, 0.4, 1.0 };           //Light Colour, maybe attempt to create a light/day effect?
		float  light0_specular[] = { 1.0, 1.0, 1.0, 1.0 };
		float  light0_ambient[] =  { 0.1, 0.1, 0.1, 1.0 };
		glLightfv( GL_LIGHT0, GL_POSITION, light0_position );
		glLightfv( GL_LIGHT0, GL_DIFFUSE, light0_diffuse );
		glLightfv( GL_LIGHT0, GL_SPECULAR, light0_specular );
		glLightfv( GL_LIGHT0, GL_AMBIENT, light0_ambient );
		glEnable( GL_LIGHT0 );
		glEnable( GL_LIGHTING );
		glEnable( GL_COLOR_MATERIAL );
		glEnable( GL_DEPTH_TEST );
		glCullFace( GL_BACK );
		glEnable( GL_CULL_FACE );
	}

/******************************************/
/* Window Rez                             */ 
/******************************************/
	void reshape (int w, int h) {
		glViewport (0, 0, (GLsizei)w, (GLsizei)h); //set the viewport to the current window specifications
		glMatrixMode (GL_PROJECTION); //set the matrix to projection
		glLoadIdentity ();
		gluPerspective (60, (GLfloat)w / (GLfloat)h, 1.0, 500.0); //set the perspective (angle of sight, width, height, , depth)
		glMatrixMode (GL_MODELVIEW); //set the matrix back to model
		windowWidth = w;	windowHeight = h;
		win_width = w; 	win_height = h;
	}

/******************************************/
/* Keyboard		                          */ 
/******************************************/
	void keyboard (unsigned char key, int x, int y) {
		keyStates[key] = true;

		if (key=='1'){
			ShowWindow( GetConsoleWindow(), SW_HIDE );
		}else if(key=='2'){
			ShowWindow( GetConsoleWindow(), SW_RESTORE );
			printf("Window Open");
		}
	
	}


	void processSpecialKeys(int key, int x, int y)
	{
		keySpecialStates[key] = true;
		switch(key) {
			  case GLUT_KEY_UP :
					//printf("up");
			  break;
			  case GLUT_KEY_DOWN:
					//printf("down");
			  break;
			  case GLUT_KEY_LEFT:
				  myGame.MoveLeft();
			  break;		
			  case GLUT_KEY_RIGHT:
				  myGame.MoveRight();
			  break;
			  }
	}

	void keyUp (unsigned char key, int x, int y) {  
		keyStates[key] = false;
	}


	void keySpecialUp (int key, int x, int y) {
		keySpecialStates[key] = false;
	} 

/******************************************/
/* Mouse Functions                        */ 
/******************************************/
	void  motion( int mx, int my ){
		
	}

	void  mouse( int button, int state, int mx, int my ){

	}
	void mouseMovement(int x, int y) {
		//if (x==0||x>(win_width/3)*2){
		//glutWarpPointer(win_width/2, y);
		//}

	}
/******************************************/
/* Other Functions                        */ 
/******************************************/
void drawBox(void)
{
  int i;

  for (i = 0; i < 6; i++) {
    glBegin(GL_QUADS);
    glNormal3fv(&n[i][0]);
    glVertex3fv(&v[faces[i][0]][0]);
    glVertex3fv(&v[faces[i][1]][0]);
    glVertex3fv(&v[faces[i][2]][0]);
    glVertex3fv(&v[faces[i][3]][0]);
    glEnd();
  }
}


/******************************************/
/* Update Functions                       */ 
/******************************************/
	void update(void)
	{
		int timeSinceStart = glutGet(GLUT_ELAPSED_TIME);
		int deltaTime = timeSinceStart - oldTimeSinceStart;
		oldTimeSinceStart = timeSinceStart;
		Rot_y+= speed * deltaTime;  //Update by time and constant speed
		if(Rot_y>360.0f)Rot_y=0.0f;

		//Send deltaT to any functions who need it
		myGame.Update_timer(deltaTime);

	}


/******************************************/
/* Display		                          */ 
/******************************************/
	void display(void)
	{
		//update vars
			update();
		//Clear whats currently rendered to screen/memory
			glClearColor (0.0f, 0.0f, 0.0f, 1.0f);
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		//Apply transforms 
			glPushMatrix();
				//glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, myGame.line_count);
				//glRotatef(Rot_y,0.0f,1.0f,0.0f);
				//glutSolidCube(1.0f);
				//drawBox();
			glPopMatrix();

		//Tetris Test
			//view update func for time call
			myGame.UpdateGrid();
			myGame.DrawGrid();

		//Redraw the screen
			glutSwapBuffers();
	}

/******************************************/
/* Init Vars	                          */ 
/******************************************/
	void init(void)
	{
	  /* Setup cube vertex data. */
	  v[0][0] = v[1][0] = v[2][0] = v[3][0] = -1;
	\4][0] = v[5][0] = v[6][0] = v[7][0] = 1;
	  v[0][1] = v[1][1] = v[4][1] = v[5][1] = -1;
	  v[2][1] = v[3][1] = v[6][1] = v[7][1] = 1;
	  v[0][2] = v[3][2] = v[4][2] = v[7][2] = 1;
	  v[1][2] = v[2][2] = v[5][2] = v[6][2] = -1;

	  /* Enable a single OpenGL light. */
		 initLightEnvironment();
	

	  /* Use depth buffering for hidden surface elimination. */
	  glEnable(GL_DEPTH_TEST);

	  /* Setup the view of the cube. */
	  glMatrixMode(GL_PROJECTION);
	  gluPerspective( /* field of view in degree */ 40.0,
					  /* aspect ratio */ 1.0,
					  /* Z near */ 1.0, 
					  /* Z far */ 10.0);
	  glMatrixMode(GL_MODELVIEW);
	  gluLookAt(5.5, 11.0, 25.0,		/* eye is at (0,0,5) */
				5.5, 11.0, -25.0,      /* center is at (0,0,0) */
				0.0, 1.0, 0.);      /* up is in positive Y direction */

	  /* Adjust cube position to be asthetic angle. */
	  //glTranslatef(0.0, 0.0, -1.0);
	  //glRotatef(60, 1.0, 0.0, 0.0);
	  //glRotatef(-20, 0.0, 0.0, 1.0);
	}


/******************************************/
/* Main			                          */ 
/******************************************/
	int main(int argc, char **argv)
	{
		glutInit(&argc, argv);
		glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
		glutInitWindowSize (windowWidth, windowHeight); //set the window size
		glutInitWindowPosition (0, 0); //set the position of the window    
		glutCreateWindow("red 3D lighted cube");
		
		init();
		glutDisplayFunc(display);
		glutIdleFunc (display); //update any variables in display, display can be changed to anyhing, as long as you move the variables to be updated, in this case, angle++;
		glutReshapeFunc (reshape); //reshape the window accordingly
		glutKeyboardFunc (keyboard); //check the keyboard
		glutKeyboardUpFunc(keyUp); // Tell GLUT to use the method "keyUp" for key up events  
		glutSpecialFunc(processSpecialKeys);
		glutSpecialUpFunc(keySpecialUp); // Tell GLUT to use the method "keySpecialUp" for special up key events  
		glutMouseFunc( mouse );
		glutMotionFunc( motion);
		glutPassiveMotionFunc(mouseMovement); 


		//ShowWindow( GetConsoleWindow(), SW_HIDE ); //Hide the Console

	  glutMainLoop();
	  return 0;             /* ANSI C requires main to return int. */
	}
