/**
* Arquivo responsavel pela leitura e escrita dos arquivos XYZ
*/
#include "stdafx.h"
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <string.h>
#include <GL/glut.h>
#include "atomo.h"

const int tamanho = 100;
static char arquivoEntrada[50] = "h:\\public_html\\tg\\testes\\out\\boundary.xyz";

/***********************************************
Variáveis globais para as listas encadeadas
************************************************/
Atomo *listaAtomos = NULL;
extern Atomo *atualAtomo = NULL;
Molecula *listaMoleculas = NULL;
extern Molecula *atualMolecula = NULL;
extern Float *floats = NULL;
extern Float *atualFloat = NULL;
Ligacao *listaLigacoes = NULL;
extern Ligacao *atualLigacao = NULL;

/***********************************************
Assinatura das funções
************************************************/
void lerArquivoXYZ(FILE *in);
void escreverDadosXYZ();
void inserirAtomo(Atomo *atomo_new);
void inserirFloat(Float *float_new);
void inserirMolecula(Molecula *molecula_new);
void desalocaAtomo(Atomo **atual);
void desalocaMolecula(Molecula **atual);
void desalocaFloat(Float **listaFloats);
void desalocaLigacao(Ligacao **lista);
void limpar();
void acharLigacoes();
float distancia(Atomo atomo1, Atomo atomo2);
float sqr(float valor);
int testarAtomos(Atomo *atm1, Atomo *atm2);

/***********************************************
Funções Gráficas do Visual1
************************************************/
void RenderEsfera(GLdouble x, GLdouble y, GLdouble z, GLdouble raio);

/***********************************************
Funções para leitura do arquivo
************************************************/
void lerArquivoXYZ(FILE *in){

	int i = 0, numLinhas = 0;
	int jaLeuSoluto = 0;
	char texto[100] = "";
	float potencial;

	if (!(in=fopen(arquivoEntrada,"r+"))){
		printf ("\nErro na abertura do arquivo de entrada!");
		getch();
		exit(1);
	}
	
	while(fscanf(in, "%d\n", &numLinhas) != EOF) {
		fgets(texto, 100, in);
		printf(texto);
		// Percorre os atomos de uma molecula
		while (i < numLinhas) {
		  Atomo *atomo_new = (Atomo *) malloc (sizeof(Atomo));
  		  fscanf (in,"%s %f %f %f",&(atomo_new->simbolo),
									 &(atomo_new->coordX),
									 &(atomo_new->coordY),
									 &(atomo_new->coordZ));

		  atomo_new->potencial = 0.0f;
		  if (!strcmp(atomo_new->simbolo, "XX") || !strcmp(atomo_new->simbolo, "Xe")) {
		    if (fscanf(in, "%f\n", &potencial)) { 
				atomo_new->potencial = potencial;
			}
		  } 
		  if (listaAtomos) {
		    inserirAtomo(atomo_new);
		  } else {
		    listaAtomos = atualAtomo = atomo_new;
		    atomo_new->next = NULL;
		    atomo_new->prev = NULL;
		  }
		  i++; // contador de atomos na molecula
		} // Fim da leitura dos atomos
		i = 0;
		numLinhas = 0;
		Molecula *molecula_new = (Molecula *) malloc (sizeof(Molecula));
		molecula_new->listaAtomos = listaAtomos;
		listaAtomos = NULL;
		atualAtomo = NULL;
		molecula_new->next = NULL;
		if (molecula_new->listaAtomos) {
			if (listaMoleculas) {
			  inserirMolecula(molecula_new);
			} else {
			  listaMoleculas = atualMolecula = molecula_new;
			  molecula_new->next = NULL;
			}
		}
	}
	fclose(in);
	acharLigacoes();
}


/*************************************************
Armazenamento com lista encandeada
*************************************************/

void inserirAtomo(Atomo *atomo_new){
    atomo_new->next = NULL;
	atomo_new->prev = atualAtomo;
    atualAtomo->next = atomo_new;
	atualAtomo = atomo_new;
}

void inserirMolecula(Molecula *molecula_new){
    molecula_new->next = NULL;
    atualMolecula->next = molecula_new;
	atualMolecula = molecula_new;
}

void inserirLigacao(Ligacao *ligacao_new){
    ligacao_new->next = NULL;
    atualLigacao->next = ligacao_new;
	atualLigacao = ligacao_new;
}

void inserirFloat(Float *float_new) {
    float_new->next = NULL;
    atualFloat->next = float_new;
	atualFloat = float_new;
}

void limpar(){
	desalocaMolecula(&listaMoleculas);
	desalocaLigacao(&listaLigacoes);
}

void desalocaAtomo(Atomo **lista){
    Atomo *aux;
	while ((*lista)->next){
		aux = (*lista)->next;
        (*lista)->next = aux->next;
/*		if (aux->dados) {
		    desalocaFloat(&(aux->dados));
		}
*/		free(aux);
	}
/*	if ((*lista)->dados) {
		desalocaFloat(&((*lista)->dados));
	}
*/	free(*lista);
	*lista = NULL;
}

void desalocaMolecula(Molecula **lista){
    Molecula *aux;
	while ((*lista)->next){ 
		aux = (*lista)->next;
		(*lista)->next = aux->next;
		desalocaAtomo(&(aux->listaAtomos));
		free(aux);
	}
    desalocaAtomo(&((*lista)->listaAtomos));
	free(*lista);
	*lista = NULL;
}

void desalocaLigacao(Ligacao **lista){
    Ligacao *aux;
	while ((*lista)->next){ 
		aux = (*lista)->next;
		(*lista)->next = aux->next;
		free(aux);
	}
	free(*lista);
	*lista = NULL;
}

void desalocaFloat(Float **listaFloats){
    Float *aux;
	while ((*listaFloats)->next){ 
		aux = (*listaFloats)->next;
		(*listaFloats)->next = aux->next;
		free(aux);
	}
	free(*listaFloats);
	*listaFloats = NULL;
}

/***********************************************
Funções para processamento dos dados
************************************************/

/***********************************************
Achar os atomos que tem ligações
************************************************/
void acharLigacoes(){

	int i = 0;

	Molecula *auxMol = listaMoleculas;
	while (auxMol && auxMol->listaAtomos){
		printf("%d\n",i++);
		Atomo *aux = auxMol->listaAtomos;
		while (aux->next && strcmp(aux->simbolo,"XX") && strcmp(aux->simbolo,"Xe")){
			Atomo *aux2 = auxMol->listaAtomos;
			while (aux2->next && strcmp(aux2->simbolo,"XX") && strcmp(aux2->simbolo,"Xe")){
				
				if (testarAtomos(aux, aux2)){ 
					printf("%s - %s > %f\n",aux->simbolo, aux2->simbolo, distancia(*aux, *aux2));
					Ligacao *ligacao_new = (Ligacao *) malloc (sizeof(Ligacao));
					ligacao_new->atomo1 = aux;
					ligacao_new->atomo2 = aux2;
					ligacao_new->next = NULL;
					if (listaLigacoes) {
					    inserirLigacao(ligacao_new);
					} else {
						listaLigacoes = atualLigacao = ligacao_new;
						ligacao_new->next = NULL;					
					}
				} else {
					//printf("> %s - %s: %.3f\n",aux->simbolo, aux2->simbolo, dist);
				}
				aux2 = aux2->next;
			}
			aux = aux->next;
		}
		auxMol = auxMol->next;
	}
}

int testarAtomos(Atomo *atm1, Atomo *atm2) {
    float dist = distancia(*atm1, *atm2);
    return (atm1 != atm2 &&  dist < 1.9 && dist > 0.4 && 
		   strcmp(atm1->simbolo,"XX") && strcmp(atm1->simbolo,"Xe") &&
		    strcmp(atm2->simbolo,"XX") && strcmp(atm2->simbolo,"Xe") &&
		   (strcmp(atm1->simbolo,"H") || strcmp(atm2->simbolo,"H"))
		   );
}

float distancia(Atomo atomo1, Atomo atomo2){
	return (float) sqrt(
		      sqr(atomo1.coordX - atomo2.coordX) +
              sqr(atomo1.coordY - atomo2.coordY) +
		      sqr(atomo1.coordZ - atomo2.coordZ));
}

float sqr(float valor){
    return valor*valor;
}

float raioCovalente(char elem[2]){

    switch(elem[0]){
		case 'H': return 1.3f;
		case 'C': return 2.0f;
		case 'N': return 2.0f;
		case 'O': return 2.0f;
		case 'F': return 1.8f;
	    case 'P': return 2.0f;
		case 'S': return 2.0f;
		default: {
			if (!strcmp(elem,"Br")) return 2.2f;
		    if (!strcmp(elem,"Cl")) return 1.9f;
			if (!strcmp(elem,"XX")) return 2.0f;
			if (!strcmp(elem,"Xe")) return 2.0f;
		
		}
		return 0.0;
		
	}
}

