#include "Salamander.h"
#include "Polygon.h"

namespace Salamander
{

defineUniqueId(Polygon);
Polygon::Polygon() :
	area_(0.0f)
{

}

Polygon::~Polygon()
{

}

bool Polygon::isPointInside(Vec2 point)
{
	// Quick out if we don't have an 'inside'
	if(vworld_.size() <= 2)
	{
		return false;
	}

	// For each edge in the polygon, ensure that the cross
	// product with the point is negative
	for(unsigned int i = 0; i < vworld_.size(); i++)
	{
		Vec2 p = point - vworld_.at(i);

		double crossProduct = -edges_.at(i) ^ p;
		if(crossProduct > 0.0) return false;
	}

	return true;

}

void Polygon::projectPoints(Vec2 axis, Vec2& overlap)
{
	for(Vec2Iterator vertex = vworld_.begin();
		vertex != vworld_.end();
		++vertex)
	{
		double distance = *vertex ^ ~axis;
		if(vertex == vworld_.begin())
		{
			// the first point is both the minimum and the maximum
			overlap.x_ = distance;
			overlap.y_ = distance;
		}
		else
		{
			if(distance < overlap.x_) overlap.x_ = distance;
			if(distance > overlap.y_) overlap.y_ = distance;
		}
	}
}

// generate useful data that doesn't change between frames
void Polygon::generateProperties()
{
	Shape::generateProperties();

	//generateCentroid();
	generateArea();
	generateMomentOfInertia();
}

// TODO PHYS : generate polygon centroid based on weighted triangle areas

void Polygon::generateMomentOfInertia()
{
	// sum(n = 0 to N) {mi ri ^ 2}
	// where N is points, mi is the mass of a point, ri is the radius of the point

	momentOfInertia_ = 0.0f;
	for(unsigned int i = 0; i < vlocal_.size(); i++)
	{
		// get the areas of the triangles either side of the vertex
		int im = ((int)i - 1);
		if(im < 0) im += vlocal_.size();
		
		double pointMass = std::abs(vlocal_.at(i) ^ edges_.at(i)) + 
						  std::abs(vlocal_.at(i) ^ edges_.at(im)) * 0.25f;
		double pointDistance = vlocal_.at(i).length();

		momentOfInertia_ += (pointMass / area_) * pointDistance * pointDistance;
	}

}

void Polygon::generateArea()
{
	// use the cross product of the component triangles
	area_ = 0.0f;
	for(unsigned int i = 0; i < vlocal_.size(); i++)
	{
		area_ += std::abs(vlocal_.at(i) ^ edges_.at(i)) * 0.5f;
	}
}

}
