#ifndef MATERIAL_H_
#define MATERIAL_H_

#include <rgbeio.h>
#include <array2d.h>
#include <string>
#include "Texture.hxx"

class Primitive;

class Material
{
public:
 	string name;
	int illum; // illumination model 	
	Vec3f Ka; // ambient reflectance
	Vec3f Kd; // diffuse reflectance
	Vec3f Ks; // specular reflectance
	float Ns; // shininess
	float d;  // disolve of the material (alpha value)
	float Ni; // Specifies the optical density for the surface. This is also known as index of refraction.
				/* The values can range from 0.001 to 10. A value of 1.0 means that light does not bend as it passes through an object. 
				 * Increasing the optical_density increases the amount of bending. Glass has an index of refraction of about 1.5. 
				 * Values of less than 1.0 produce bizarre results and are not recommended.
				 */ 	 
	Vec3f Tf; // transmission filter	
	/*
		Vector Definition
		
		H unit vector bisector between L and V
		L unit light vector
		N unit surface normal
		V unit view vector
		
		The illumination models are:
		
		0 This is a constant color illumination model. The color is the specified Kd for the material. The formula is:
		
		color = Kd
		
		1 This is a diffuse illumination model using Lambertian shading. The color includes an ambient constant term and a diffuse shading term for each light source. The formula is
		
		color = KaIa + Kd { SUM j=1..ls, (N * Lj)Ij }
		
		2 This is a diffuse and specular illumination model using Lambertian shading and Blinn's interpretation of Phong's specular illumination model (BLIN77). The color includes an ambient constant term, and a diffuse and specular shading term for each light source. The formula is:
		
		color = KaIa
		+ Kd { SUM j=1..ls, (N*Lj)Ij }
		+ Ks { SUM j=1..ls, ((H*Hj)^Ns)Ij }
		
		3 This is a diffuse and specular illumination model with reflection using Lambertian shading, Blinn's interpretation of Phong's specular illumination model (BLIN77), and a reflection term similar to that in Whitted's illumination model (WHIT80). The color includes an ambient constant term and a diffuse and specular shading term for each light source. The formula is:
		
		color = KaIa
		+ Kd { SUM j=1..ls, (N*Lj)Ij }
		+ Ks ({ SUM j=1..ls, ((H*Hj)^Ns)Ij } + Ir)
		
		Ir = (intensity of reflection map) + (ray trace)
		
		4 The diffuse and specular illumination model used to simulate glass is the same as illumination model 3. When using a very low dissolve (approximately 0.1), specular highlights from lights or reflections become imperceptible.
		
		Simulating glass requires an almost transparent object that still reflects strong highlights. The maximum of the average intensity of highlights and reflected lights is used to adjust the dissolve factor. The formula is:
		
		color = KaIa
		+ Kd { SUM j=1..ls, (N*Lj)Ij }
		+ Ks ({ SUM j=1..ls, ((H*Hj)^Ns)Ij } + Ir)
		
		5 This is a diffuse and specular shading models similar to illumination model 3, except that reflection due to Fresnel effects is introduced into the equation. Fresnel reflection results from light striking a diffuse surface at a grazing or glancing angle. When light reflects at a grazing angle, the Ks value approaches 1.0 for all color samples. The formula is:
		
		color = KaIa
		+ Kd { SUM j=1..ls, (N*Lj)Ij }
		+ Ks ({ SUM j=1..ls, ((H*Hj)^Ns)Ij Fr(Lj*Hj,Ks,Ns)Ij} + Fr(N*V,Ks,Ns)Ir})
		
		
		6 This is a diffuse and specular illumination model similar to that used by Whitted (WHIT80) that allows rays to refract through a surface. The amount of refraction is based on optical density (Ni). The intensity of light that refracts is equal to 1.0 minus the value of Ks, and the resulting light is filtered by Tf (transmission filter) as it passes through the object. The formula is:
		
		color = KaIa
		+ Kd { SUM j=1..ls, (N*Lj)Ij }
		+ Ks ({ SUM j=1..ls, ((H*Hj)^Ns)Ij } + Ir)
		+ (1.0 - Ks) TfIt
		
		7 This illumination model is similar to illumination model 6, except that reflection and transmission due to Fresnel effects has been introduced to the equation. At grazing angles, more light is reflected and less light is refracted through the object. The formula is:
		
		color = KaIa
		+ Kd { SUM j=1..ls, (N*Lj)Ij }
		+ Ks ({ SUM j=1..ls, ((H*Hj)^Ns)Ij Fr(Lj*Hj,Ks,Ns)Ij} + Fr(N*V,Ks,Ns)Ir})
		
		+ (1.0 - Kx)Ft (N*V,(1.0-Ks),Ns)TfIt
		
		8 This illumination model is similar to illumination model 3 without ray tracing. The formula is:
		
		color = KaIa
		+ Kd { SUM j=1..ls, (N*Lj)Ij }
		+ Ks ({ SUM j=1..ls, ((H*Hj)^Ns)Ij } + Ir)
		
		Ir = (intensity of reflection map)
		
		9 This illumination model is similar to illumination model 4without ray tracing. The formula is:
		
		
		color = KaIa
		+ Kd { SUM j=1..ls, (N*Lj)Ij }
		+ Ks ({ SUM j=1..ls, ((H*Hj)^Ns)Ij } + Ir)
		
		Ir = (intensity of reflection map)
		
		10 This illumination model is used to cast shadows onto an invisible surface. This is most useful when compositing computer-generated imagery onto live action, since it allows shadows from rendered objects to be composited directly on top of video-grabbed images. The equation for computation of a shadowmatte is formulated as follows.
		
		color = Pixel color. The pixel color of a shadowmatte material is always black.
		
		color = black 
	*/
	//float Ft; // Fresnel reflectance
	//float Ft; // Fresnel transmittance
				
					 	
	const Texture* mapKd; // texture map for diffuse reflectivity
		
public:
	Material() : illum(2), Ka(0), Kd(0.8), Ks(0.2), Ns(40), d(0), Ni(1), Tf(1), mapKd(NULL) {}
	
	Material(int illum, Vec3f Ka, Vec3f Kd, Vec3f Ks, float Ns, float d, float Ni, Vec3f Tf, const Texture* mapKd) 
		: illum(illum), Ka(Ka), Kd(Kd), Ks(Ks), Ns(Ns), d(d), Ni(Ni), Tf(Tf), mapKd(mapKd) {}
	
	Material(ifstream& is, string name, const char* baseDir): name(name), mapKd(NULL) {
		Material();	
		while(!is.eof()) {
			std::string curLine;
			std::getline(is, curLine);
			if(curLine.size() <= 1) // TODO: detect empty lines
				return;
			std::istringstream issLine(curLine);
			std::string lineType;
			issLine >> std::ws >> lineType;
			if(lineType == "Ns") {
				issLine >> Ns;
			}
			else if(lineType == "Ka") {
				float x, y, z;
				issLine >> x >> y >> z;	
				Ka = Vec3f(x, y, z);
			}
			else if(lineType == "Kd") {
				float x, y, z;
				issLine >> x >> y >> z;	
				Kd = Vec3f(x, y, z);
			}
			else if(lineType == "Ks") {
				float x, y, z;
				issLine >> x >> y >> z;	
				Ks = Vec3f(x, y, z);
			}
			else if(lineType == "Ni") {
				issLine >> Ni;
			}
			else if(lineType == "d") {
				issLine >> d;
			}
			else if(lineType == "illum") {
				issLine >> illum;
			}
			else if(lineType == "map_Kd") {
				string mapKdFileName;
				issLine >> mapKdFileName;
				mapKdFileName = string(baseDir) + '/' + mapKdFileName;				
				mapKd = new Texture(mapKdFileName.c_str());
			}		
		}
	}
	
	/*
	Vec3f GetKd(const Ray& ray) const {
		if(!mapKd)
			return Kd;
		float u, v;
		ray.hit->GetUV(ray, u, v);
		return mapKd->GetTexel(u, v);
	}
	*/
	
	virtual ~Material() {}	
};

#endif /*MATERIAL_H_*/

