#ifndef _mgTL2Triangles_HH_
#define _mgTL2Triangles_HH_

#include "mg/Pvector.h"
#include "Tl2/TL2Triangle.h"

/****************************************************************/
/*   Copyright (c) 2017 by System fugen G.K.                */
/*                       All rights reserved.                   */
/****************************************************************/

class MGFace;
class mgTL2Face;
class mgTL2Fans;
class mgTL2LPline;

/** @addtogroup UseTessellation
 *  @{
 */

///A vector of mgTL2Triangle's.

///mgTL2Triangle holds multiple triangles, and mgTL2Triangles holds vector of mgTriangle's.
///ポリゴンのベクトル保持クラス
class MG_DLL_DECLR mgTL2Triangles{

public:
	typedef MGPvector<mgTL2Triangle>::const_iterator const_iterator;
	typedef MGPvector<mgTL2Triangle>::iterator iterator;

friend std::ostream& operator<< (std::ostream& out, const mgTL2Triangles& tlTriangles);

//////////// constructor ///////////////

mgTL2Triangles(
	MGCL::TL_DATA_KIND dkind=MGCL::UV,
	///< Indicates if triangles's data is (u,v) data, (x,y,z) or (x,y,z) with the normal.
	///< =UV(0): (u,v) data. The space dimension of all the elements(MGPosition) of mgTL2Triangle is 2.
	///< =XYZ(1): (x,y,z) data. The space dimension of all the elements(MGPosition) of mgTL2Triangle is 3.
	///< =XYZNormal(2): (x,y,z) with (xn,yn,zn)=normal data. The space dimension of all the elements(MGPosition)
	///<     of mgTL2Triangle is 6 and includes (x,y,z,xn,yn,zn). Here (xn,yn,zn) is the unit normal
	///<     at the position (x,y,z) of the surface.
	const MGSurface* surf=0
);

///Copy constructor.
mgTL2Triangles(const mgTL2Triangles& tris);

//////////// operator overload ////////////

///Return the i-th mgTL2Triangle.
const mgTL2Triangle& operator[](int i)const;
mgTL2Triangle& operator[](int i);

////////// member function /////////////
iterator begin(){return m_triangles.begin();}
iterator end(){return m_triangles.end();}
const_iterator begin()const{return m_triangles.begin();}
const_iterator end()const{return m_triangles.end();}

mgTL2Triangle* front(){return m_triangles.front();};
mgTL2Triangle* back(){return m_triangles.back();};

const mgTL2Triangle* front()const{return m_triangles.front();};
const mgTL2Triangle* back()const{return m_triangles.back();};

///Return true if m_triangles' data is (u,v).
bool is_uv()const{return m_kind==MGCL::UV;};

///Make strip data from pline0 and pline2 and push back to this.
///The number of vertices of pline0 is greater or equal to the one of pline2.
///And the differecne must be at most 1.
void makeStrip(
	const mgTL2LPline& pline0,
	const mgTL2LPline& pline2
);

///Make fan data from plinen and pline0 and push back to this.
///The number of vertices of plinen is 2 or greater than 2.
///The fan is made from the pline0's start point to n vertices of plinen.
void makeFan(
	const mgTL2LPline& plinen,
	const mgTL2LPline& pline0
);

///Return true if m_triangles' data is (u,v).
bool need_normal()const{return m_kind==MGCL::XYZNormal;};

///return the data kind of this.
MGCL::TL_DATA_KIND get_kind()const{return m_kind;};

void push_back(mgTL2Triangle* pTlTriangle){m_triangles.push_back(pTlTriangle);};
void push_back(mgTL2Triangles& tris){m_triangles.push_back(tris.m_triangles);};

///Push back a triangel of type mgTESTRIANG_FAN.
///The veritces of the triangle is verticesIDs which are vertex id of fans.
void push_back(
	const mgTL2Fans& fans,///<Target to push back.
	int nvTri,///<Number of vertices in verticesIDs. generally nvTri!=verticesIDs.size().
	const std::vector<int>& verticesIDs///< Vertex ids.
);

int size()const{return int(m_triangles.size());};

void set_surface(const MGSurface* surf){m_surface=surf;};
const MGSurface* surface()const{return m_surface;};

///Do perform the tessellation for the mgTL2Plygon that has 3 or 4 edges outer loop, and
///that has no inner loops.
///The result will be appended onto triangles.
///When triangles.is_uv()=false, all of the element of the triangle position data has normal data as
///(x,y,z,xn,yn,zn). Here (x,y,z) is the position data and (xn,yn,zn) is the normal vector
///at the position (x,y,z).
///When triangles.is_uv()=true, all of the element of the triange position data are (u,v).
///Tessellated triangles will be appended.
void tessellate1234edgesLoop(
	const MGLoop& oloop//Outer boundary loop of the face of mgTL2Plygon
					//to tessellate whose number of edges is 4.
);

private:
	const MGSurface* m_surface;///<Surface pointer of this triangles.
	MGCL::TL_DATA_KIND m_kind;///< Indicates if m_triangles's data is (u,v) data,
				///< (x,y,z), or (x,y,z) with the normal.
	///< =UV(0): (u,v) data. The space dimension of all the elements(MGPosition) of mgTL2Triangle is 2.
	///< =XYZ(1): (x,y,z) data. The space dimension of all the elements(MGPosition) of mgTL2Triangle is 3.
	///< =XYZNormal(2): (x,y,z) with (xn,yn,zn)=normal data. The space dimension of all the elements(MGPosition)
	///<     of mgTL2Triangle is 6 and includes (x,y,z,xn,yn,zn). Here (xn,yn,zn) is the unit normal
	///<     at the position (x,y,z) of the surface.

	MGPvector<mgTL2Triangle> m_triangles;	///<ポリゴンのベクトル

	
///Tessellate a rectangle that has only 4 vertices, and puch back the tris to this.
void tessellate2by2(
	const mgTL2LPline&  pl,
	const mgTL2LPline&  pl_opposite
);

///Tessellate a rectangle that has only 4 edges, whose number of vertices are (2,2,2,n).
///Here n>=3. Tessellated tris are pushed back to this.
void tessellate222n(
	const mgTL2LPline& pl_id3,//edge that has 3 or more than 3 vetices.
	const mgTL2LPline& pl_opposite//opposite edge of pl_id3.
);

///Tessellate a rectangle that has 2 non-continuous edges of only 2 vertices.
///Tessellated triangles will be appended.
///pl.number_of_points()>=pl_opposite.number_of_points() is assumed.
void tessellate2n2n(
	const mgTL2LPline& pl,//an edge whose number of vetices is more than 2.
	const mgTL2LPline& pl_opposite//Opposite edge of pl.
);

///Tessellate a rectangle that has 2 continuous edges of only 2 vertices.
///Tessellated triangles will be appended.
void tessellate22nn(
	int id2,	//id of edge that has 2 vertices. Next edge of id2 also have only 2 vertices.
	const mgTL2LPline pline[4]
);

///Do perform the tessellation for the mgTL2Plygon that has 2 edges as the boundary.
///The result will be appended onto triangles.
///Tessellated triangles will be appended.
void tessellate2(
	const mgTL2LPline LPline[2]
);

///Tessellate a rectangle in case that one of the edges has
///2 or 3 vertices,and the other 3 edges have 3, or more than 3 vertices.
///Tessellated triangles will be appended.
void tessellate3nnn(
	int id3,	//id of edge that has 2 or 3 vertices.
	const mgTL2LPline pline[4]
);

///Do perform the tessellation for the mgTL2Plygon that has 3 edges as the boundary.
///The result will be appended onto triangles.
void tessellate3(
	const mgTL2LPline LPline[3]
);

//Tessellate a rectangle of a General case.
//All of the four edges have 4 or more than 4 vertices.
//Tessellated triangles will be appended.
void tessellate_nnnn(
	int minID,
	const mgTL2LPline pline[4]
);

///Tessellate a polygon pline whose two opposing edges' number of vertices
///are the same and the other edges' numbers of vertices differ at most 1.
///Let id0=maxID, id1=(id0+1)%4, id2=(id0+2)%4, id3=(id0+3)%4.
///Then the number of vertices of id1 and id3 are the same.
///The number of id0 is greater or equal to id2, and the difference is
///at most 1.
///Tessellated triangles will be appended.
void tessellate_nm(
	int maxID,
	const mgTL2LPline pline[4]
);
///Do perform the tessellation for the mgTL2Plygon that has 4 edges as the boundary.
///The result will be appended onto triangles.
///When triangles.is_uv()=false, all of the element of the triangle position data has normal data as
///(x,y,z,xn,yn,zn). Here (x,y,z) is the position data and (xn,yn,zn) is the normal vector
///at the position (x,y,z).
///When triangles.is_uv()=true, all of the element of the triange position data are (u,v).
///Input pline[i] is used as 
void tessellate4(
	const mgTL2LPline LPline[4]
);

///Do perform the tessellation for a concave rectangle.
///The result will be appended onto triangles.
///Tessellated triangles will be appended.
void tessellateConcave4(
	int concaveID,	//vertiex id at which vertex concavity is detected.
	const mgTL2LPline LPline[4]
);

///Do perform the tessellation for a sharp vertex rectangle.
///The result will be appended onto triangles.
///Tessellated triangles will be appended.
void tessellateSharp4(
	int sharpID,	//vertiex id at which sharpness is detected.
	const mgTL2LPline LPline[4]
);

};

/** @} */ // end of UseTessellation group
#endif
