#include "include.h"

int width = 512;	// ancho actual de la ventana; el valor lo mantiene reshape().
int height = 512;	// alto actual de la ventana; el valor lo mantiene reshape().

int mspf = MILLISECONDS_PER_FRAME;

Pantalla * actual;
Pantalla * menu;
Pantalla * juego;

Pantalla * getPantallaActual() {
	return actual;
}

Pantalla * getMenu() {
	return menu;
}

Pantalla * getJuego() {
	return juego;
}

void setJuego(Pantalla * j) {
	juego = j;
}

void goTo(Pantalla * p) {
	actual = p;

	glPopAttrib();
	glPushAttrib(GL_ALL_ATTRIB_BITS);

	p->init();
	p->reshape(width, height);
}


/**
 *  Función para realizar inicializaciones.
 *  
 */
void init() {
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glEnable(GL_LINE_SMOOTH);
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LESS);
	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

	goTo(getMenu());

	glPushAttrib(GL_ALL_ATTRIB_BITS);
}


/**
 *  Función timer que se llama una y otra vez para realizar la animación. 
 */
void timer(int id) {
	time_t antes = time(&antes);
	
	getPantallaActual()->timer();
	glutPostRedisplay();

	time_t despues = time(&despues);
	unsigned int sleep = Config::msPorFrame - (despues - antes);
	if (sleep < 0) sleep = 0;
	glutTimerFunc(sleep, timer, id++);
}

/**
 *  Esta función se llama siempre y cuando se necesite redibujar la ventana.
 *  Para forzar ser llamada se puede llamar a la subrutina glutPostRedisplay().
 */
void display() {
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	getPantallaActual()->display();

	glFlush();
	glutSwapBuffers();        // No comentar esta función 
}

/**
 *  Se llama a esta función cuando se cambia el tamaño de la ventana.
 *  No es necesario cambiar esta función
 */
void reshape(int newWidth, int newHeight) {
	//glViewport(0, 0, newWidth, newHeight);
	height = newHeight;
	width = newWidth;
	getPantallaActual()->reshape(width, height);
}

/**
 *  Se llama a esta función cuando se presiona o suelta los botones
 *  del mouse.
 */
void mouse(int button, int state, int x, int y) {
	getPantallaActual()->mouse(button, state, x, y);
}

/**
 *  Se llama a esta función al mover el mouse.
 */
void motion(int x, int y) {
	getPantallaActual()->motion(x, y);
}

/**
 *  Se llama a esta función cuando el usuario presiona cualquier caracter
 *  en el teclado.
 */
void keyboard(unsigned char key, int x, int y) {
	Keyboard::getInstance()->keyDown(key);
	getPantallaActual()->keyboard(key, x, y);
}

void keyboardUp(unsigned char key, int x, int y) {
	Keyboard::getInstance()->keyUp(key);
}

/**
 *  Se llama a esta función al presionar ciertas teclas especiales
 *  como las teclas de función y las flechas.
 */
void special(int key, int x, int y) {
	/* guardo estado de teclas del juego */
	Keyboard::getInstance()->specialDown(key);
	/* segun el estado del juego invoco a la funcion correspondiente */
	getPantallaActual()->special(key, x, y);
}

void specialUp(int key, int x, int y) {
	/* guardo estado de teclas del juego */
	Keyboard::getInstance()->specialUp(key);
}

/**
 *  Se llama cuando no se tiene ningún evento a procesar.
 *  Se llama repetidas veces si el programa no hace nada.
 */
void idle() {
}


int main(int argc, char **argv) {

	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
	glutInitWindowSize(width, height);
	glutInitWindowPosition(150, 50);
	glutCreateWindow("Obligarorio");

	menu = new Menu();
	juego = new Juego();

	glutDisplayFunc(display);
	glutReshapeFunc(reshape);
	glutMouseFunc(mouse);
	//glutMotionFunc(motion);
	glutKeyboardFunc(keyboard);
	glutKeyboardUpFunc(keyboardUp);
	glutSpecialFunc(special);
	glutSpecialUpFunc(specialUp);
	//glutIdleFunc(idle);
	glutIgnoreKeyRepeat(1);
	glutPassiveMotionFunc(motion);
	glutTimerFunc(MILLISECONDS_PER_FRAME, timer, 1);

	init();
	glutMainLoop();

	return 0;
}

