#pragma once
#include <iostream>
#include <fstream>
#include <algorithm>
#include <vector>
#include "Debugger.h"
#include "GLM/glm.hpp"


/* - This function loads the OBJ file and returns the number of triangles | 이 함수는 OBJ 파일을 로드하고 삼각형 갯수를 반환합니다- */
void LoadOBJ(const std::string& file_path, float out_vertex_buffer_data[][8], unsigned int& out_number_of_triangle)
{
	Debugger::GetInstance()->WriteMessage("Loading OBJ file...");
	Debugger::GetInstance()->WriteMessage(file_path);

	std::vector<unsigned int> vertexIndices, uvIndices, normalIndices;
	std::vector<glm::vec3> temp_vertices;
	std::vector<glm::vec2> temp_uvs;
	std::vector<glm::vec3> temp_normals;

	std::ifstream obj_file(file_path.data());

	if (obj_file.is_open() == false)
	{
		Debugger::GetInstance()->WriteError("File open Faild !");
	}

	std::string read_one_line;

	while (std::getline(obj_file, read_one_line))
	{
		std::replace(read_one_line.begin(), read_one_line.end(), '/', ' '); // f 값을 쉽게 읽기 위해 "/" 기호를 " " 로 바꾸기
		std::stringstream stream_one_line(read_one_line);

		// parsing start
		if (read_one_line.find("#") != std::string::npos) // ignore # comments | 주석 무시
		{
			// do nothing
		}
		else if (read_one_line.find("mtl") != std::string::npos) // ignore material informations
		{
			// do nothing
		}
		else if (read_one_line.find("s") != std::string::npos) // ignore smoothing informations
		{
			// do nothing
		}
		else if ((read_one_line.find("o") != std::string::npos) || (read_one_line.find("g") != std::string::npos)) // ignore group informations
		{
			// do nothing
		}
		else if (read_one_line.find("vt") != std::string::npos)
		{
			glm::vec2 uv;
			stream_one_line.ignore(256, 'v'); // Ignore characters and read only the remainder | 문자를 무시하고 나머지만 읽는다
			stream_one_line.ignore(256, 't'); // Ignore characters and read only the remainder | 문자를 무시하고 나머지만 읽는다
			stream_one_line >> uv.x >> uv.y;
			temp_uvs.push_back(uv);
		}
		else if (read_one_line.find("vn") != std::string::npos)
		{
			glm::vec3 normal;
			stream_one_line.ignore(256, 'v'); // Ignore characters and read only the remainder | 문자를 무시하고 나머지만 읽는다
			stream_one_line.ignore(256, 'n'); // Ignore characters and read only the remainder | 문자를 무시하고 나머지만 읽는다
			stream_one_line >> normal.x >> normal.y >> normal.z;
			temp_normals.push_back(normal);
		}
		else if (read_one_line.find("v") != std::string::npos) // If we can find specific string
		{
			glm::vec3 vertex;
			stream_one_line.ignore(256, 'v'); // Ignore characters and read only the remainder | 문자를 무시하고 나머지만 읽는다
			stream_one_line >> vertex.x >> vertex.y >> vertex.z;
			temp_vertices.push_back(vertex);
		}
		else if (read_one_line.find("f") != std::string::npos)
		{
			unsigned int vertexIndex[3], uvIndex[3], normalIndex[3];
			stream_one_line.ignore(256, 'f'); // Ignore characters and read only the remainder | 문자를 무시하고 나머지만 읽는다
			//stream_one_line.ignore(256, '/'); // Ignore characters and read only the remainder | 문자를 무시하고 나머지만 읽는다

			stream_one_line >> vertexIndex[0] >> uvIndex[0] >> normalIndex[0] >> vertexIndex[1] >> uvIndex[1] >> normalIndex[1] >> vertexIndex[2] >> uvIndex[2] >> normalIndex[2];

			vertexIndices.push_back(vertexIndex[0]);
			vertexIndices.push_back(vertexIndex[1]);
			vertexIndices.push_back(vertexIndex[2]);
			uvIndices.push_back(uvIndex[0]);
			uvIndices.push_back(uvIndex[1]);
			uvIndices.push_back(uvIndex[2]);
			normalIndices.push_back(normalIndex[0]);
			normalIndices.push_back(normalIndex[1]);
			normalIndices.push_back(normalIndex[2]);
		}

	}

	// Re-organize vertices of each triangles by indices information
	for (unsigned int i = 0; i < vertexIndices.size(); i++)
	{
		// Get the indices of its attributes
		unsigned int vertexIndex = vertexIndices[i];
		unsigned int uvIndex = uvIndices[i];
		unsigned int normalIndex = normalIndices[i];

		// Get the attributes thanks to the index
		glm::vec3 vertex = temp_vertices[vertexIndex - 1];
		glm::vec2 uv = temp_uvs[uvIndex - 1];
		glm::vec3 normal = temp_normals[normalIndex - 1];

		// Put the attributes in buffers
		out_vertex_buffer_data[i][0] = vertex.x;
		out_vertex_buffer_data[i][1] = vertex.y;
		out_vertex_buffer_data[i][2] = vertex.z;

		out_vertex_buffer_data[i][3] = normal.x;
		out_vertex_buffer_data[i][4] = normal.y;
		out_vertex_buffer_data[i][5] = normal.z;

		out_vertex_buffer_data[i][6] = uv.x;
		out_vertex_buffer_data[i][7] = uv.y;
	}

	out_number_of_triangle = vertexIndices.size(); // save the number of triangles
}
