#ifndef PARTICLE_DRAWER_H
#define PARTICLE_DRAWER_H

#include <list>
#include <vector>
#include "ParticleEngine.h"
#include "ParticleManager.h"


#include "MemoryManager/DebugNew.h"


namespace ParticleSystem
{
/**
 * classe permettant de gerer un affichage des moteur de particules cohérent.
 *
 * Cette classe est en faite une classe utilitaire permettant de prendre en compte l'affichage de moteurs de particules
 * non additifs. En effet lorsqu'un moteur de particules n'est pas en mode additif, il faut prendre en compte le fait
 * que les differents moteurs doivent etres affiché du plus profond au plus proche afin que l'equation de blending
 * soit valide.
 *
 * Pour cela, le drawer peut prendre plusieurs manager de particules ou moteurs de particules, il les stocke
 * en interne en fonction de leur eloignement par rapport à la camera. ainsi, l'utilisateur n'a plus a se preoccuper
 * de l'ordre d'affichage des moteurs de particules.
 *
 * Pour permettre une plus grande finesse dans l'affichage des moteurs de particules (culling et autre) le drawer,
 * comme pour le manager, implemente des methode d'iteration. celle ci permettent a l'utilisateur de parcourire 
 * l'ensemble des moteurs de particules dans l'ordre dans lequel ils doivent etres affiché.
 */
class ParticleDrawer
{
private:
	/**
	 * structure stockant un pointeur sur un moteur de particules et la distance de ce moteur de particules par rapport
	 * à la camera.
	 */
	struct Engine
	{
		/**
		 * le moteur de particules
		 */
		ParticleEngine * engine;
		/**
		 * la distance a la camera.
		 */
		float distance;
	};

	/**
	 * la liste de moteur de particules du drawer.
	 */
	std::list<Engine> *engine;

	/**
	 * l'iterateur utilisé par les methodes d'iteration.
	 */
	std::list<Engine>::iterator iterator;
protected:
public:

	/**
	 * constructeur par defaut
	 */ 
	ParticleDrawer(void);

	/**
	 * destructeur par defaut
	 */
	virtual ~ParticleDrawer(void);

	/**
	 * methode ajoutant l'ensemble des moteurs de particules present dans le manager au drawer.
	 *
	 * Les moteurs de particules seront ajouté dans la liste des moteur trié en fonction de leur distance
	 * par rapport a la camera. Ainsi par la suite quand l'utilisateur voudra afficher ses moteurs de particules,
	 * il lui suffira de les afficher dans l'ordre auquel ils arrivent durant l'iteration.
	 *
	 * Attention, cette methode utilise l'iteration de la classe de ParticleManager. Il ne faut donc pas faire
	 * appel a cettte methode durant une iteration du particleManager.
	 *
	 * De même, cette methode redemmare l'iteration en cours afin d'assurer que tout les moteurs de particules
	 * seront bien pris en cours lors de l'execution, il ne faut donc par faire appel à cette methode durant une
	 * iteration.
	 * 
	 * @param manager : le manager dont on veut ajouter les moteurs de particules au drawer.
	 */
	void addManager(ParticleManager * manager);

	/**
	 * methode ajoutant un moteur de particule au drawer.
	 *
	 * Le moteur est inseré dans la liste en fonction de sa distance à la camera.
	 */
	void addEngine(ParticleEngine * e);

	/**
	 * nettoie la liste de moteur de particule du drawer. Celui ci pourra etre réutilisé pour afficher des moteurs
	 * de particules.
	 */
	void clear();

	/**
	 * dessine de facon brute l'ensemble des moteurs de particule du drawer.
	 *
	 * aucun test n'est effectué pour savoir si le moteur de particule doit etre affiché.
	 */
	void draw();

	/**
	 * demarre une iteration sur les moteurs de particules du drawer.
	 *
	 * une iteration type est du genre
	 * <PRE>
	 * ParticleDrawer drawer;
	 * [...]
	 * for(drawer.startIteration();!drawer.iterationFinished();drawer.next())
	 * {
	 * 	drawer.current().draw();
	 * }
	 * </PRE>
	 * les iteration servent a parcourire l'ensemble des moteurs de particules en fonction de leur position par rapport
	 * a la camera.
	 * 
	 * En utilisant le mecanisme d'iteration, d'utilisateur est assuré de voir ses moteur de particule proposé du plus
	 * lointain au plus proche. Ceci permet de resoudre des problemes lié a l'alpha blending et à l'ordre d'affichage
	 * des moteurs de particules.
	 */
	void startIteration();

	/**
	 * permet de savoir si l'iteration est terminée ou pas.
	 *
	 * @return bool: true si l'iteration est terminée, false sinon.
	 */
	bool iterationFinished();

	/**
	 * retourne le moteur de particule courant dans l'iteration.
	 */
	ParticleEngine &current();

	/**
	 * passe l'iteration au moteur de particule suivant.
	 *
	 * Il est a noter que si l'iteration est terminée, cette methode ne change pas de moteur de particules. Ceci afin
	 * d'assurer la validitée permanente du moteur de particules retourné par current().
	 */
	void next();
};

}

#include "MemoryManager/DebugNewOff.h"



#endif
