/*! PROCEDIMIENTO GENERAL:
-Se empieza a leer el archivo generado por gmsh.
-Se ignoran los primeros 34 caracteres.
-Se coloca en la variable N_N el numero de nodos.
	OJO, los nodos pueden estar desordenados.

-Con un bucle "for" se leen tantas lineas como nodos existan.
	Se lee del archivo origen el INDICE, coordenada X, coordenada Y y la ultima columna que se ignorara.
	Se escribe en el archivo destino el valor cardinal "i" del bucle, y los datos coordenada X, coordenada Y, y fin de linea.
	Se crea la variable tipo MAP para almacena pares (viejo nodo, nuevo nodo)
-Se ignoran los siguientes 18 caracteres.
-Se coloca en la variable N_E el numero de elementos.
	OJO, puesto que se han rebautizado los nodos con un nuevo indice, habra que cambiar los nodos asociados a cada elemento.
-Con un bucle for se barren todos los elementos.
	Se lee el indice y el tipo de elemento.
	Segun el caso (mediante un switch) se trata cada elemento.
		En cada caso se leen los nodos y los atributos que se desean conseguir, el resto se pasa a ignore.
		En cada caso se escriben los datos en el archivo destino, respentando el indice original.
			Mediante la relacion map "newNode" se colocan los nuevos numeros de nodos que forman cada elemento.
		En las variables N_nf, N_edg, N_ele se van contando el numero de elementos de cada tipo.

-Se termina cada archivo con un "end" y se escribe el sumario en otro archivo.
*/


#include "g2f.h"
#include <iostream>
#include <string>
#include <map>
#include <stdlib.h>
#include <string.h>
#define EndLine 12
/* EnldLine es el numero de caracteres de la ultima linea de los archivos GMSH. Se utiliza para crear un vector de caracteres en el que se incrustara esta ultima linea. Si el vector queda vacio despues de ejecutarse el programa, es que no se ha leido correctamente esa ultima linea y por tanto hay un error en el archivo de entrada.
*/

using namespace std;

G2f::G2f( const char *ruta, const char *temporal ) // CONSTRUCTOR
{ // open Files //
	char *ptrRuta;
	int size=strlen(temporal);
	ptrRuta=new char[size+10];

	cout << "g2f.cpp: Archivo Gmsh (" << ruta << ")\n";
	fileIn.open(ruta, ios ::in ); // input file
		if(!fileIn.is_open()){ cout << "g2f.cpp: Problema al leer archivo de entrada\n";exit(0); }

	strcpy(ptrRuta,temporal); strncat(ptrRuta,"/g2f.node",9);
	fileNode.open(ptrRuta,ios :: out); // nodes
		if(!fileNode.is_open()){ cout << "g2f.cpp: Problema al crear archivo temporal\n";exit(0); }

	strcpy(ptrRuta,temporal); strncat(ptrRuta,"/g2f.edge",9);
	fileEdge.open(ptrRuta,ios :: out); // boundary elements
		if(!fileEdge.is_open()){ cout << "g2f.cpp: Problema al crear archivo temporal\n";exit(0); }

	strcpy(ptrRuta,temporal); strncat(ptrRuta,"/g2f.ele",8);
	fileEle.open(ptrRuta,ios :: out); // inside elements
		if(!fileEle.is_open()){ cout << "g2f.cpp: Problema al crear archivo temporal\n";exit(0); }

	strcpy(ptrRuta,temporal); strncat(ptrRuta,"/g2f.nodef",10);
	fileNodef.open(ptrRuta,ios :: out); // ?
		if(!fileNodef.is_open()){ cout << "g2f.cpp: Problema al crear archivo temporal\n";exit(0); }

	strcpy(ptrRuta,temporal); strncat(ptrRuta,"/g2f.ene",8);
	fileData.open(ptrRuta,ios :: out); // summary of elemets and nodes
		if(!fileData.is_open()){ cout << "g2f.cpp: Problema al crear archivo temporal\n";exit(0); }
} // end of constructor


/*! getOrder() representa la funcion principal de G2f, y es la que se encarga
de leer el archivo .msh y extraer y separar en distintos archivos los datos necesarios
para Femsii.
Segun va leyendo el archivo va mallado, va escribiendo en el archivo adecuando
asi que no necesita reservar memoria.
Al final de cada archivo incluye una "F" de fin. Ademas de un archivo extra con el tamanhio
de cada archivo generado. Si posteriormente el programa que lea los archivos encuentra
que tras completar el numero de interaciones marcadas por el archivo extra, no se encuentra
una F, el archivo estara corrupto.
*/
void G2f::getOrder(short unsigned precision)
{ // order and separate different types of nodes and elements in files. READ CONSTRUCTOR
	double corx, cory, ignore;		// X, Y values; ignore reads, numbers to ignore
	char trash,endfile[EndLine];		// ignore reads, characters to ignore; check file finish
	string EndElements ("$EndElements"); // to check file end --> file uncorrupt
	short unsigned type, atri;	// type of element (1, 2, 15), and atribute --- under 65000
	unsigned i,n1,n2,n3,	// for nodes
	INDICEE,			// fisrt colum of gmsh file
	N_edg=0,N_ele=0,N_nf=0;		// number of elementos for any type of elements
	map<unsigned,unsigned> newNode; // STL map declaration to store new and old index

	// NODES //
	fileNode.precision( precision ); // set precision to output fileNode
	for(int i=0;i<36 ;++i) fileIn >> trash; // don't need 34 firts characters
	fileIn >> N_N;
	cout << "g2f.cpp: (N_N) Nodes: " << N_N << '\n';	// number of nodes to screen: N_N
	for( i=0; i<N_N; i++){
		fileIn >> INDICEE >> corx >> cory >> ignore; // get information from input file
		fileNode << i << ' ' << corx << ' ' << cory << endl; // write to file a new first column
		newNode[INDICEE]=i; // storage a relation of old and new index
	}

	// ELEMENTS //
	for(i=0;i<18 ;i++) fileIn >> trash; // don't need next 18 characters
	fileIn>>N_E;
	cout << "g2f.cpp: (N_E) Elements: " << N_E << '\n'; // number of elements to screen: N_E
	for(i=0;i<N_E ;i++) {	// classifying and placing elements by type in its respective files
		fileIn >> INDICEE >> type;
		switch(type){
		case 15: //nodes
			fileIn >> ignore >> ignore >> atri >> ignore >> n1;
			fileNodef << INDICEE << ' ' << n1 << ' '<< atri << endl;
			N_nf=N_nf+1;
			break;
		case 1: //edge
			fileIn >> ignore >> ignore >> atri >> ignore >> n1 >> n2;
			fileEdge << INDICEE << ' ' << newNode[n1] << ' ' << newNode[n2] << ' ' << atri << endl;
			N_edg=N_edg+1;
			break;
		case 2: //triangle
			fileIn >> ignore >> ignore >> atri >> ignore >> n1 >> n2 >> n3;
			fileEle<<INDICEE<<' '<<newNode[n1]<<' '<<newNode[n2]<<' '<<newNode[n3]<<' '<<atri <<endl;
			N_ele=N_ele+1;
			break;
		} 
	}

	// after finish with elements must be $EndElements, else file is corrupted
	fileIn >> endfile;
	if (EndElements.compare(endfile) != 0){cout << "\nArchivo corrupto\n"; exit(0);}
	// leaving memory and files
	fileData << N_ele<<endl << N_N<<endl << N_edg<<endl << N_nf<<endl; // Summary of nodes and elements
	fileIn.close(); fileData.close();
	fileNode<<"F"; fileNode.close();
	fileEdge<<"F"; fileEdge.close();
	fileEle<<"F"; fileEle.close();
	fileNodef<<"F"; fileNodef.close();
	cout << "g2f.cpp: Archivos cerrados\n";
}
