/*****************************************************************************
 * Class for managing double buffering and timing issues.  See .h for more
 * details
 * ***************************************************************************/

#include "Graphics.h"

/*****************************************************************************
 * Initialize the backbuffer and stuff
 * ***************************************************************************/
Graphics::Graphics(){
	buf = create_bitmap(SCN_WIDTH, SCN_HEIGHT);
	start_of_tick = 0;
	start_of_second = clock();
	should_draw_framerate = true;
	frames_last_second = FPS;
	delay = 1000/FPS;
	delay_changed = 0;
	frames_this_second = 0;
}

/*****************************************************************************
 * Update waits until the next frame, and then updates the screen
 * ***************************************************************************/
void Graphics::update(){
	update_particles();
	draw_particles();
	
	update_framerate();
	
	blit(buf, screen, 0, 0, 0, 0, SCN_WIDTH, SCN_HEIGHT);
	while(clock() < start_of_tick + delay)
		; // wait

	start_of_tick = clock();
}

/*****************************************************************************
 * draw_framerate puts the framerate on the screen
 * ***************************************************************************/
void Graphics::update_framerate(){
	frames_this_second++;

	// Recalculate framerate every second
	if (clock() > start_of_second + 1000){
		frames_last_second = frames_this_second;
		frames_this_second = 0;
		start_of_second = clock();

		// Calculate an appropriate delay
		delay_changed++;
		int desired_delay = 1000/FPS;
		int actual_delay = 1000/frames_last_second;
		int delay_difference = desired_delay - actual_delay;
		if (delay_changed > 5)
			delay_difference = delay_difference / 4;
		delay = delay + delay_difference;
		if (delay < 0)
		    delay = 0;
	}

	// Draw framerate to screen
	char cbuf[64];
	sprintf(cbuf, "Framerate: %i, Delay: %i", frames_last_second, delay);
	if (should_draw_framerate)
		textout_centre_ex(buf, font, cbuf, 100, 10, 0xffffff, -1);
}

/*****************************************************************************
 * Updates the list of particles by calling their update function, and
 * deleting them from the list if they are no longer alive.
 * ***************************************************************************/
void Graphics::update_particles(){ 
	list<particle*>::iterator i;
	for (i = particle_list.begin(); i != particle_list.end(); ++i){
		if ((*i)->update() == false){
			i = particle_list.erase(i);	
		}	
	}
}

/*****************************************************************************
 * Draw all particles to the back buffer
 * ***************************************************************************/
void Graphics::draw_particles(){
	list<particle*>::iterator i;
	for(i = particle_list.begin(); i != particle_list.end(); ++i){
		(*i)->draw(buf);
	}
}

/*****************************************************************************
 * Adds the given particle to the list of particles, or a new particle with
 * the givem properties
 * ***************************************************************************/
void Graphics::add_particle(int alpha, int lifetime, BITMAP *picture, 
							int x, int y, int xvel, int yvel)
{
	particle *new_particle = new particle(alpha, lifetime, picture, x, y, xvel, yvel);
	particle_list.push_back(new_particle);
}

void Graphics::add_particle(particle *new_particle){
	particle_list.push_back(new_particle);
}
