#include "ParticleSystem.h"

ParticleSystem::ParticleSystem(const unsigned int maxpart) {
	maxparticles = maxpart;
	numparticles = 0;
	lastupdate = 0;

	particles = new Particle[maxpart];
}

ParticleSystem::ParticleSystem(const ParticleSystem& rhs) {
	maxparticles = rhs.maxparticles;
	numparticles = rhs.numparticles;
	lastupdate = rhs.lastupdate;

	particles = new Particle[maxparticles];
	memcpy(particles, rhs.particles, maxparticles * sizeof(Particle));
}

ParticleSystem& ParticleSystem::operator=(const ParticleSystem& rhs) {
	if (&rhs == this)
		return *this;

	delete [] particles;

	maxparticles = rhs.maxparticles;
	numparticles = rhs.numparticles;
	lastupdate = rhs.lastupdate;

	particles = new Particle[maxparticles];
	memcpy(particles, rhs.particles, maxparticles * sizeof(Particle));

	return *this;
}

ParticleSystem::~ParticleSystem() {
	delete [] particles;
	particles = 0;
}

ParticleVector ParticleSystem::getOrigin() const { return origin; }
void ParticleSystem::setOrigin(const ParticleVector& neworigin) { origin = neworigin; }

ParticleVector ParticleSystem::getSize() const { return size; }
void ParticleSystem::setSize(const ParticleVector& newsize) { size = newsize; }

Particle* ParticleSystem::emit(unsigned int& numtoemit) {
	assert(numparticles <= maxparticles);
	
	if (numparticles + numtoemit > maxparticles)
		numtoemit = maxparticles - numparticles;

	Particle* ret = &(particles[numparticles]);
	numparticles += numtoemit;

	return ret;
}

void ParticleSystem::reset() {
	while (numparticles > 0)
		particles[--numparticles].Stop();
}

void ParticleSystem::update() {

	unsigned long curtime = glutGet(GLUT_ELAPSED_TIME);
	unsigned long timediff = curtime - lastupdate;

	lastupdate = curtime;
	
	//Do whatever the particle system does.
	updateBehavior();
	

	for (unsigned int partnum = 0; partnum<numparticles;partnum++) {
		if (!particles[partnum].active) {
			//Inactive particles get bumped off of the array.
			particles[partnum] = particles[numparticles-1];
			numparticles--;

			//Pretend that this iteration didn't happen.
			if (partnum > 0)
				partnum--;

			continue;
		}
		
		if (particles[partnum].maxtimetolive <= 0.0)
			//This probably hasn't been set yet.
			particles[partnum].maxtimetolive =
			particles[partnum].timetolive;
		
		//Timetolive is in seconds; timediff is ms.
		particles[partnum].timetolive -= timediff / 1000.0;
		if (particles[partnum].timetolive <= 0.0) {
			particles[partnum].active = false;
			continue;
		}

		//Make the particle fade.
		glColor4f(particles[partnum].color.r,
		particles[partnum].color.g,
		particles[partnum].color.b,
		particles[partnum].color.a /
		particles[partnum].maxtimetolive*particles[partnum].timetolive);

		particles[partnum].pos += particles[partnum].velocity *
		(timediff / 1000.0);
			
		particles[partnum].velocity +=
		particles[partnum].acceleration * (timediff / 1000.0);

		glBegin(GL_TRIANGLE_STRIP);
		glTexCoord2d(1,1);
		glVertex3f(
		particles[partnum].pos.x+particles[partnum].size/2,
		particles[partnum].pos.y+particles[partnum].size/2,
		particles[partnum].pos.z);
				
		glTexCoord2d(0,1);
		glVertex3f(
		particles[partnum].pos.x-particles[partnum].size/2,
		particles[partnum].pos.y+particles[partnum].size/2,
		particles[partnum].pos.z);

		glTexCoord2d(1,0);
		glVertex3f(
		particles[partnum].pos.x+particles[partnum].size/2,
		particles[partnum].pos.y-particles[partnum].size/2,
		particles[partnum].pos.z);
			
		glTexCoord2d(0,0);
		glVertex3f(
		particles[partnum].pos.x-particles[partnum].size/2,
		particles[partnum].pos.y-particles[partnum].size/2,
		particles[partnum].pos.z);
			
		glEnd();
	}

}
