#include <windows.h>
#include <iostream>
#define GLUT_DISABLE_ATEXIT_HACK 
#include "constants.h"
#include "vector.h"
#include "tank.h"
#include "bullet.h"
#include <GL/glut.h>
#include <math.h>

using namespace std;

/*
 * Implement the Tank class
 */


/*
 * Constructors
 */
// Default constructor
Tank::Tank(void):radius(TANK_RADIUS), 
				 color(COLORR, COLORG, COLORB),
				 alive(true),
				 theta(INITIAL_THETA),
				 phi(INITIAL_PHI),
				 power(INITIAL_POWER)

{
}

// Constructor sets location
Tank::Tank(const Vector& _loc):radius(TANK_RADIUS), 
						color(COLORR, COLORG, COLORB),
						loc(_loc),
						alive(true),
						theta(INITIAL_THETA),
						phi(INITIAL_PHI),
						power(INITIAL_POWER)
{}

Tank::~Tank(void)
{}

/*
 * Display
 */
void Tank::draw(void) const
{
	// Draw the tank.

	glColor3f(color[0], color[1], color[2]);  // establish color in RGB
	glPushMatrix();
	glTranslatef(loc[0], loc[1], loc[2]); // move center
	glutSolidSphere(radius, RESOLUTION, RESOLUTION);
	glPopMatrix(); //end sphere draw

	// Draw the tank's gun barrel.

	double dx = sin(phi) * cos(theta);
	double dz = sin(phi) * sin(theta);
	double dy = cos(phi);

	Vector unit(dx, dy, dz);

	Vector begin = loc + (unit * radius);
	Vector end = begin + (unit * BARREL_LENGTH);

	glBegin(GL_LINES);
	glVertex3f(begin[0], begin[1], begin[2]);
	glVertex3f(end[0], end[1], end[2]);
	glEnd();
}

/*
 * Draw tank's power bar (but only if its the tank's turn, handled by the caller)
 */
void Tank::drawBar(void) const
{
	// Draw the tank's power bar

	glColor3f(POWER_RED, POWER_GREEN, POWER_BLUE);  // establish color in RGB
	glBegin(GL_LINES);
	glVertex3f(loc[0], loc[1]+POWER_BAR_OFFSET, loc[2]);
	glVertex3f(loc[0],loc[1]+POWER_BAR_OFFSET+POWER_BAR_HEIGHT, loc[2]);
	glEnd();

	glPushMatrix();
	glTranslatef(loc[0], loc[1]+POWER_BAR_OFFSET+POWER_BAR_HEIGHT*(((double)power)/MAX_POWER), loc[2]);
	glutSolidSphere(POWER_BAR_RADIUS, RESOLUTION, RESOLUTION);
	glPopMatrix();
	
}

/*
 * Setters
 */
void Tank::setLoc(const Vector& newloc)
{
	loc = newloc;
}

void Tank::setColor(const Vector& col)
{
	color = col;
}
void Tank::setTheta(double _theta)
{
	theta = _theta;
	normalizeAngle(theta);
}

void Tank::setPhi(double _phi)
{
	phi = _phi;
	normalizeAngle(phi);
}

/*
 * Getters
 */
Vector Tank::getLoc() const
{
	return loc;
}

double Tank::getTheta() const
{
	return theta;
}

double Tank::getPhi() const
{
	return phi;
}

int Tank::getPower() const
{
	return power;
}

/*
 * State
 */
bool Tank::isAlive() const
{
	return alive;
}

void Tank::die()
{
	alive = false;
}

/*
 * Aim
 */
void Tank::rotateTheta(double diffTheta)
{
	PlaySound("TURRET_MOVE", 0, SND_RESOURCE | SND_ASYNC);
	theta += diffTheta;
	normalizeAngle(phi);
}

void Tank::rotatePhi(double diffPhi)
{
	PlaySound("TURRET_MOVE", 0, SND_RESOURCE | SND_ASYNC);
	phi += diffPhi;
	normalizeAngle(phi);
}

void Tank::powerUp()
{
	if (power < MAX_POWER)
	{
		PlaySound("POWER_UP", 0, SND_RESOURCE | SND_ASYNC);
		power++;
	}
}

void Tank::powerDown()
{
	if (power > 0)
	{
		PlaySound("POWER_DOWN", 0, SND_RESOURCE | SND_ASYNC);
		power--;
	}
}

/*
 * Fire!
 */
// The tank behaves like a ball factory here.
Bullet* Tank::launch() const
{
	// Find the distance between the center of the ball
	// and the center of the bullet.
	double centersDistance = radius + BARREL_LENGTH + BULLET_RADIUS;

	double dx = sin(phi) * cos(theta);
	double dz = sin(phi) * sin(theta);
	double dy = cos(phi);

	Vector unit(dx, dy, dz);

	Vector locVec = unit * centersDistance + loc;
	Vector velVec = unit * power / POWER_DIVISOR;
	return new Bullet(locVec, velVec);
}

/*
 * Private helper functions.
 */
double Tank::normalizeAngle(double& angle)
{
	while (angle > 2 * PI)
	{
		angle = angle - 2 * PI;
	}
	while (angle < 0)
	{
		angle = angle + 2 * PI;
	}
	return angle;
}