/* Vertex.cpp
 *
 * Definition of the Vertex class.
 */

#include "Vertex.h"
#include <cmath>
#include <GL/glut.h>

Vertex::Vertex(const Tuple& v1, const Tuple& color)
 : Obstruction(),
   v1_(v1),
   color_(color),
  litNormal_(),
  sumNormal_(),
  triCount_(0)
{
	// Nothing (more) to do
}

Vertex::~Vertex()
{
	// Nothing to do
}

/* addNormal
 *
 * Update the vertex's litNormal_ so that it represents the average of the
 * normals of the triangles connecting to it.
 */
void Vertex::addNormal(const Tuple& normal)
{
	sumNormal_ += normal;
	triCount_++;

	litNormal_ = sumNormal_ / triCount_;
}

/* draw
 *
 * This is here just in case we ever decide to draw vertices.
 */
void Vertex::draw(bool light) const
{
	(void)light; // Don't use lighting setting b/c there is nothing to draw
}

/* pathIntersect
 *
 * Determines if this vertex is on the given path and returns the Beta value,
 * (the percent of path completed before collision).
 */
const double Vertex::pathIntersect(
	const Path& path,
	double radius) const
{
	/* Here we'll use the quadratic equation to determine if and where the ball
	 * collides with the edge.  Actually, we're checking whether the center
	 * of the ball intersects a cyllinder about the x-axis with a radius
	 * equal to the ball's radius plus a BUFFER.
	 */

	// Standardize input path to match standardized edge vertices
	Path sPath = path.translate(-v1_);

	// Define a few helpful variables to clarify the following code
	double x1 = sPath.endPos().x();
	double y1 = sPath.endPos().y();
	double z1 = sPath.endPos().z();
	double x0 = sPath.begPos().x();
	double y0 = sPath.begPos().y();
	double z0 = sPath.begPos().z();

	// Make sure the ball is moving
	if (x0 != x1 || y0 != y1 || z0 != z1)
	{
		// We'll fill this with the distance along the path where the ball
		//   touches the buffer about the origin
		double beta;

		// If the ball starts in the buffer, collide instantly; otherwise
		//   just collide when the ball reaches the buffer
		double r0 = sqrt(z0 * z0 + y0 * y0 + z0 * z0);
		if (r0 < radius + BUFFER)
		{
			// Define variables for the quadratic equation
			double a =
				(x1 - x0) * (x1 - x0) +
				(y1 - y0) * (y1 - y0) +
				(z1 - z0) * (z1 - z0);
			double b =
				2 * (x0 * (x1 - x0) + y0 * (y1 - y0) + z0 * (z1 - z0));
			double c =
				x0 * x0 + y0 * y0 + z0 * z0 - radius * radius;

			// Check the determinant; if negative, then no collision
			double det = b * b - 4 * a * c;
			if (det >= 0.0)
			{
				// Collide no later than now (0.0)
				beta = min((-b - sqrt(det)) / (2 * a), 0.0);
			}
			else
			{
				// Add EPSILON to err on the safe side (no collision)
				beta = 1.0 + EPSILON;
			}
		}
		else
		{
			// Define variables for the quadratic equation
			double a =
				(x1 - x0) * (x1 - x0) +
				(y1 - y0) * (y1 - y0) +
				(z1 - z0) * (z1 - z0);
			double b =
				2 * (x0 * (x1 - x0) + y0 * (y1 - y0) + z0 * (z1 - z0));
			double c =
				x0 * x0 + y0 * y0 + z0 * z0 -
				(radius + BUFFER) * (radius + BUFFER);

			// Check the determinant; if negative, then no collision
			double det = b * b - 4 * a * c;
			if (det >= 0.0)
			{
				// We only care about lowest beta, so consider only -sqrt(det)
				beta = (-b - sqrt(det)) / (2 * a);
			}
			else
			{
				// Add EPSILON to err on the safe side (no collision)
				beta = 1.0 + EPSILON;
			}
		}

		// Make sure beta is in range
		if (beta >= 0.0 && beta < 1.0)
			return beta;
	}

	// Add EPSILON to err on the safe side (no collision)
	return 1.0 + EPSILON;
}

/* calcNormal
 *
 * Returns the normal of the given vertex relative to a given point, which is
 * simply the direction of the line from the vertex through the point.
 */
const Tuple Vertex::calcNormal(const Tuple& point) const
{
	return (point - v1_).norm();
}
