#ifndef TRIANGLE_HXX
#define TRIANGLE_HXX

#include "Primitive.hxx"
#include "Shader.hxx"

using namespace std;

class Triangle : public Primitive
{
	Vec3f a, b, c;
public:
	Triangle(Vec3f a, Vec3f b, Vec3f c, Shader *shader)
		: Primitive(shader),a(a),b(b),c(c)
	{};

	virtual bool Intersect(Ray &ray)
	{
		const Vec3f edge1 = b-a;
		const Vec3f edge2 = c-a;

		const Vec3f pvec = ray.dir^edge2;

		const float det = Dot(edge1, pvec);
		if (fabs(det) < Epsilon) return false;

		const float inv_det = 1.0f / det;

		const Vec3f tvec = ray.org-a;
		float lambda = Dot(tvec, pvec);
		lambda *= inv_det;

		if (lambda < 0.0f || lambda > 1.0f) return false;

		const Vec3f qvec = tvec^edge1;
		float mue = Dot(ray.dir, qvec);
		mue *= inv_det;

		if (mue < 0.0f || mue+lambda > 1.0f) return false;

		float f = Dot(edge2, qvec);
		f *= inv_det;
		if (ray.t <= f || f <  Epsilon  ) return false;

		//////////////////////////////////////////////////////////////////////////
		//Hint: store the computed barycentric coordinates into Ray::u and Ray::v.
		//////////////////////////////////////////////////////////////////////////

		ray.t = f;
		ray.hit = this;

		return true;
	};

	virtual Vec3f GetNormal(Ray &ray)
	{
		Vec3f e1 = b - a;
		Vec3f e2 = c - a;
		Vec3f normal = Cross(e1,e2);
		Normalize(normal);
		return normal;
	};

	float TriangleArea(Vec3f a, Vec3f b, Vec3f c)
	{
		Vec3f e1 = b - a;
		Vec3f e2 = c - a;
		Vec3f normal = Cross(e1,e2); 
		return 0.5f * Length(normal);
	};

	virtual Box CalcBounds()
	{
		Box bounds;

		bounds.Extend(a);
		bounds.Extend(b);
		bounds.Extend(c);

		return bounds;
	}
};

#endif
