#pragma once
#include "../../stdafx.h"
#include "../glLibLocals.h"
#include "../glLibShader.h"

#include "glLibParticleAttractor.h"
#include "glLibParticleCollider.h"
#include "glLibParticleEmitter.h"

#include "../glLibRender/glLibRendererParticle.h"

class glLibParticleSystem {
	public:
		unsigned long max_numof_particles;

		float null_position[3];

		glLibTexture2D* texture_particle;

	private:
		list<glLibParticleAttractor*> _attractors;
		list< glLibParticleCollider*>  _colliders;
		list<  glLibParticleEmitter*>   _emitters;
		map<glLibParticleEmitter*,unsigned long> _emitters_array_partition; //tells how many particles in the arrays each emitter is responsible for

		float _forces[3];

		char _type;

		bool _must_delete_texture;

		bool _initialized;

		GLfloat *_arr_position, *_arr_velocity, *_arr_params1, *_arr_params2, *_arr_rand_vecs;

		glLibRendererParticle* _renderer;

		//GPU simulation specific
		glLibShader *shader_update, *shader_attractor;

		GLuint _vbo_position_1, _vbo_position_2; //position
		GLuint _vbo_velocity_1, _vbo_velocity_2; //velocity
		GLuint _vbo_params1_1, _vbo_params1_2; //time, max time, unused
		GLuint _vbo_params2_1, _vbo_params2_2; //position jitter sc, velocity jitter sc, unused
		GLuint _vbo_rand_vecs; //normalized random vectors

		char _vbo_ping_pong_velocity;
		char _vbo_ping_pong_others;

		GLint  _location_update_position;
		GLint  _location_update_velocity;
		GLint   _location_update_params1;
		GLint   _location_update_params2;
		GLint _location_update_rand_vecs;

		GLint _location_attractor_position;
		GLint _location_attractor_velocity;
		GLint  _location_attractor_params1;

	public:
		glLibParticleSystem(glLibFlag simulation_type);
		~glLibParticleSystem();

		void add_element(glLibParticleAttractor* attractor);
		void add_element(glLibParticleCollider* collider);
		void add_element(glLibParticleEmitter* emitter);
		void remove_element(glLibParticleAttractor* attractor);
		void remove_element(glLibParticleCollider* collider);
		void remove_element(glLibParticleEmitter* emitter);

		void set_texture(glLibTexture2D* new_texture);

		void set_renderer(glLibRendererParticle* renderer);

		template <typename type_float> void add_force(type_float x, type_float y, type_float z) {
			_forces[0] += (float)x;
			_forces[1] += (float)y;
			_forces[2] += (float)z;
		}
		template <typename type_float> void add_force(type_float force[3]) {
			for (char i=0;i<3;++i) _forces[i] += (float)force[i];
		}

		unsigned long get_numof_particles_required(void);
		void init(unsigned long new_max_numof_particles);

	private:
		void glLibInternal_print_particles_array(void);
		void glLibInternal_recalculate_particle_ownership(void);

	private:
		void glLibInternal_step_cpu(float dt);
		void glLibInternal_step_gpu_attractors(float dt);
		void glLibInternal_step_gpu(float dt);
	public:
		void step(float dt);

	public:
		void draw(void);
};

/*
TODO:
Branching particle systems (e.g., fire particles emit smoke).  How will we handle that internally???

velocity dampening also

some emitters' streams periodically stutter.  Probably a particle ownership issue

stop / start emitters
*/