#include "main.h"
#include <vector>


Mix_Chunk *thrustsound1;
Mix_Chunk *thrustsound2;
Mix_Chunk *shootsound;
Mix_Chunk *hitsound;
Mix_Chunk *explodesound;

void setSounds(Mix_Chunk *ts1, Mix_Chunk *ts2, Mix_Chunk *ss, Mix_Chunk *hs, Mix_Chunk *es) {
	thrustsound1 = ts1;
	thrustsound2 = ts2;
	shootsound = ss;
	hitsound = hs;
	explodesound = es;
}

spaceship::spaceship() {
	//Setup spaceship initial properties.
	this->ticks = SDL_GetTicks();

	this->x = rand()%SCREENWIDTH;
	this->y = rand()%SCREENHEIGHT;
	this->speedx = 0;
	this->speedy = 0;
	this->acceleration = 0;
	this->rotFreq = 0;
	this->angle = 0;
	this->AIenabled = true;
	this->score = 0;
	this->health = 1000;
	this->thrustchannel1 = -1;
	this->thrustchannel2 = -1;
	
	
	for (int i = 0; i < NUMBULLETS; i++) {
		this->bullets.push_back(*(new bullet));
	}
}

spaceship::~spaceship() {
}

SDLKey spaceship::getUpKey() {
	return keys[0];
}
	
SDLKey spaceship::getDownKey() {
	return keys[1];
}

SDLKey spaceship::getLeftKey() {
	return keys[2];
}

SDLKey spaceship::getRightKey() {
	return keys[3];
}

SDLKey spaceship::getShootKey() {
	return keys[4];
}

void spaceship::shoot() {
	this->shootchannel = Mix_PlayChannel(-1, shootsound, 1);
	for (unsigned int i = 0; i < this->bullets.size(); i++) {
		if (this->bullets[i].used == true)
			continue;
		for (int j = 0; j < BULLETTRAIL; j++) {
			this->bullets[i].x[j] = (this->width - 
					((BULLETTRAIL - j) / BULLETTRAIL)) * 
					sin(this->angle * M_PI/180) + this->x;
			this->bullets[i].y[j] = (this->width - 
					((BULLETTRAIL - j) / BULLETTRAIL)) * 
					(-1) * cos(this->angle * M_PI/180) + 
					this->y;
		}
		this->bullets[i].speedx = BULLETSPEED  * 
				sin(this->angle * M_PI/180);
		this->bullets[i].speedy = BULLETSPEED * (-1) *
				cos(this->angle * M_PI/180);
		this->bullets[i].used = true;
		return;
	}
	this->bullets.push_back(*(new bullet));
	this->bullets[bullets.size() - 1].texture = this->bullets[0].texture;
	this->bullets[bullets.size() - 1].gravity = this->gravity;
	for (int j = 0; j < BULLETTRAIL; j++) {
		this->bullets[bullets.size() - 1].x[j] = (this->width - 
				((BULLETTRAIL - j) / BULLETTRAIL)) * 
				sin(this->angle * M_PI/180) + this->x;
		this->bullets[bullets.size() - 1].y[j] = (this->width - 
				((BULLETTRAIL - j) / BULLETTRAIL)) * 
				(-1) * cos(this->angle * M_PI/180) + 
				this->y;
	}
	this->bullets[bullets.size() - 1].speedx = BULLETSPEED  * 
			sin(this->angle * M_PI/180);
	this->bullets[bullets.size() - 1].speedy = BULLETSPEED * (-1) *
			cos(this->angle * M_PI/180);
	this->bullets[bullets.size() - 1].used = true;
}

void spaceship::move(vector<planet*> &planetlist, vector<spaceship> &spaceshiplist, screen *scr) {
	GLuint tmp;
	tmp = SDL_GetTicks();
	float speed;
	int i;
	float theta;
	float distance;

	for (unsigned int i = 0; i < planetlist.size(); i++) {
		if (planetlist[i]->mass == 0)
			continue;
		theta = atan2(this->y - planetlist[i]->y, 
			      this->x - planetlist[i]->x);
		distance = sqrt(pow(this->x - planetlist[i]->x, 2) +
			   pow(this->y - planetlist[i]->y, 2));
		if (distance < planetlist[i]->width/2 + this->width/2) {
			if (this == &spaceshiplist[0]) {
				this->die(scr, spaceshiplist[1]);
			} else {
				this->die(scr, spaceshiplist[0]);
			}
		}
		if (planetlist[i]->gravity == this->gravity) {
			this->speedx -= (planetlist[i]->mass/(this->mass*distance)) * 
					GRAVITYCONSTANT * cos(theta) * 
					(TIMESTEP)/1000;
			this->speedy -= (planetlist[i]->mass/(this->mass*distance)) *
					GRAVITYCONSTANT * sin(theta) * 
					(TIMESTEP)/1000;
		} else {
			this->speedx += (planetlist[i]->mass/(this->mass*distance)) * 
					GRAVITYCONSTANT * cos(theta) * 
					(TIMESTEP)/1000;
			this->speedy += (planetlist[i]->mass/(this->mass*distance)) *
					GRAVITYCONSTANT * sin(theta) * 
					(TIMESTEP)/1000;
		}
	}

	this->angle = this->angle + 360*this->rotFreq*(TIMESTEP)/1000;
	while (this->angle > 360) 
		this->angle -= 360;
	while (this->angle < 0) 
		this->angle += 360;
		
	speed = sqrt(pow(this->speedx, 2) + pow(this->speedy, 2));
	if (speed > 0)
		theta = atan2(this->speedy, this->speedx);

	this->speedx -= cos(theta)*speed*DRAGFACTOR*(TIMESTEP)/1000;
	this->speedy -= sin(theta)*speed*DRAGFACTOR*(TIMESTEP)/1000;

	this->speedx += sin(this->angle*M_PI/180)*this->acceleration*(TIMESTEP)/1000;
	this->speedy -= cos(this->angle*M_PI/180)*this->acceleration*(TIMESTEP)/1000;

	this->x += this->speedx*(TIMESTEP)/1000;
	this->y += this->speedy*(TIMESTEP)/1000;
		
	for (i = 0; i < 3; i++) {
		switch(i) {
			case 0:
				theta = 0;
				break;
			case 1:
				theta = 135;
				break;
			case 2: 
				theta = 225;
				break;
			default:
				break;
		}
		if (this->x + this->width*sin((this->angle + theta)*M_PI/180)/2 < scr->left) {
			this->x = scr->left - this->width*sin((this->angle + theta)*M_PI/180)/2;
			this->speedx = 0;
		}
		if (this->y - this->height*cos((this->angle + theta)*M_PI/180)/2 < scr->top) {
			this->y = scr->top + this->height*cos((this->angle + theta)*M_PI/180)/2;
			this->speedy = 0;
		}
		if (this->x + this->width*sin((this->angle + theta)*M_PI/180)/2 > scr->right) {
			this->x = scr->right - this->width*sin((this->angle + theta)*M_PI/180)/2;
			this->speedx = 0;
		}
		if (this->y - this->height*cos((this->angle + theta)*M_PI/180)/2 > scr->bottom) {
			this->y = scr->bottom + this->height*cos((this->angle + theta)*M_PI/180)/2;
			this->speedy = 0;
		}
	}	
	
	for (unsigned int i = 0; i < bullets.size(); i++) {
		this->bullets[i].move(planetlist, spaceshiplist, scr);
	}
	
	this->ticks = tmp;
}

void spaceship::draw(GLuint texture) {
	glPushMatrix(); //begin drawing the ship

	/* Rotate. */
	glTranslatef(this->x, this->y, 0.0); 
	glRotatef(this->angle, 0.0, 0.0, 1.0);

	glBindTexture(GL_TEXTURE_2D, texture);

	glEnable(GL_BLEND);
	glBegin(GL_QUADS);
	glTexCoord2i(0, 0);
	glVertex3f((-1)*this->width/2, (-1)*this->height/2, 0);

	glTexCoord2i(1, 0);
	glVertex3f(this->width/2, (-1)*this->height/2, 0);

	glTexCoord2i(1, 1);
	glVertex3f(this->width/2, this->height/2, 0);

	glTexCoord2i(0, 1);
	glVertex3f((-1)*this->width/2, this->height/2, 0);
	glEnd();

	glPopMatrix();
	
	for (unsigned int i = 0; i < this->bullets.size(); i++) {
		this->bullets[i].draw();
	}
}

int spaceship::setRotFreq(float rotFreq) {
	this->rotFreq = rotFreq;
	return 1;
}

float spaceship::getRotFreq() {
	return this->rotFreq;
}

int spaceship::setAcceleration(float acceleration) {
	if (acceleration != 0) {
		if (this->thrustchannel1 < 0)
			this->thrustchannel1 = Mix_FadeInChannel(-1, thrustsound1, -1, 300);
		if (this->thrustchannel2 < 0)
			this->thrustchannel2 = Mix_FadeInChannel(-1, thrustsound2, -1, 300);
	} else {
		if (this->thrustchannel1 >= 0) {
			Mix_FadeOutChannel(this->thrustchannel1, 50);
			this->thrustchannel1 = -1;
		}
		if (this->thrustchannel2 >= 0) {
			Mix_FadeOutChannel(this->thrustchannel2, 50);
			this->thrustchannel2 = -1;
		}
	}
	this->acceleration = acceleration;
	return 1;
}

float spaceship::getAcceleration() {
	return this->acceleration;
}

void spaceship::setTextures(GLuint gravshiptex, GLuint antigravshiptex, GLuint gravbullettex, GLuint antigravbullettex) {
	if (this->gravity == GRAVITY) {
		this->texture = gravshiptex;
		for (unsigned int i = 0; i < this->bullets.size(); i++) {
			this->bullets[i].texture = gravbullettex;
		}
	} else {
		this->texture = antigravshiptex;
		for (unsigned int i = 0; i < this->bullets.size(); i++) {
			this->bullets[i].texture = antigravbullettex;
		}
	}
}

void spaceship::setkeys(SDLKey up, SDLKey down, SDLKey left, SDLKey right, SDLKey shoot) {
	this->keys[0] = up;
	this->keys[1] = down;
	this->keys[2] = left;
	this->keys[3] = right;
	this->keys[4] = shoot;	
}

void spaceship::setgravity(bool grav) {
	this->gravity = grav;
	for (int i = 0; i < NUMBULLETS; i++)
		this->bullets[i].gravity = grav;
}

void spaceship::die(screen *scr, spaceship &other) {
	this->health -= 100;
	if (this->health <= 0) {
		other.score++;
		this->x = rand()%((int)(scr->right - scr->left));
		this->y = rand()%((int)(scr->bottom - scr->top));
		this->health = 1000;
	}
	this->hitchannel = Mix_PlayChannel(-1, hitsound, 1);
}

float spaceship::getX() {
	return this->x;
}

float spaceship::getY() {
	return this->y;
}

bullet::bullet() {
	this->ticks = SDL_GetTicks();
	this->mass = 5;
	for (int i = 0; i < BULLETTRAIL; i++) {
		this->x[i] = 0;
		this->y[i] = 0;
	}
	this->speedx = 0;
	this->speedy = 0;	
	this->used = false;
	this->gravity = GRAVITY;
}

bullet::~bullet() {
	
}

void bullet::move(vector<planet*> &planetlist, vector<spaceship> &spaceshiplist, screen *scr) {
	GLuint tmp = SDL_GetTicks();
	float theta;
	float distance;
	
	for (unsigned int i = 0; i < planetlist.size(); i++) {
		if (planetlist[i]->mass == 0)
			continue;
		if (this->used == false) {
			this->ticks = tmp;
			return;
		}
		theta = atan2(this->y[0] - planetlist[i]->y, 
			      this->x[0] - planetlist[i]->x);
		distance = sqrt(pow(this->x[0] - planetlist[i]->x, 2) +
				pow(this->y[0] - planetlist[i]->y, 2));
		if (distance < planetlist[i]->width/2 + this->width/2) {
			this->used = false;
			Mix_PlayChannel(-1, explodesound, 1);
			continue;
		}
		if (planetlist[i]->gravity == this->gravity) {
			this->speedx -= (planetlist[i]->mass/(this->mass*distance)) * 
					GRAVITYCONSTANT * cos(theta) * 
					(TIMESTEP)/1000;
			this->speedy -= (planetlist[i]->mass/(this->mass*distance)) *
					GRAVITYCONSTANT * sin(theta) * 
					(TIMESTEP)/1000;
		} else {
			this->speedx += (planetlist[i]->mass/(this->mass*distance)) * 
					GRAVITYCONSTANT * cos(theta) * 
					(TIMESTEP)/1000;
			this->speedy += (planetlist[i]->mass/(this->mass*distance)) *
					GRAVITYCONSTANT * sin(theta) * 
					(TIMESTEP)/1000;
		}
	}
	
	for (int i = 0; i < NUMSHIPS; i++) {
		distance = sqrt(pow(this->x[0] - spaceshiplist[i].getX(), 2) +
				pow(this->y[0] - spaceshiplist[i].getY(), 2));
		if (distance < this->width/2 + 20) {
			spaceshiplist[i].die(scr, spaceshiplist[(i+1)%2]);
			this->used = false;
		}
	}
		
	this->x[0] += this->speedx * (TIMESTEP)/1000;
	this->y[0] += this->speedy * (TIMESTEP)/1000;
	
	for (int i = 1; i < BULLETTRAIL; i++) {
		theta = atan2(this->y[i]- this->y[i-1], this->x[i] - this->x[i-1]);
		this->x[i] = this->x[i-1] + BULLETGAP * cos(theta);
		this->y[i] = this->y[i-1] + BULLETGAP * sin(theta);
	}
	
	if (this->x[0] - this->width/2 < scr->left) {
		this->used = false;
	}
	if (this->x[0] + this->width/2 > scr->right) {
		this->used = false;
	}
	if (this->y[0] - this->height/2 < scr->top) {
		this->used = false;
	}
	if (this->y[0] + this->height/2 > scr->bottom) {
		this->used = false;
	}
	
	this->ticks = tmp;
}

void bullet::draw() {
	if (this->used == false)
		return;
	for (int i = 0; i < BULLETTRAIL; i++) {
		glPushMatrix(); //begin drawing the ship

		/* Rotate. */
		glTranslatef(this->x[i], this->y[i], 0.0); 
		glRotatef(atan2(this->speedy, this->speedx) * 180/M_PI + 90, 0, 0, 1);

		glBindTexture(GL_TEXTURE_2D, this->texture);

		glEnable(GL_BLEND);
		glBegin(GL_QUADS);
		glColor4f(1, 1, 1, ((float)(BULLETTRAIL - i + 1))/ (BULLETTRAIL + 1));
		glTexCoord2i(0, 0);
		glVertex3f((-1)*this->width/2, (-1)*this->height/2, 0);

		glTexCoord2i(1, 0);
		glVertex3f(this->width/2, (-1)*this->height/2, 0);

		glTexCoord2i(1, 1);
		glVertex3f(this->width/2, this->height/2, 0);

		glTexCoord2i(0, 1);
		glVertex3f((-1)*this->width/2, this->height/2, 0);
		glColor4f(1, 1, 1, 1);
		glEnd();

		glPopMatrix();
	}
}

