/* Ball.h
 *
 * Interface definition for the Ball class, which stores ball data and can
 * calculate the ball's expected path over time step dt.
 */

#ifndef BALL_H_INCLUDED
#define BALL_H_INCLUDED 1

#include <list>
#include <vector>
#include "Tuple.h"
#include "Obstruction.h"
#include "Path.h"

class Ball
{
private:
	// Constants
	static const int			BALL_DETAIL = 16;
	static const float			SHININESS;
	static const float			SPECULAR_COLOR[];
	static const unsigned int	STOP_CHECKS = 50;
	static const double			STOP_DISTANCE;
	static const double			ROLL_VELOCITY;
	static const double			ROLL_DISTANCE;
	static const double			COLLISION_TIME;
	static const double			DEF_RADIUS;

	// Member Variables
	double					radius_;
	Tuple					position_;
	Tuple                   lastStopPos_; // position of last stop
	Tuple					velocity_;
	Tuple					color_;		// Color in r, g, b format
	std::vector<Obstruction*>	rolls_;		// Things the ball is rolling on
	std::list<Tuple>		history_;	// Record of ball's trajectory
	bool					stopped_;
	bool					rollDebug_;

	// The minimum y value the Ball can have before we reset it to
	// its previous stop position.
	double                  MIN_Y;
	static const double     DEF_MIN_Y; // default value

public:
	// Constructors/Destructor
	Ball(
		double radius = DEF_RADIUS,
		Tuple positon = Tuple(),
		Tuple velocity = Tuple(),
		Tuple color = Tuple(.1,.5,.8)); // default to blue ball b/c black balls are hard to see
	~Ball();

	// Member Functions
	void		draw(bool light) const;	// Draw a sphere to represent the ball
	const Path	calcPath(				// Find ball's expected path over dt
		double dt) const;
	void		clearAll();				// Empty out the existing rolls/history
	const bool	checkStopped();			// Check if the ball has stopped
	const bool	checkRolling(			// Test set of obstructions for rolling
		const std::vector<Obstruction*>& testRolls = std::vector<Obstruction*>());
	const bool	checkBottomedOut();		// If we are below MIN_Y, reset position
	void		doCollision(			// Bounce off of an obstacle
		const std::vector<Obstruction*>& testRolls = std::vector<Obstruction*>());
	void		doFriction(				// Respond to friction due to rolling
		double dt);
	void		impulse(				// Accelerate the ball over dt
		double dt,
		const Tuple& acceleration);

	// Accessor Functions
	const double&	radius()						{return radius_;}
	const Tuple&	position() const				{return position_;}
	const Tuple&	velocity() const				{return velocity_;}
	bool            stopped()                       {return stopped_;}
	(const Tuple)*	pPosition() const				{return &position_;}

	// Utility
	void rollDebugToggle() {rollDebug_ = !rollDebug_;}
	const bool rollDebug() const {return rollDebug_;}
	
	void            setMinY(double minY)            {MIN_Y = minY;}
	void			moveTo(const Tuple& newPos)
		{position_ = newPos; if (stopped_) {stopped_ = false; history_.clear();}}
	void			accelTo(const Tuple& newVel)
		{velocity_ = newVel; if (stopped_) {stopped_ = false; history_.clear();}}
	void			moveBy(const Tuple& dPos)
		{position_ += dPos; if (stopped_) {stopped_ = false; history_.clear();}}
	void			accelBy(const Tuple& dVel)
		{velocity_ += dVel; if (stopped_) {stopped_ = false; history_.clear();}}
	
};

#endif // BALL_H_INCLUDED
