#pragma once

#include <iostream>
#include <vector>
#include <string>

#include <C2/lm/vector2.h>
#include <C2/lm/vector3.h>

#include <C2/graph/material.h>

#include "ObjPrimitive.h"

#include "../SubObject.h"



namespace lib_geo
{


class BaseMesh;
class BaseFace;
class BasePolyline;
class BaseMaterial;


class ObjGroupInfo
{
public:
	std::string m_Name;
};



//! Obj形式のマテリアル
class ObjMaterial
{
public:
	ObjMaterial(void)
	{
		m_FileDirPath.clear();
		m_Name.clear();
		m_TextureFileName.clear();
		m_NormalMapFileName.clear();

		m_Ambient.set( 0.0f , 0.0f , 0.0f );
		m_Diffuse.set( 0.0f , 0.0f , 0.0f );
		m_Specular.set( 0.0f , 0.0f , 0.0f );
		m_Shininess   = 1.0f;
		m_Ni          = 0.0f;
		m_Transparent = 1.0f;
		m_Illum       = 0;
	}

	void Clear(void)
	{
		ObjMaterial default_mat;
		(*this) = default_mat;
	}

	std::string GetTextureFilePath(void) const
	{
		// TODO : 絶対パスに対応していない
		return m_FileDirPath + m_TextureFileName;
	}

	std::string GetNormalMapFilePath(void) const
	{
		// TODO : 絶対パスに対応していない
		return m_FileDirPath + m_TextureFileName;
	}


public:
	std::string   m_Name;               //!< 読み込み元mtlファイル名
	std::string   m_FileDirPath;        //!< 読み込み元mtlが保存されているディレクトリパス
	std::string   m_TextureFileName;    //!< テクスチャファイル名
	std::string   m_NormalMapFileName;  //!< 法線マップテクスチャファイル名

	lm::vec3f     m_Ambient;
	lm::vec3f     m_Diffuse;
	lm::vec3f     m_Specular;
	float         m_Shininess;
	float         m_Ni;
	float         m_Transparent;
	int           m_Illum;
};


//! Obj形式マテリアルセットファイルの情報
class ObjMaterialGroup
{
public:
	std::string               m_Filename;
	std::vector<ObjMaterial>  m_Materials;
};


//! Obj形式のメッシュ
class ObjMesh
{
public:
	ObjMesh(void)
	{}

	void Clear(void)
	{
		m_Positions.clear();
		m_Normals.clear();
		m_UVs.clear();
		m_Faces.clear();

		m_Objects.clear();
		m_MaterialNames.clear();

		m_MaterialGroups.clear();
	}

	bool Load( const std::string& i_Filename );
	bool Save( const std::string& i_Filename ) const;
	bool LoadStream( std::istream& ist );
	bool SaveStream( std::ostream& ost ) const;

	void ConvertToBaseMesh( BaseMesh& o_mesh ) const;
	void ConvertToBaseMeshEachGroup( std::vector<BaseMesh>& o_mesh ) const;
	void ConvertToBaseMeshEachObject( std::vector<BaseMesh>& o_mesh ) const;

	void CreateMatIndexMap( std::vector<int>& MatNameIdxToID ) const;

protected:
	void ReadToNextLine( std::istream& ist );

	const std::vector<ObjMaterial>* GetPrimaryMaterials(void) const;

	void CopyVerts( BaseMesh& o_mesh ) const;

	void CopyMaterials( BaseMesh& o_mesh ) const;
	void CopyMaterial( BaseMaterial& mat_dst , const ObjMaterial& mat_obj ) const;
	void CopyColor(lib_graph::color4f& col, const lm::vec3f& v_col) const;

	void CopyFaces(BaseMesh& o_mesh) const;
	void CopyPolyline(BaseMesh& o_mesh) const;
	void CopyFaces(BaseMesh& o_mesh, size_t offset, size_t num_faces) const;
	void CopyFaces(BaseMesh& o_mesh, const std::vector<size_t>& fids) const;

	void CopyPolylines(BaseMesh& o_mesh, const std::vector<size_t>& lids) const;
	void CopyPolylineIndexBuffer(BasePolyline& bl, const ObjPolyline& ol) const;

	void CopyFaceIndexBuffer(BaseFace& bf, const ObjFace& of) const;

public:
	std::vector<lm::vec3f>          m_Positions;
	std::vector<lm::vec3f>          m_Normals;
	std::vector<lm::vec2f>          m_UVs;
	std::vector<ObjFace>            m_Faces;
	std::vector<ObjPolyline>        m_Polylines;

	std::vector<SubObject>          m_Objects;
	std::vector<ObjGroupInfo>       m_Groups;
	std::vector<std::string>        m_MaterialNames;

	std::vector<ObjMaterialGroup>   m_MaterialGroups;
};


}
