#pragma once

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


namespace lib_geo
{


class ObjMesh;


class FidSeparator
{
public:
	FidSeparator(void) :
		cntVal(1)
	{
	}

	void addHead(char* h)
	{
		strTop[cntVal] = h;
		cntVal++;
	}

	void toSeparator(char* s, size_t slen)
	{
		strTop[0] = &s[0];
		for (size_t j = 0; j < slen; j++)
		{
			if (s[j] == '/')
			{
				addHead(&s[j + 1]);
				s[j] = '\0';
			}
		}
	}

public:
	int cntVal;
	char* strTop[3];
};


class ObjMeshReader
{
public:
	bool Load( ObjMesh& mesh , const std::string& i_Filename );
	bool LoadStream( ObjMesh& mesh , std::istream& ist );

protected:
	bool LoadObjMain( ObjMesh& mesh , std::istream& ist , bool LoadMaterialFile );

	void InitializeWorkBuffer(void);

	void ReadVertLine           ( std::istream& ist , ObjMesh& mesh );
	void ReadNormLine           ( std::istream& ist , std::vector<lm::vec3f>& normals );
	void ReadUVLine             ( std::istream& ist , std::vector<lm::vec2f>& uvs );
	void ReadFaceLine           ( std::istream& ist , ObjMesh& mesh );
	void ReadPolylineLine       ( std::istream& ist , std::vector<ObjPolyline>& lines );
	void ReadObjectSplitLine    ( std::istream& ist , ObjMesh& mesh );
	void ReadGroupSplitLine     ( std::istream& ist , ObjMesh& mesh );
	void ReadMaterialSelectLine ( std::istream& ist , ObjMesh& mesh );
	void ReadMaterialGroup      ( std::istream& ist , ObjMesh& mesh );

	void SetLastObjectVertNum(ObjMesh& mesh);

	bool CheckAndModifyContinueToNextLine(std::string& s) const;

	float ReadNextFloat(std::istream& ist)
	{
		ist >> m_ReadCache;
		return (float)atof(m_ReadCache.c_str());
	}

	void ReadVec(std::istream& ist, lm::vec2f& v)
	{
		v.x = ReadNextFloat(ist);
		v.y = ReadNextFloat(ist);
	}

	void ReadVec(std::istream& ist, lm::vec3f& v)
	{
		v.x = ReadNextFloat(ist);
		v.y = ReadNextFloat(ist);
		v.z = ReadNextFloat(ist);
	}

private:
	std::map<std::string, int>  m_MatIdxMap;
	int                         m_PrimaryMatIdx;

	std::map<std::string, int>  m_GroupIdxMap;
	int                         m_PrimaryGroupIdx;

	std::string                 m_LoadWorkDirPath;

	std::string m_ReadCache;
};


}
