/*!\file:  CreateFaces.cpp
 * \brief: create faces from 2d mesh
 */ 

#include "../../classes/classes.h"
#include "../../shared/shared.h"

void CreateFaces(IoModel* iomodel){

	/*If faces are already present, exit*/
	if(iomodel->faces) return;

	/*Check Iomodel properties*/
	if(iomodel->dim!=2)             _error_("only 2d model are supported");
	if(iomodel->numberofvertices<3) _error_("not enough elements in mesh");
	_assert_(iomodel->elements);

	/*Intermediaries*/
	bool exist;
	int  i,j,v1,v2,v3;
	int  maxnbf,nbf;

	/*Maximum number of faces*/
	maxnbf = 3*iomodel->numberofelements;

	/*Initialize intermediaries*/
	int*  facestemp = xNew<int>(maxnbf*4);         /*format: [vertex1 vertex2 element1 element2]                */
	bool* exchange  = xNewZeroInit<bool>(maxnbf);  /*Faces are ordered, we need to keep track of vertex swapping*/
	for(i=0;i<maxnbf;i++) facestemp[i*4+3]=-1;     /*Initialize last column of faces as -1 (boundary edge)      */

	/*Initialize chain*/
	int* head_minv = xNew<int>(iomodel->numberofvertices);
	int* next_edge = xNew<int>(maxnbf);
	for(i=0;i<iomodel->numberofvertices;i++) head_minv[i]=-1;

	/*Initialize number of faces*/
	nbf = 0;

	for(i=0;i<iomodel->numberofelements;i++){
		for(j=0;j<3;j++){

			/*Get the two indices of the edge number j of the ith triangle*/
			v1 = iomodel->elements[i*3+j];
			if(j==2)
			 v2 = iomodel->elements[i*3+0];
			else
			 v2 = iomodel->elements[i*3+j+1];

			/*v1 and v2 must be sorted*/
			if(v2<v1){
				v3=v2; v2=v1; v1=v3;
			}

			/*This edge a priori has not been processed yet*/
			exist = false;

			/*Go through all processed faces connected to v1 and check whether we have seen this edge yet*/
			_assert_(v1>=0 & v1<iomodel->numberofvertices);
			for(int e=head_minv[v1]; e!=-1; e=next_edge[e]){
				if(facestemp[e*4+1]==v2){
					exist = true;
					facestemp[e*4+3]=i+1;
					break;
				}
			}

			/*If this edge is new, add it to the lists*/
			if(!exist){
				_assert_(nbf<maxnbf);

				/*Update faces*/
				facestemp[nbf*4+0] = v1;
				facestemp[nbf*4+1] = v2;
				facestemp[nbf*4+2] = i+1;
				if(v1!=iomodel->elements[i*3+j]) exchange[nbf]=true;

				/*Update chain*/
				next_edge[nbf] = head_minv[v1];
				head_minv[v1]  = nbf;

				/*Increase number of faces*/
				nbf++;
			}
		}
	}

	/*Clean up*/
	xDelete<int>(head_minv);
	xDelete<int>(next_edge);

	/*Create final faces*/
	int* faces = xNew<int>(nbf*4); /*vertex1 vertex2 element1 element2*/
	for(int i=0;i<nbf;i++){
		if(exchange[i]){
			faces[i*4+0]=facestemp[i*4+1];
			faces[i*4+1]=facestemp[i*4+0];
		}
		else{
			faces[i*4+0]=facestemp[i*4+0];
			faces[i*4+1]=facestemp[i*4+1];
		}
		faces[i*4+2]=facestemp[i*4+2];
		faces[i*4+3]=facestemp[i*4+3];
	}
	xDelete<int>(facestemp);
	xDelete<bool>(exchange);

	/*Assign output pointers*/
	iomodel->faces         = faces;
	iomodel->numberoffaces = nbf;
}
