#pragma once

#include"../Eigen/Dense"
#include<string>
#include<vector>

class Mesh_2D
{
public:
	void GetMesh(std::string str,std::string jstr);

	int GetNbrVertex();
	void GetVertex(int num, Eigen::Vector3d& vertex);

	int GetNbrEdge();
	int GetEdge(int numEdge,int numVertex);

	int GetNbrTri();
	int GetTri(int numTri,int numVertex);
	int GetEdgeOfTri(int numTri,int numEdge);
	int GetDomainOfTri(int numTri);

	int GetNbrEdges();
	void GetCoonOfEdges(int numEdges, Eigen::Vector2i& coonOfEdges);
	int GetDomainOfEdges(int numEdges);
	void GetNormOfEdges(int numEdgs, Eigen::Vector3d& normOfEdges);

	void GetIndexOfDomain(Eigen::VectorXi domain, Eigen::VectorXi& nodeIndex, Eigen::VectorXi& edgeIndex);
	void GetIndexOfDomain2(Eigen::VectorXi domain, Eigen::VectorXi& edgeIndex, Eigen::VectorXi& edgeNum);
	void GetIndexOfPBC(Eigen::MatrixXi PBC, Eigen::VectorXcd PBCData,
		Eigen::VectorXi& srcNodeIndex, Eigen::VectorXi& dstNodeIndex, Eigen::VectorXcd& nodePhi,
		Eigen::VectorXi& srcEdgeIndex, Eigen::VectorXi& dstEdgeIndex, Eigen::VectorXcd& edgePhi);
	void GetEdgesIndexOfDomain(int domain, Eigen::VectorXi& edgesIndex);

	void Test_ReadData(std::string str);
private:
	int _mNbrVertex = 0;
	Eigen::MatrixXd _mVertex;//n*3
	int _mNbrEdge = 0;
	Eigen::MatrixXi _mEdge;//n*2

	int _mNbrTri = 0;
	Eigen::MatrixXi _mTri;//n*3
	Eigen::MatrixXi _mEdgeOfTri;//n*3
	Eigen::VectorXi _mDomainOfTri;//n*1

	int _mNbrEdges = 0;
	Eigen::MatrixXi _mCoonOfEdges;//n*2
	Eigen::VectorXi _mDomainOfEdges;//n*1
	Eigen::MatrixXd _mNormOfEdges;//n*3

      int _mNbrCopyOfEdges = 0;
	Eigen::MatrixXi _mCopyOfEdges;//n*2
      int _mNbrCopyOfVertexs = 0;
	Eigen::MatrixXi _mCopyOfVertex;//n*2

	Eigen::MatrixXi _mInitTri;//n*3
	Eigen::VectorXi _mMappingOfVertex; //n*1
	Eigen::MatrixXi _mConnOfTri;//n*2
};

class Mesh_3D
{
public:
	void GetMesh(std::string str, std::string jstr);

	int GetNbrVertex();
	void GetVertex(int num, Eigen::Vector3d& vertex);

	int GetNbrEdge();
	int GetEdge(int numEdge, int numVertex);

	int GetNbrFace();
	int GetFace(int numFace, int numVertex);
	int GetFaceOfTet(int numTet, int numFace);

	int GetNbrTet();
	int GetTet(int numTet, int numVertex);
	int GetEdgeOfTet(int numTet, int numEdge);
	int GetDomainOfTet(int numTet);

	int GetNbrPrism();
	int GetPrism(int numPrism, int numVertex);
	int GetEdgeOfPrism(int numPrism, int numEdge);
	int GetDomainOfPrism(int numPrism);

	int GetNbrTri();
	int GetTri(int numTri, int numVertex);
	int GetDomainOfTri(int numTri);
	void GetCoonOfTri(int numTri, Eigen::Vector3i& connOfTri);

	int GetNbrQuad();
	int GetQuad(int numQuad, int numVertex);
	int GetDomainOfQuad(int numQuad);
	void GetCoonOfQuad(int numQuad, Eigen::Vector2i& coonOfQuad);

	void GetTriIndexOfDomain(Eigen::VectorXi domain, Eigen::VectorXi& edgeIndex);
	void GetTriIndexOfDomain2(Eigen::VectorXi domain, Eigen::VectorXi indexNum,
		Eigen::VectorXi& triIndex, Eigen::VectorXi& triNum);
	void GetIndexOfPBC(Eigen::MatrixXi PBC, Eigen::VectorXcd PBCData,
		Eigen::VectorXi& srcEdgeIndex, Eigen::VectorXi& dstEdgeIndex, Eigen::VectorXcd& edgePhi);
	void GetIndexOfPBC(const std::vector<Eigen::VectorXi>& srcDomains,
		const std::vector<Eigen::VectorXi>& dstDomains,
		const Eigen::VectorXcd& PBCData, const Eigen::VectorXd& pbcAngles,
		const Eigen::MatrixXd& pbcWaveVecs,
		Eigen::VectorXi& srcEdgeIndex, Eigen::VectorXi& dstEdgeIndex, Eigen::VectorXcd& edgePhi,
		bool useFaceStyleEdgeTol = false);
	void GetIndexOfPBCFaces(const std::vector<Eigen::VectorXi>& srcDomains,
		const std::vector<Eigen::VectorXi>& dstDomains,
		const Eigen::VectorXd& pbcAngles,
		const Eigen::MatrixXd& pbcWaveVecs,
		Eigen::VectorXi& srcFaceIndex, Eigen::VectorXi& dstFaceIndex, Eigen::VectorXcd& facePhi);

	void GetNormOfFace(int domain, Eigen::Vector3d& norm);
	void GetTriIndicesOfDomain(int domain, Eigen::VectorXi& triIndices);

	void BuildFaceTopology();

private:
	int _mNbrVertex = 0;
	Eigen::MatrixXd _mVertex;//n*3
	int _mNbrEdge = 0;
	Eigen::MatrixXi _mEdge;//n*2

	int _mNbrFace = 0;
	Eigen::MatrixXi _mFace;//n*3
	Eigen::MatrixXi _mFaceOfTet;//n*4

	int _mNbrTet = 0;
	Eigen::MatrixXi _mTet;//n*4
	Eigen::MatrixXi _mEdgeOfTet;//n*4
	Eigen::VectorXi _mDomainOfTet;//n*1

	int _mNbrPrim = 0;
	Eigen::MatrixXi _mPrism;//n*6
	Eigen::MatrixXi _mEdgeOfPrism;//n*9
	Eigen::VectorXi _mDomainOfPrism;//n*1

	int _mNbrTri = 0;
	Eigen::MatrixXi _mTri;//n*3
	Eigen::VectorXi _mDomainOfTri;//n*1
	Eigen::MatrixXi _mConnOfTri;//n*3  MeshType numMesh numFace 

	int _mNbrQuad = 0;
	Eigen::MatrixXi _mQuad;//n*4
	Eigen::VectorXi _mDomainOfQuad;//n*1
	Eigen::MatrixXi _mConnOfQuad;//n*2 numMesh numFace

	Eigen::MatrixXi _mCopyOfTri;//n*2
	Eigen::MatrixXi _mCopyOfQuad;//n*2
	int _mNbrCopyOfTri = 0;
	int _mNbrCopyOfQuad = 0;

	Eigen::MatrixXd _mNormOfFace;// maxDomain+1 * 3, indexed by domain id
};
