#ifdef _WIN32
#include <windows.h>
#endif
#include "stdafx.h"
#include <GL/glut.h>
#include "atomo.h"

// Funçoes de DataXYZ
void lerArquivoXYZ(FILE *in);
void limpar();
float raioCovalente(char elem[2]);

// Funcoes deste arquivo
void drawCube();
void drawLine(float x1, float y1, float z1, float x2, float y2, float z2);
void drawLigacoes();
void drawMolecula(Molecula *mol);
int coloreElemento(char elem[2]);

static int NUM_LINHAS_LATITUDE = 100;
static int NUM_LINHAS_LONGITUDE = 100;

// Cores
float cores[][3] = 
{
	{0.0f, 0.0f, 0.0f},  // Branco
	{0.0f, 0.0f, 1.0f},  // Azul
	{0.0f, 1.0f, 0.0f},  // Verde
	{0.0f, 1.0f, 1.0f},  // Cyan
	{1.0f, 0.0f, 0.0f},  // Vermelho
	{1.0f, 0.0f, 1.0f},  // Magenta
	{1.0f, 1.0f, 0.0f},  // Amarelo
	{0.5f, 0.5f, 0.5f},  // Cinza
	{1.0f, 1.0f, 1.0f}  // Preto
};

// Cubo
GLfloat light_diffuse[] = {1.0, 1.0, 0.0, 1.0};  /* Red diffuse light. */
GLfloat light_position[] = {0.0, 0.0, 1.0, 1.0};  /* Infinite light location. */
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. */

/**
 Assinaturas dos métodos
 */
void RenderEsfera(GLdouble x, GLdouble y, GLdouble z, GLdouble raio);

void initVisual()
{
  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

  /* Setup cube vertex data. */
  v[0][0] = v[1][0] = v[2][0] = v[3][0] = -1;
  v[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. */
  /*glLightfv(GL_LIGHT0, GL_AMBIENT , light_diffuse);
  glLightfv(GL_LIGHT0, GL_POSITION, light_position);
  glEnable(GL_LIGHT0);
  glEnable(GL_LIGHTING);
*/
  /* Use depth buffering for hidden surface elimination. */
  glEnable(GL_DEPTH_TEST);

  /* Setup the view of the cube. */
  glMatrixMode(GL_PROJECTION);
  
  // Seta a matriz de projeção perspectiva
  gluPerspective( /* field of view in degree */ 40.0,
    /* aspect ratio */ 1.0,
    /* Z near */ 1.0, /* Z far */ 10.0);
  
  glMatrixMode(GL_MODELVIEW);

  // Seta a matriz de visualizaçao
  gluLookAt(0.0, 0.0, 5.0,  /* eye is at (0,0,5) */
    0.0, 0.0, 0.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.5);
  glRotatef(-45, 0.0, 1.0, 0.0);
  glRotatef(-45, 0.0, 0.0, 1.0);
  //glRotatef(-20, 0.0, 0.0, 1.0);

}

void DisplayVisual()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	

	// Seta o tipo de matriz que será utilizado
	// http://www.opengl.org/developers/documentation/man_pages/hardcopy/GL/html/gl/matrixmode.html?glMatrixMode#first_hit
//	glMatrixMode(GL_MODELVIEW); 
	
	// Carrega a matriz identidade
//	glLoadIdentity();
	
	drawCube();
    drawMolecula(listaMoleculas);
	drawLigacoes();
/*
	RenderEsfera(0,0,0,0.05);
	RenderEsfera(0,0,1,0.05);
	drawLine(0,0,0,0,0,1);
	RenderEsfera(1,0,0,0.05);
	drawLine(0,0,1,1,0,0);
	RenderEsfera(0,1,0,0.05);
	drawLine(1,0,0,0,1,0);
	RenderEsfera(1,1,0,0.05);
	drawLine(0,1,0,1,1,0);
	RenderEsfera(0,1,1,0.05);
	drawLine(1,1,0,0,1,1);\
	RenderEsfera(1,1,1,0.05);
	drawLine(0,1,1,1,1,1);
*/
	// Mudança de escala
	// http://www.opengl.org/developers/documentation/man_pages/hardcopy/GL/html/gl/scale.html?glScalef#first_hit
	//glScalef(2.5f, 2.5f, 2.5f);
     
	//RenderEsfera(1.0, 1.0, 1.0, 1);
	//glFinish();
	glutSwapBuffers();
}

void ReshapeVisual(int w, int h)
{
	glViewport(0, 0, (GLsizei)w, (GLsizei)h);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(60.0f, (GLfloat)w / (GLfloat) h, 1.0f, 20.0f);
	glMatrixMode(GL_MODELVIEW);
}
   
int main(int argc, char ** argv)
{
	FILE *in = NULL;
	lerArquivoXYZ(in);

	glutInit(&argc, argv);

	glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGB);
	glutInitWindowSize(640, 480);
	glutInitWindowPosition(0, 0);
	glutCreateWindow("VisualAGOA");

	glutDisplayFunc(DisplayVisual);
	initVisual();
	//glutReshapeFunc(ReshapeVisual);

	glutMainLoop();

	limpar();
	return 0;

}


void RenderEsfera(GLdouble x, GLdouble y, GLdouble z, GLdouble raio) {

	glPushMatrix();
	//  http://www.opengl.org/developers/documentation/man_pages/hardcopy/GL/html/gl/translate.html?glTranslatef#first_hit
    glTranslatef(x,y,z);    
	glutSolidSphere(raio, NUM_LINHAS_LATITUDE, NUM_LINHAS_LONGITUDE);

	glPopMatrix();
}


void drawCube(){
  int i;

  glScalef(1.2f, 1.2f, 1.2f);
  for (i = 0; i < 8; 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();
  }

}

void drawMolecula(Molecula *mol){
    Atomo *aux = mol->listaAtomos;

	while(aux){
		if (aux->potencial == 0) {
			int indexCor = coloreElemento(aux->simbolo);
			glColor3fv(cores[indexCor]);
		    RenderEsfera(aux->coordX, aux->coordY, aux->coordZ, 0.1);//raioCovalente(aux->simbolo));
		} else {
			glColor3fv(cores[0]);
		    //RenderEsfera(aux->coordX, aux->coordY, aux->coordZ, 0.1);//raioCovalente(aux->simbolo));
		}
		aux = aux->next;
	}
}

void drawLigacoes() {
    Ligacao *aux = listaLigacoes;
	Atomo *at1 = NULL, *at2 = NULL;

	while (aux) {
        at1 = aux->atomo1;
		at2 = aux->atomo2;
		drawLine(at1->coordX, at1->coordY, at1->coordZ, at2->coordX, at2->coordY, at2->coordZ);
		aux = aux->next;
	}
}

void drawLine(float x1, float y1, float z1, float x2, float y2, float z2){
   glColor3f(1.0, 0.0, 0.0);
   glBegin(GL_LINES);
     glVertex3f(x1, y1, z1);
	 glVertex3f(x2, y2, z2);
   glEnd();
}

int coloreElemento(char elem[2]){

    switch(elem[0]){
		case 'H': return 7; // Vermelho
		case 'C': return 1;
		case 'N': return 7;
		case 'O': return 6;
		case 'F': return 7;
	    case 'P': return 7;
		case 'S': return 7;
		default: {
			if (!strcmp(elem,"Br")) return 7;
		    if (!strcmp(elem,"Cl")) return 7;
			if (!strcmp(elem,"XX")) return 7;
			if (!strcmp(elem,"Xe")) return 7;
		
		}
		return 7;		
	}
}