vector<unsigned int> TetrahedMesh::getAdjecentTetraheds(unsigned int ind, arma::Mat<double> v) {

	vector<unsigned int> tetraIndices;
	Tetrahed tempTetra = mTetraheds->at(ind);
	vector<unsigned int> faceIndices = tempTetra.getFaceInd();
	int count = 0;

	for(int i=0; i<4;i++){

		 //get face
		Face & face = mFaces->at(faceIndices[i]);
		//get all vertices of that face
		HalfEdge* edge = &mHalfEdges->at(face.getEdgeInd());

		Vertex & v1 = mVertices->at(edge->getVertexInd());
		edge = &mHalfEdges->at(edge->getNextInd());

		Vertex & v2 = mVertices->at(edge->getVertexInd());
		edge = &mHalfEdges->at(edge->getNextInd());

		Vertex & v3 = mVertices->at(edge->getVertexInd());
		int index = face.getOppositeFaceInd();
		if  (index != -1 && (vecEquals(v, v1.getPosition()) || vecEquals(v, v2.getPosition()) || vecEquals(v, v3.getPosition()))){

			getAdjecent(mFaces->at(index).getTetrahedInd(), ind, &tetraIndices, v, count);
			break;
		}


	}
	return tetraIndices;

}
void TetrahedMesh::updatePosition(unsigned int tetraIndex, vector<arma::Mat<double> > vertexPos)
{
    Tetrahed tempTetra;
    tempTetra = mTetraheds->at(tetraIndex);

    vector<unsigned int> faceIndices = tempTetra.getFaceInd();
    set<unsigned int> vertexIndices;

     for(int i=0; i<4;i++){

        Face & face = mFaces->at(faceIndices[i]);

        HalfEdge* edge = &mHalfEdges->at(face.getEdgeInd());

        vertexIndices.insert(edge->getVertexInd());

        edge = &mHalfEdges->at(edge->getNextInd());
        vertexIndices.insert(edge->getVertexInd());

        edge = &mHalfEdges->at(edge->getNextInd());
        vertexIndices.insert(edge->getVertexInd());
    }

    set<unsigned int>::iterator iter = vertexIndices.begin();
    int count = 0;
    while(iter!=vertexIndices.end())
    {
        mVertices->at(*iter).setPosition(vertexPos[count]);
        iter++;
        count++;
    }

}
void TetrahedMesh::deconnect(vector<unsigned int> adjecentList, arma::Mat<double> v, unsigned int vIndex) {
	unsigned int vInd;
	Vertex temp;
	temp.setPosition(v);

	mVertices->push_back(temp);
	vInd = mVertices->size()-1;

	for (int j = 0; j < adjecentList.size(); j++) {

		vector<unsigned int> faceIndices = mTetraheds->at(adjecentList.at(j)).getFaceInd();

			for (int i = 0; i< faceIndices.size();i++) {

				Face & face = mFaces->at(faceIndices[i]);


				HalfEdge* edge = &mHalfEdges->at(face.getEdgeInd());

				Vertex & v1 = mVertices->at(edge->getVertexInd());

				if(vecEquals(v1.getPosition(),v)) {
					//mFaces->at(faceIndices[i]).setOppositeFaceInd(-1);
					edge->setVertexInd(vInd);

					break;
				}

				edge = &mHalfEdges->at(edge->getNextInd());

				Vertex & v2 = mVertices->at(edge->getVertexInd());

					if(vecEquals(v2.getPosition(),v)) {
					//mFaces->at(faceIndices[i]).setOppositeFaceInd(-1);
					edge->setVertexInd(vInd);


					break;
				}

				edge = &mHalfEdges->at(edge->getNextInd());

				Vertex & v3 = mVertices->at(edge->getVertexInd());

					if(vecEquals(v3.getPosition(),v)) {

					edge->setVertexInd(vInd);


					break;
				}



			}
	}
}
void TetrahedMesh::getAdjecent(unsigned int currentind, unsigned int baseind, vector<unsigned int> *tetraIndices, arma::Mat<double> v, int count){

	count += 1;


	Tetrahed tempTetra = mTetraheds->at(currentind);
	vector<unsigned int> faceIndices = tempTetra.getFaceInd();

	 for(int i=0; i<4;i++){
		bool check = false;
		 //get face
		Face & face = mFaces->at(faceIndices[i]);

		//get all vertices of that face
		HalfEdge* edge = &mHalfEdges->at(face.getEdgeInd());

		Vertex & v1 = mVertices->at(edge->getVertexInd());
		edge = &mHalfEdges->at(edge->getNextInd());

		Vertex & v2 = mVertices->at(edge->getVertexInd());
		edge = &mHalfEdges->at(edge->getNextInd());

		Vertex & v3 = mVertices->at(edge->getVertexInd());
		int index = face.getOppositeFaceInd();

	if (index != -1 && (vecEquals(v, v1.getPosition()) || vecEquals(v, v2.getPosition()) || vecEquals(v, v3.getPosition()))){


				currentind = mFaces->at(index).getTetrahedInd();
				if(currentind != baseind) {
				 for (int j = 0; j < tetraIndices->size(); j++) {
					 if (tetraIndices->at(j) == currentind) {
						 check = true;
						 break;
					 }
				 }
				 if (check == false) {

				 tetraIndices->push_back(currentind);

				 getAdjecent(currentind,  baseind, tetraIndices, v,count);
				 }


		 }
    }

	}


}
void TetrahedMesh::crackStructure(unsigned int ind, arma::Mat<double> eigVec) {

	Tetrahed tempTetra = mTetraheds->at(ind);

	vector<unsigned int> faceIndices = tempTetra.getFaceInd();
	vector<unsigned int> vertexIndices;

     for(int i=0; i<4;i++){

        Face & face = mFaces->at(faceIndices[i]);

        HalfEdge* edge = &mHalfEdges->at(face.getEdgeInd());

        vertexIndices.push_back(edge->getVertexInd());

        edge = &mHalfEdges->at(edge->getNextInd());
        vertexIndices.push_back(edge->getVertexInd());

        edge = &mHalfEdges->at(edge->getNextInd());
        vertexIndices.push_back(edge->getVertexInd());
    }

	 int size = vertexIndices.size();

	unsigned int rIndex = rand() % size;
	unsigned int vIndex = vertexIndices.at(rIndex);

	arma::Mat<double> v(3,1);

	v= mVertices->at(vIndex).getPosition();






	vector<unsigned int> adjecentList = getAdjecentTetraheds(ind, v);
	if (adjecentList.size() > 0) {
	determineLocationOfCrack(ind,adjecentList,v,eigVec,vIndex);
	}


}
void TetrahedMesh::AddFace(unsigned int vertexIndex1,unsigned int vertexIndex2, unsigned int vertexIndex3,unsigned int &faceIndex, vector<Face> *mFacesTemp, vector<HalfEdge> *mEdgesTemp, vector<Vertex> *mVerticesTemp)
{
    //add halfedges
    unsigned int edgeIndex1,edgeIndex2,edgeIndex3,edgeIndex4,edgeIndex5,edgeIndex6;
    AddHalfEdgePair(vertexIndex1,vertexIndex2,edgeIndex1,edgeIndex2, mEdgesTemp,mVerticesTemp);
    AddHalfEdgePair(vertexIndex2,vertexIndex3,edgeIndex3,edgeIndex4, mEdgesTemp,mVerticesTemp);
    AddHalfEdgePair(vertexIndex3,vertexIndex1,edgeIndex5,edgeIndex6, mEdgesTemp,mVerticesTemp);

    // Connect inner ring
    mEdgesTemp->at(edgeIndex1).setNextInd(edgeIndex3);
    mEdgesTemp->at(edgeIndex1).setPrevInd(edgeIndex5);

    mEdgesTemp->at(edgeIndex3).setNextInd(edgeIndex5);
    mEdgesTemp->at(edgeIndex3).setPrevInd(edgeIndex1);

    mEdgesTemp->at(edgeIndex5).setNextInd(edgeIndex1);
    mEdgesTemp->at(edgeIndex5).setPrevInd(edgeIndex3);

  	 // Finally, create the face, don't forget to set the normal
	Face *face = new Face();


    vector<Face>::iterator iter;
	iter = mFacesTemp->begin();
	int count = 0;
	while(iter != mFacesTemp->end()){

		HalfEdge* edge = &mEdgesTemp->at(iter->getEdgeInd());

		Vertex & v1 = mVerticesTemp->at(edge->getVertexInd());
		edge = &mEdgesTemp->at(edge->getNextInd());

		Vertex & v2 = mVerticesTemp->at(edge->getVertexInd());
		edge = &mEdgesTemp->at(edge->getNextInd());

		Vertex & v3 = mVerticesTemp->at(edge->getVertexInd());





	if (vecEquals(mVerticesTemp->at(vertexIndex1).getPosition(), v1.getPosition()) || vecEquals(mVerticesTemp->at(vertexIndex1).getPosition(), v2.getPosition()) || vecEquals(mVerticesTemp->at(vertexIndex1).getPosition(), v3.getPosition())){
		if(vecEquals(mVerticesTemp->at(vertexIndex2).getPosition(),v1.getPosition()) || vecEquals(mVerticesTemp->at(vertexIndex2).getPosition(), v2.getPosition()) || vecEquals(mVerticesTemp->at(vertexIndex2).getPosition(),v3.getPosition())){
			if(vecEquals(mVerticesTemp->at(vertexIndex3).getPosition(), v1.getPosition()) || vecEquals(mVerticesTemp->at(vertexIndex3).getPosition(),v2.getPosition()) || vecEquals(mVerticesTemp->at(vertexIndex3).getPosition(), v3.getPosition())){

				face->setOppositeFaceInd(count);
				iter->setOppositeFaceInd(mFacesTemp->size());
				//cout <<  "Count: " << count << endl;
				break;
			}

		}
		}
		count++;

		iter += 1;

	}

    // Connect the face to an edge
    face->setEdgeInd(edgeIndex1);

    mFacesTemp->push_back((*face));
	delete face;

    // Compute and assign a normal
    mFacesTemp->back().setNormal(FaceNormal(mFacesTemp->size() - 1, mFacesTemp, mEdgesTemp, mVerticesTemp));

    // All half-edges share the same left face (previously added)
    mEdgesTemp->at(edgeIndex1).setFaceInd(mFacesTemp->size() - 1);
    mEdgesTemp->at(edgeIndex2).setFaceInd(mFacesTemp->size() - 1);
    mEdgesTemp->at(edgeIndex3).setFaceInd(mFacesTemp->size() - 1);
    //also send back faceIndex
    faceIndex = mFacesTemp->size() - 1;



}
void TetrahedMesh::RenderEdges(int mode) {

	const int numTriangles = mFaces->size();

    for (int i = 0; i < numTriangles; i++){

		Face & face = mFaces->at(i);


    HalfEdge* edge = &mHalfEdges->at(face.getEdgeInd());

    Vertex & v1 = mVertices->at(edge->getVertexInd());
    edge = &mHalfEdges->at(edge->getNextInd());

    Vertex & v2 = mVertices->at(edge->getVertexInd());
    edge = &mHalfEdges->at(edge->getNextInd());

    Vertex & v3 = mVertices->at(edge->getVertexInd());

		if (mode == 0) {
			if (face.getOppositeFaceInd() != -1) {
			glColor3f(0.2f, 0.0f, 1.0f);

			glBegin(GL_LINES);
			glVertex3f(v1.getPosition()[0], v1.getPosition()[1], v1.getPosition()[2]);
			glVertex3f(v2.getPosition()[0], v2.getPosition()[1], v2.getPosition()[2]);
			glVertex3f(v2.getPosition()[0], v2.getPosition()[1], v2.getPosition()[2]);
			glVertex3f(v3.getPosition()[0], v3.getPosition()[1], v3.getPosition()[2]);
			glVertex3f(v3.getPosition()[0], v3.getPosition()[1], v3.getPosition()[2]);
			glVertex3f(v1.getPosition()[0], v1.getPosition()[1], v1.getPosition()[2]);
			glEnd();
			}

		}

		if (mode == 1) {
			if (face.getOppositeFaceInd() == -1) {
			glColor3f(0.2f, 0.0f, 1.0f);

			glBegin(GL_LINES);
			glVertex3f(v1.getPosition()[0], v1.getPosition()[1], v1.getPosition()[2]);
			glVertex3f(v2.getPosition()[0], v2.getPosition()[1], v2.getPosition()[2]);
			glVertex3f(v2.getPosition()[0], v2.getPosition()[1], v2.getPosition()[2]);
			glVertex3f(v3.getPosition()[0], v3.getPosition()[1], v3.getPosition()[2]);
			glVertex3f(v3.getPosition()[0], v3.getPosition()[1], v3.getPosition()[2]);
			glVertex3f(v1.getPosition()[0], v1.getPosition()[1], v1.getPosition()[2]);
			glEnd();
			}

		}

		if (mode == 2) {

			glColor3f(0.2f, 0.0f, 1.0f);

			glBegin(GL_LINES);
			glVertex3f(v1.getPosition()[0], v1.getPosition()[1], v1.getPosition()[2]);
			glVertex3f(v2.getPosition()[0], v2.getPosition()[1], v2.getPosition()[2]);
			glVertex3f(v2.getPosition()[0], v2.getPosition()[1], v2.getPosition()[2]);
			glVertex3f(v3.getPosition()[0], v3.getPosition()[1], v3.getPosition()[2]);
			glVertex3f(v3.getPosition()[0], v3.getPosition()[1], v3.getPosition()[2]);
			glVertex3f(v1.getPosition()[0], v1.getPosition()[1], v1.getPosition()[2]);
			glEnd();


		}
	}



}
void TetrahedMesh::RenderNormals(int mode) {


	const int numTriangles = mFaces->size();

    for (int i = 0; i < numTriangles; i++){

    Face & face = mFaces->at(i);

    HalfEdge* edge = &mHalfEdges->at(face.getEdgeInd());

    Vertex & v1 = mVertices->at(edge->getVertexInd());
    edge = &mHalfEdges->at(edge->getNextInd());

    Vertex & v2 = mVertices->at(edge->getVertexInd());
    edge = &mHalfEdges->at(edge->getNextInd());

    Vertex & v3 = mVertices->at(edge->getVertexInd());

	arma::Mat<double> vCenter, normal;
	normal = face.getNormal();
	float scale= 80;
	vCenter = (v1.getPosition()+v2.getPosition()+v3.getPosition())/3.0;

		if (mode == 0) {
			if (face.getOppositeFaceInd() != -1) {
			glColor3f(1.0f, 0.0f, 1.0f);
			glBegin(GL_LINES);
			glVertex3f(vCenter[0], vCenter[1], vCenter[2]);
			glVertex3f(vCenter[0]+normal[0]/scale, vCenter[1]+normal[1]/scale, vCenter[2]+normal[2]/scale);

			glEnd();
			}

		}

		if (mode == 1) {
			if (face.getOppositeFaceInd() == -1) {
			glColor3f(1.0f, 0.0f, 1.0f);
			glBegin(GL_LINES);
			glVertex3f(vCenter[0], vCenter[1], vCenter[2]);
			glVertex3f(vCenter[0]+normal[0]/scale, vCenter[1]+normal[1]/scale, vCenter[2]+normal[2]/scale);

			glEnd();
			}

		}

		if (mode == 2) {

			glColor3f(1.0f, 0.0f, 1.0f);
			glBegin(GL_LINES);
			glVertex3f(vCenter[0], vCenter[1], vCenter[2]);
			glVertex3f(vCenter[0]+normal[0]/scale, vCenter[1]+normal[1]/scale, vCenter[2]+normal[2]/scale);

			glEnd();


		}
  }

}
void TetrahedMesh::Render(int mode)
{

// Draw geometry

  const int numTriangles = mFaces->size();
  for (int i = 0; i < numTriangles; i++){

    Face & face = mFaces->at(i);
    face.setNormal(FaceNormal(i,mFaces, mHalfEdges, mVertices));
    HalfEdge* edge = &mHalfEdges->at(face.getEdgeInd());

    Vertex & v1 = mVertices->at(edge->getVertexInd());
    edge = &mHalfEdges->at(edge->getNextInd());

    Vertex & v2 = mVertices->at(edge->getVertexInd());
    edge = &mHalfEdges->at(edge->getNextInd());

    Vertex & v3 = mVertices->at(edge->getVertexInd());

		if(mode == 2){
			if (face.getOppositeFaceInd() == -1) {
			glColor3f(1.0f, 1.0f, 1.0f);

			glNormal3f(face.getNormal()[0], face.getNormal()[1], face.getNormal()[2]);

			glBegin(GL_TRIANGLES);
			glVertex3f(v1.getPosition()[0], v1.getPosition()[1], v1.getPosition()[2]);
			glVertex3f(v2.getPosition()[0], v2.getPosition()[1], v2.getPosition()[2]);
			glVertex3f(v3.getPosition()[0], v3.getPosition()[1], v3.getPosition()[2]);
			glEnd();
		}
		}

		if(mode == 1){
			if (face.getOppositeFaceInd() != -1) {
			glColor3f(1.0f, 1.0f, 1.0f);

			glNormal3f(face.getNormal()[0], face.getNormal()[1], face.getNormal()[2]);

			glBegin(GL_TRIANGLES);
			glVertex3f(v1.getPosition()[0], v1.getPosition()[1], v1.getPosition()[2]);
			glVertex3f(v2.getPosition()[0], v2.getPosition()[1], v2.getPosition()[2]);
			glVertex3f(v3.getPosition()[0], v3.getPosition()[1], v3.getPosition()[2]);
			glEnd();
			}
		}

		if(mode == 0){

			glColor3f(1.0f, 1.0f, 1.0f);

			glNormal3f(face.getNormal()[0], face.getNormal()[1], face.getNormal()[2]);

			glBegin(GL_TRIANGLES);
			glVertex3f(v1.getPosition()[0], v1.getPosition()[1], v1.getPosition()[2]);
			glVertex3f(v2.getPosition()[0], v2.getPosition()[1], v2.getPosition()[2]);
			glVertex3f(v3.getPosition()[0], v3.getPosition()[1], v3.getPosition()[2]);
			glEnd();

		}

  }



}