#pragma once

#include <LibGeo/Mesh/BaseMesh.h>
#include <LibGeo/CrossSection.h>

#include <vector>
#include <map>

#include "Image/GeomTexture.h"

#include "PolylineContext.h"
#include "TextureLib.h"
#include "Bone.h"



namespace geom
{


class GeomObject;


class VertexLinker
{
public:
	VertexLinker(void)
	{
		m_IsLoop = false;
	}

public:
	std::vector<int> m_VertLinks;
	bool             m_IsLoop;
};


class FaceGroup
{
public:
	FaceGroup(void) :
		m_GroupID(-1)
	{
	}

	bool IsEmpty(void) const
	{
		return m_Fids.empty();
	}

	int GetTopFid(void) const
	{
		if(m_Fids.empty())
			return -1;

		return m_Fids.front();
	}

	void ClearGroup(void)
	{
		m_Fids.clear();
		m_GroupID = -1;
	}

public:
	std::vector<int> m_Fids;
	int m_GroupID;
};


class MeshBuf
{
public:
	MeshBuf(GeomObject* parent = NULL) :
		m_MBufIdx(-1),
		m_WholeIndex(-1),
		m_Parent(parent),
		m_Visible(true),
		m_SelMatIdx(-1)
	{
	}

	void CreateAdjBufOnce(void);

	bool IsValidMaterialIdx(int idx) const;

	void ClearTexture(void);

	void CreateFaceMatGroup(void);

	void ClearSelect(void);

	void ClearAllBuf(void);

	bool HasTexture(void) const;

	GeomTextureSet* GetTextureFromFace(const lib_geo::BaseFace& f);
	GeomTextureSet* GetTexture(int idx);
	GeomTextureSet* GeSeltTexture(void);
	lib_geo::BaseMaterial* GetMaterial(int idx);
	lib_geo::BaseMaterial* GetSelMaterial(void);

	void CreateTextureBuf(size_t size);

	void UpdateBBox(void);
	void ResetIniBBox(void);

	const lm::range3f& GetBBox(void) const
	{
		return m_BBox;
	}

	const lm::range3f& GetBBoxIni(void) const
	{
		return m_BBoxIni;
	}

	size_t GetNumFaces(void) const
	{
		return m_Mesh.m_Faces.size();
	}

	size_t GetNumVerts(void) const
	{
		return m_Mesh.m_Verts.size();
	}

	void FlipFace(bool normal_only);

	void SwapVertSelect(int vidx);
	void SetVertSelect(int vidx, bool select);
	bool GetVertSelect(int vidx) const;

	void UpdateCrossSection(bool SplitGroup, const lib_geo::Plane& cutplane);

	void InitializeBuffer(void);

	void Triangulate(void);

	void InitColorTexture(int idx, const std::string& filepath, const std::string& name, const gl::TextureConfig& config);
	void InitNormalTexture(int idx, const std::string& filepath, const std::string& name, const gl::TextureConfig& config);
	gl::GlTexture* GetInitTexture(const std::string& filepath, const std::string& name, const gl::TextureConfig& config);

	void ReleaseTextureUnit(int mat_idx, TextureType type);
	void ReleaseTextureUnit(GeomTextureSet* ts, TextureType type);

	GeomObject* GetParent(void);
	const GeomObject* GetParent(void) const;

	int GetDecWholeIdx(void) const;
	static int DecodeWholeIdx_Obj(int id);
	static int DecodeWholeIdx_Mesh(int id);

	bool IsVisible(void) const;

	void SelectMatAuto(void);
	bool IsMatSelected(void) const;
	int GetSelMatIdx(void) const;
	void SetSelMatIdx(int mat_idx);
	bool IsSelectedMat(int mat_idx) const;

private:
	bool IsExistTextureLink(gl::GlTexture* tex);

public:
	int m_MBufIdx;
	int m_WholeIndex;

	bool m_Visible;
	std::string m_Name;

	lib_geo::BaseMesh                   m_Mesh;
	std::map<int, bool>                 m_SelVerts;

	std::map<int, FaceGroup>            m_FaceMatGroup;

	std::vector<VertexLinker>           m_VertLinkers;

	lib_geo::CrossSection               m_CrossSection;
	std::vector<lib_geo::CrossSection>  m_CrossSectionLog;

	PolylineContext                     m_PolylineContext;

	BoneDeform                          m_Bones;

	int m_SelMatIdx;

private:
	GeomObject*  m_Parent;

	lm::range3f  m_BBox;
	lm::range3f  m_BBoxIni;

	boost::ptr_vector<GeomTextureSet> m_Textures;
};


}
