/**
* 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>

const int tamanho = 100;
static char arquivoEntrada[50] = "d:\\junufpe\\tg\\xyz\\boundary.xyz";

typedef struct _float{
  float valor;
  struct _float *next;
} Float;

typedef struct atomo {
  char simbolo[2];
	float coordX;
	float coordY;
	float coordZ;
	Float potencial;
	struct atomo *prev;
	struct atomo *next;
} Atomo;

typedef struct molecula {
	Atomo *listaAtomos;
    struct molecula *next;
} Molecula;

/***********************************************
Variáveis globais para as listas encadeadas
************************************************/
Atomo *listaAtomos = NULL, *atualAtomo = NULL;
Molecula *listaMoleculas = NULL, *atualMolecula = NULL;;
Float *floats = NULL, *atualFloat = 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 limpar();

void acharLigacoes();
float distancia(Atomo atomo1, Atomo atomo2);
float sqr(float valor);


/***********************************************
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));

		  floats = NULL;
		  // Percorre os parametros extras de cada atomo
		  if (!strcmp(atomo_new->simbolo, "XX") && !strcmp(atomo_new->simbolo, "Xe")) {
		    if (fscanf(in, "%.4f\n", &potencial)) { // potencial < 1, pois todo potencial é fracionario
				Float *float_new = (Float *) malloc (sizeof(Float));
				float_new->valor = potencial;
				if (floats) {
				  inserirFloat(float_new);
				} else {
				  float_new->next = NULL;
				  floats = atualFloat = float_new;
				}
			}
		  } // fim da leitura dos parametros extras

		  potencial = 1;
		  atomo_new->dados = floats;
		  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();
	limpar();
}


/*************************************************
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 inserirFloat(Float *float_new) {
    float_new->next = NULL;
    atualFloat->next = float_new;
	atualFloat = float_new;
}

void limpar(){
	desalocaMolecula(&listaMoleculas);
}

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 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->next && auxMol->listaAtomos){
		printf("%d\n",i++);
		Atomo *aux = auxMol->listaAtomos;
		while (aux->next && !aux->dados){
			Atomo *aux2 = auxMol->listaAtomos;
			while (aux2->next && !aux2->dados){
				float dist = distancia(*aux, *aux2);
				if (aux != aux2 &&  dist < 1.9 && dist > 0.4 && strcmp(aux->simbolo,"XX") != 0 &&
					strcmp(aux2->simbolo,"XX") != 0){ 
					printf("%s - %s: %.3f\n",aux->simbolo, aux2->simbolo, dist);
				} else {
					//printf("> %s - %s: %.3f\n",aux->simbolo, aux2->simbolo, dist);
				}
				aux2 = aux2->next;
			}
			aux = aux->next;
		}
		auxMol = auxMol->next;
	}
}

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){
    switch(elem){
		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;
		case 'Br': return 2.2f;
		case 'Cl': return 1.9f;
		case 'XX': return 2.0f;
		case 'Xe': return 2.0f;
		default: return 2.0f;
	}
}

