#include "ObjMaterial.h"

#include <fstream>
#include <sstream>
#include <cctype>
#include <algorithm>


ObjMaterial::ObjMaterial()
{
	Clear();
}


void ObjMaterial::LoadLine(std::string& line)
{
	switch (line.at(0))
	{
	case 'K': // Ka, Kd, Ks
		LoadColor(line);
		break;
	case 'T': //Tf or Tr
		LoadTfTrLine(line);
		break;
	case 'N': // Ns, Ni
		LoadNsNiLine(line);
		break;
	case 'd': //d = dissolve 
		LoadDissolveLine(line);
		break;
	case 'i': // illum
		LoadIllumLine(line);
		break;
	case 'm': // map_Ka, map_Kd, map_Ks
		LoadMap(line);
		break;
	case 'b':
	case 'B':
		LoadBumpLine(line);
		break;
	default:
		break;
	}
}

void ObjMaterial::LoadTfTrLine(std::string& line)
{
	if (std::string what = line.substr(0, 2); what == "Tf") // transmission filter
	{
		// TODO: again, for Tf is as above
		line = line.substr(3);

		// so check the prefix
		if (line.substr(0, 3) != "xyz" && line.substr(0, 8) != "spectral")
		{
			std::istringstream sstream(line);

			// TODO: implement it!
		}
		// else not implemented yet
	}
	else if (what == "Tr")
	{
		line = line.substr(3);

		std::istringstream sstream(line);
		sstream >> dissolve;
		dissolve = 1. - dissolve;
	}
}



void ObjMaterial::LoadNsNiLine(std::string& line)
{
	if (std::string what = line.substr(0, 2); what == "Ns") // specular exponent
	{
		line = line.substr(3);

		std::istringstream sstream(line);
		sstream >> exponent;
	}
	else if (what == "Ni") // optical density
	{
		line = line.substr(3);

		std::istringstream sstream(line);
		sstream >> refractionCoeff;
	}
}


void ObjMaterial::LoadDissolveLine(std::string& line)
{
	if (std::string what = line.substr(0, 1); what == "d") // halo factor
	{
		line = line.substr(2);

		std::istringstream sstream(line);
		sstream >> dissolve;
	}
}


void ObjMaterial::LoadBumpLine(std::string& line)
{
	if (std::string what = line.substr(0, 4); what == "bump" || what == "Bump") // bump, see above map_bump, it's the same thing
	{
		line = line.substr(5);
		bumpTexture = line;
	}
}

void ObjMaterial::LoadIllumLine(std::string& line)
{
	if (std::string what = line.substr(0, 5); what == "illum")
	{
		line = line.substr(6);
		int i;
		std::istringstream sstream(line);
		sstream >> i;
		illumination = ObjMaterial::Illumination(i);
	}
}


void ObjMaterial::LoadColor(const std::string& line, Color& color) const
{
	// so check the prefix
	if (line.substr(0, 3) != "xyz" && line.substr(0, 8) != "spectral")
	{
		std::istringstream sstream(line);

		sstream >> color.r;
		try
		{
			sstream >> color.g >> color.b;
		}
		catch (...)
		{
			color.g = color.b = color.r;
		}
	}
	// else not implemented yet
}


void ObjMaterial::LoadColor(std::string& line)
{
	if (std::string what = line.substr(0, 2); what == "Ka") // ambient reflectivity
	{
		// TODO: can actually be not ony 'Ka r g b' but also 'Ka spectral file.rfl factor' or 'Ka xyz x y z'
		line = line.substr(3);
		LoadColor(line, ambientColor);
	}
	else if (what == "Kd") // diffuse reflectivity
	{
		// TODO: for Kd is as above
		line = line.substr(3);

		LoadColor(line, diffuseColor);
	}
	else if (what == "Ks") // specular reflectivity
	{
		// TODO: for Ks is as above
		line = line.substr(3);

		LoadColor(line, specularColor);
	}
	else if (what == "Ke") // emission color
	{
		// TODO: for Ke is as above
		line = line.substr(3);

		LoadColor(line, emissionColor);
	}
}

void ObjMaterial::FixLine(std::string& line)
{
	if (line.at(0) == '\\' || line.at(0) == '/')
		line = line.substr(1);
	std::replace(line.begin(), line.end(), '/', '\\');
}


void ObjMaterial::LoadMap(std::string& line)
{
	if (std::string what = line.substr(0, 6); what == "map_Ka") // material ambient is multiplied by the texture value
	{
		line = line.substr(7);
		FixLine(line);
		ambientTexture = line;
	}
	else if (what == "map_Kd") // material diffuse is multiplied by the texture value
	{
		line = line.substr(7);
		FixLine(line);
		diffuseTexture = line;
	}
	else if (what == "map_Ks") // material specular is multiplied by the texture value
	{
		line = line.substr(7);
		FixLine(line);
		specularTexture = line;
	}
	else if (what == "map_Ke") // material emission color is multiplied by the texture value
	{
		line = line.substr(7);
		FixLine(line);
		glowTexture = line;
	}
	else if (what == "map_Ns") // material specular exponent is multiplied by the texture value
	{
		line = line.substr(7);
		FixLine(line);
		exponentTexture = line;
	}
	else if (what == "map_d " || what == "map_d\t") // material dissolve is multiplied by the texture value
	{
		line = line.substr(6);
		FixLine(line);
		dissolveTexture = line;
	}
	else
	{
		what = line.substr(0, 8);
		if (what == "map_bump" || what == "map_Bump") // bump mapping, this probably should be implemented
		{
			line = line.substr(9);
			FixLine(line);
			bumpTexture = line;
		}
	}
}
