//	Dot.h - A sine dot.
//  ----------------------------------------------------------------------------
//	This file is part of 'GameTemplate', template code for a game.
//	Copyright (C) 2011  Niall Moody
//	
//	This program is free software: you can redistribute it and/or modify
//	it under the terms of the GNU General Public License as published by
//	the Free Software Foundation, either version 3 of the License, or
//	(at your option) any later version.
//
//	This program is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//	GNU General Public License for more details.
//
//	You should have received a copy of the GNU General Public License
//	along with this program.  If not, see <http://www.gnu.org/licenses/>.
//	----------------------------------------------------------------------------

#ifndef DOT_H_
#define DOT_H_

#include "TwoFloats.h"
#include "ThreeFloats.h"
#include "NiallsDrawingLib/OpenGLHeaders.h"

#include <stdint.h>

class Drawer;

///	A sine dot.
class Dot
{
  public:
	///	Constructor.
	/*!
		\param rail The rail this dot starts on.
		\param numRails The number of rails currently available.
		\param speed The dot's speed.
	 */
	Dot(int rail, int numRails, float speed);
	///	Destructor.
	~Dot();

	///	Draws (and moves) the dot and its trail.
	/*!
		\param d The Drawer to draw with.
		\param bright When the dot's within the player's radius, draw it
		brighter (outside radius: colour * 1; inside radius: colour * 1.25).
	 */
	void draw(Drawer *d, float bright);

	///	Tells the dot to stop moving.
	void pause(bool val = true);
	///	Tells the dot to kill its synth voice.
	void killTone();

	///	Returns the dot's position.
	const TwoFloats& getPosition() const {return position;};
	///	Returns the dot's colour.
	const ThreeFloats& getColour() const {return colour;};
	
	///	Called when the player clicks the mouse button while this dot's selected.
	void startSwipe(const TwoFloats& mousePos);
	///	Called when the player moves the mouse while this dot's selected.
	void swipe(const TwoFloats& mousePos);
	///	Called when the player releases the mouse button while this dot's selected.
	void endSwipe(const TwoFloats& mousePos);

	///	Deflects the dot onto another rail.
	void deflect(const TwoFloats& playerPos);
	///	Attracts the dot onto another rail.
	void attract(const TwoFloats& playerPos);

	///	Tells the dot how many other dots are nearby.
	void setNearby(float val);

	///	Returns which rail this dot is on.
	int getRail() const {return rail;};
	///	Returns this dot's speed.
	float getSpeed() const {return speed;};

	///	Tells the dot it's collided with another.
	void setCollided();

	///	The radius of a dot (constant).
	static const float Radius;
  private:
	///	Helper method: Draws the trail with mitred corners.
	void drawMitredLine();
	///	Helper method: Draws the trail as a straight line.
	void drawStraightLine();

	///	The size of the dot's trail.
	enum
	{
		TrailSize = 64
	};

	///	The dot image.
	static uint32_t dotImage;
	///	The trail texture.
	static GLuint lineImage;

	///	The dot's colour.
	ThreeFloats colour;
	///	Index of the dot's colour.
	/*!
		0 = red,
		1 = green,
		2 = blue
	 */
	int colIndex;

	///	The dot's current position.
	TwoFloats position;
	///	The dot's previous positions.
	TwoFloats prevPos[TrailSize];
	///	The dot's speed.
	float speed;

	///	The dot's current rail.
	int rail;
	///	The number of currently-available rails.
	int numRails;

	///	The rail the dot's moving towards.
	int newRail;
	///	Used to move the dot towards newRail in a cosine motion.
	float movingRail;

	///	If the dot's being swiped by the player.
	bool swiping;
	///	The swipe start position (y-axis).
	float swipeStart;
	///	Used to count to 3 (mouse move messages) before we commence the rail move.
	int swipeCount;

	///	Our index to a synth voice.
	int synthIndex;

	///	True if we've killed the synth voice already.
	bool noteOff;
	///	True if this dot collided with another.
	bool collided;

	///	True if we should be paused.
	bool isPaused;
};

#endif
