/*
 * $Id: mtlparser.cpp,v 1.0 2011-04-22 22:50:29 sedlad1 Exp $
 *
 * Description  : One line description of file.
 * Author       : David Sedlacek <david.sedlacek@fel.cvut.cz>
 *
 * Purpose      :
 *     OBJ material Library parser.
 *     http://people.sc.fsu.edu/~jburkardt/data/mtl/mtl.html
 *	   http://paulbourke.net/dataformats/mtl/
 */


#include "scenemodule.h"
#include <wx/filename.h>
#include "mtlparser.h"

using namespace VRUT;


MTLParser::MTLParser(wxInputStream * _inputStream, SCENE_ID _sceneID, const wxString _scenePath, Module * _module)
: inputStream(_inputStream), sceneID(_sceneID), module(_module), material(NULL)
{
	fileName = wxFileName(_scenePath).GetName();
	wxFileName filename2(_scenePath);
	scenePath = filename2.GetPath();
	if (!scenePath.empty())
		scenePath += filename2.GetPathSeparator();
}

MTLParser::~MTLParser()
{
	///Is called by wxWidgets itself on wxApp end but it doesn't work in dynamic library
}

bool MTLParser::parseFile()
{
	TextParser textParser(inputStream, 100000, 100);
//	newName = textParser.GetWxString("\r\n");
	///prepare
	material = NULL;
	std::vector<Vector3> v;

	///parse
	const char *keywords[]={"newmtl", "Ka", "Kd", "Ks", "d", "Tr", "Ns", "illum", "map_Kd", "Tf", "Ni", "#", "Ke", "map_Ka", ""};

	while (!textParser.IsEmpty())
	{
		switch (textParser.KeywordsSwitch(keywords))
		{
		case 0://newmtl
			{
				if (material)
				{
					module->PostToKernel(GET_EVT_SCENE_MATERIAL_ADD(sceneID, material));
					material = NULL;
				}
				textParser.SkipChars(" \t");
				materialName=textParser.GetWxLine();

				material = new Material(materialName);

				//material->flags = Material::FLAT_REFLECTION;
				//material->flags |= Material::DOUBLE_SIDED;
				break;
			}
		case 1://Ka - ambient color
			{
				Vector3 v;
				if (textParser.ParseVector(v._v, 3) != 3)
				{
					LOGERROR(wxT("<MTLParser>Error parsing 'Ka'."));
					return false;
				}
				if (material)
					material->ambient= Vector4(v.x, v.y, v.z, 1);
				break;
			}
		case 2://Kd - diffuse color
			{
				Vector3 v;
				if (textParser.ParseVector(v._v, 3) != 3)
				{
					LOGERROR(wxT("<MTLParser>Error parsing 'Kd'."));
					return false;
				}
				if (material)
					material->diffuse= Vector4(v.x, v.y, v.z, 1);
				break;
			}
		case 3://Ks - specular color
			{
				Vector3 v;
				if (textParser.ParseVector(v._v, 3) != 3)
				{
					LOGERROR(wxT("<MTLParser>Error parsing 'Ks'."));
					return false;
				}
				if (material)
					material->specular= Vector4(v.x, v.y, v.z, 1);
				break;
			}
			break;
		case 4://d - defines the transparency of the material to be alpha, the value 1.0 means no transparency
		{
			float f;
			if (!textParser.ParseFloat(&f))
			{
				LOGERROR(wxT("<MTLParser>Error parsing 'd'."));
				return false;
			}
			if (material)
			{
				material->diffuse.w = f;
				if (material->diffuse.w < 1.0f)
				{
					material->flags |= Material::BLENDED;
					material->blendSrc = GL_SRC_ALPHA;
					material->blendDst = GL_ONE_MINUS_SRC_ALPHA;
				}
				else
					material->flags ^= Material::BLENDED;
			}
			break;
		}
		case 5://Tr - defines the transparency of the material to be alpha, the value 0.0 means no transparency (meaning is opposite to "d")
			{
				float f;
				if (!textParser.ParseFloat(&f)) 
				{
					LOGERROR(wxT("<MTLParser>Error parsing 'Tr'."));
					return false;
				}
				if (material)
				{
					material->diffuse.w = 1.0f - f;
					if (material->diffuse.w < 1.0f)
					{
						material->flags |= Material::BLENDED;
						material->blendSrc = GL_SRC_ALPHA;
						material->blendDst = GL_ONE_MINUS_SRC_ALPHA;
					}
					else
						material->flags ^= Material::BLENDED;
				}
				break;
			}
		case 6://Ns
			{
				float f;
				if (!textParser.ParseFloat(&f)) 
				{
					LOGERROR(wxT("<MTLParser>Error parsing 'Ns'."));
					return false;
				}
				if (material)
					material->shininess=f;
				break;
			}
		case 7://illum
			//denotes the illumination model used by the material. 
			//illum = 1 indicates a flat material with no specular highlights, so the value of Ks is not used. 
			//illum = 2 denotes the presence of specular highlights, and so a specification for Ks is required. 

			/*
			 Illumination    Properties that are turned on in the 
			model           Property Editor
 
			 0		Color on and Ambient off
			 1		Color on and Ambient on
			 2		Highlight on
			 3		Reflection on and Ray trace on
			 4		Transparency: Glass on
 					Reflection: Ray trace on
			 5		Reflection: Fresnel on and Ray trace on
			 6		Transparency: Refraction on
 					Reflection: Fresnel off and Ray trace on
			 7		Transparency: Refraction on
 					Reflection: Fresnel on and Ray trace on
			 8		Reflection on and Ray trace off
			 9		Transparency: Glass on
 					Reflection: Ray trace off
			 10		Casts shadows onto invisible surfaces
			*/
			{
				int illum;
				if (!textParser.ParseInt(&illum)) 
				{
					LOGERROR(wxT("<MTLParser>Error parsing 'illum'."));
					return false;
				}
				/*switch(illum) {
					case 0:
						material->fla
				}*/
				break;
			}
		case 8://map_Kd - texture
			{
				textParser.SkipChars(" \t");
				wxString texName = textParser.GetWxLine();
				wxString texPath = scenePath + texName;
				if (addImageCache.find(texPath) == addImageCache.end())
				{
					addImageCache.insert(texPath);
					KERNEL->GetMessageSink()->PostJob(new SceneImageAddJob((EventSceneImageAdd*)GET_EVT_SCENE_IMAGE_ADD(texPath)));
				}
				if (material)
					material->imageName = texPath;
				break;
			}
		case 9://Tf
		case 10://Ni
		case 11://comment
		case 12://Ke	
			textParser.GetWxLine();
			break;
		case 13://map_Ka
			textParser.GetWxLine();
			LOGWARNING(wxT("<MTLParser>Error map_Ka - skipped"));
			break;
		default:
			LOGERROR(wxT("<MTLParser>Unexpected token: '" + textParser.GetWxLine() + wxT("'")));
			//return false;
			break;
		}
	}

	if (material)
		module->PostToKernel(GET_EVT_SCENE_MATERIAL_ADD(sceneID, material));

	return true;
}

bool MTLParser::Parse(const NODE_ID &rootID)
{
	smart_pointer_v2<Scene> scene;
	KERNEL->sceneManager->GetScene(scene, sceneID);
	if (!scene)
		return false;

	materialName = wxT("OBJDefault");
	nodeName = fileName + wxT("_node");

	//parse
	if (!parseFile())
	{
		LOGERROR(wxT("<OBJParser>Scene not loaded properly"));
		return false;
	}
	return true;
}
