#ifndef CPARTICLEEMITTERMANAGER_H_INCLUDED
#define CPARTICLEEMITTERMANAGER_H_INCLUDED

//This Emitter tries to add mor functions to every emitter while
//wrapping them, and manupilate after the emit the particles.
/*
Extending the ParticleSystem

After being a long time user and also a fan of Irrlicht, i get
the feeling that some parts of the engine are getting no or only
small progress. I know it is a small (but very competent) team behind
the Engine. And one of the parts are the ParticleSysten.
The Design ist good, but it need (in my  opinion) some more features.
I found some nice ideas and ready-made affectors round here, and
i interated them in my project. And i made some extentions to Irrlicht !
And to get other involved, i put it together in a zip-file.
Basically i added some fields to the SParticle-Struct, and made some
small changes in the CParticleSystemScenenNode.

New Features now :
    * Rotating Particles
    * Scaled Particles
    * Weighted Particles
    * Aligned Particles
    * Start-Delay of Emitt
    * Various Delaytimes between emitting.

After modifying Irrlicht, i added some Affectors to enable rotating,
scaling and aligning. Not made at the moment are usage for the particle-weight.
that could be important for 'Snow' or 'Bouncing'. (and some others).

And to get random-Parametters when emitt Particles i wrote a CParticleEmitterManager,
thet act as Decorator and delegates the 'emitt' to his member-emitter (that was giving
when instantiating this Manager). After the Emitt it manipulates the 'extra-flags' of
the Particles. This make us independent from the other emitters - so we can use all
existing Emitters.

Thats all, only small schanges in Irrichti itself, but much more  features for the
Particles.

And now - i hope here are some people agree with me, that we need alo mor changes,
we should discuss -wich we want and how to get them.



*/











//The Usage is very straight-forward,  create a emitter and the creaate
// a manager, trhat holds the emitter, and act as a emitter.
// now we can use our 'additions' to the SParticle-Structure with initial
// settings without changing the existing emitters.

// the backdraft ist that we need to go also through the complete particle-array
//
// I'm working on a/the IrrlichtWrapper for PureBasic. And

/*
	// create a particle system

	scene::IParticleSystemSceneNode* ps = 0;
	ps = smgr->addParticleSystemSceneNode(false);
	ps->setPosition(core::vector3df(-70,60,40));
	ps->setScale(core::vector3df(2,2,2));

	ps->setParticleSize(core::dimension2d<f32>(20.0f, 20.0f));

	scene::IParticleEmitter* em = ps->createBoxEmitter(
		core::aabbox3d<f32>(-7,0,-7,7,1,7),
		core::vector3df(0.0f,0.06f,0.0f),
		80,100,
		video::SColor(0,255,255,255), video::SColor(0,255,255,255),
		800,2000);


    IParticleEmitter* emMgr = new CParticleEmitterManager(em, 10,20, -100.0f, 100.0f, 0.5f,2.0f, 1.0f,1.0f, 0, 0.0f, 0.0f );


	ps->setEmitter(emMgr);
	em->drop();

*/
#include "irrlicht.h"
#include "IParticleEmitter.h"
#include "irrArray.h"
#include "Random.h"


using namespace irr;
using namespace core;


namespace irr
{
namespace scene
{
class CParticleEmitterManager : public IParticleEmitter
{
public:
    //! constructor
    CParticleEmitterManager(IParticleEmitter* emitter, u32 delay_min, u32 delay_max ,
                                f32 rotate_min = 0.0f, f32 rotate_max = 0.0f,
                                f32 scale_min=1.0f, f32 scale_max=1.0f,
                                f32 weight_min=1.0f, f32 weight_max=1.0f,
                                u32 init_delay=0,
                                f32 rotate_speed_min = 0.0, f32 rotate_speed_max=0.0
                                ) //, u32 stop_time=0)
                                :
                                m_emitter(emitter),
                        m_delay_min(delay_min),m_delay_max(delay_max),
                        m_rotate_min(rotate_min),m_rotate_max(rotate_max),
                        m_scale_min(scale_min),m_scale_max(scale_max),
                        m_weight_min(weight_min),m_weight_max(weight_max),
                        m_init_delay(init_delay), //m_stop_time(stop_time),
                        m_rotate_speed_min(rotate_speed_min), m_rotate_speed_max(rotate_speed_max),
                        m_enabled(false)

    {
        irr::core::randomize();

        //calculate first delaytime
        m_delay_time = m_delay_min+rndi(m_delay_max-m_delay_min);
        m_enabled = (init_delay>0?false:true);

    };


    s32 emitt(u32 now, u32 timeSinceLastCall, SParticle*& outArray) {
        Time += timeSinceLastCall;
		s32 newParticles = 0;

		//Use initial Delay
		if (!m_enabled)
		{
		    if (m_init_delay > Time)
                return 0;
            m_enabled=true;
            Time=m_delay_time;
		}


        if (Time >= m_delay_time)
        {
            //calculate  delaytime
            m_delay_time = m_delay_min+rndi(m_delay_max-m_delay_min);

            //call the emitter
            if (m_emitter)
            {
                newParticles =  m_emitter->emitt(now,Time,outArray);

                if (newParticles && outArray)
                {
                    for (s32 i=0; i<newParticles; ++i)
                    {
                        SParticle& p =  outArray[i];

                        //now make some randome transformations
                        p.scale = irr::core::rnd(m_scale_min, m_scale_max);
                        p.rotation = irr::core::rnd(m_rotate_min, m_rotate_max);
                        p.rotation_speed = irr::core::rnd(m_rotate_speed_min, m_rotate_speed_max);
                        p.weight = irr::core::rnd(m_weight_min, m_weight_max);
//                        printf("scale=%f, rotation=%f, rot_speed=%f, weight=%f\n",p.scale,p.rotation,p.rotation_speed,p.weight);
                    }
                }
            }
            Time=0;
        }
        return newParticles;

    };


    const IParticleEmitter* getEmitter()
    {
        return m_emitter;
    }

    void setEmitter(IParticleEmitter* emitter)
    {
        m_emitter = emitter;
    }


    void setScaleRange(f32 scale_min, f32 scale_max)
    {
        m_scale_min = scale_min;
        m_scale_max = scale_max;
    }

    void setRotationRange(f32 rotate_min, f32 rotate_max)
    {
        m_rotate_min = rotate_min;
        m_rotate_max = rotate_max;
    }

    void setRotationSpeedRange(f32 rotate_speed_min, f32 rotate_speed_max)
    {
        m_rotate_speed_min = rotate_speed_min;
        m_rotate_speed_max = rotate_speed_max;
    }

    void setWeightRange(f32 weight_min, f32 weight_max)
    {
        m_weight_min = weight_min;
        m_weight_max = weight_max;
    }
//----- here are the IrrlichtInterfaceMathods

    void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options)
    {
    };

    //! Reads attributes of the object.
    s32 deserializeAttributes(s32 startIndex, io::IAttributes* in, io::SAttributeReadWriteOptions* options)
    {
        return in->findAttribute("MaxAngleDegrees");
    }


	//! Set direction the emitter emits particles
	void setDirection( const core::vector3df& newDirection )
	{
	    if (m_emitter)
	    	    m_emitter->setDirection(newDirection);
    };

	//! Set minimum number of particles the emitter emits per second
	void setMinParticlesPerSecond( u32 minPPS ) {
        if (m_emitter)
            m_emitter->setMinParticlesPerSecond(minPPS);
    };

	//! Set maximum number of particles the emitter emits per second
	void setMaxParticlesPerSecond( u32 maxPPS ) {
	    if (m_emitter)
            m_emitter->setMaxParticlesPerSecond(maxPPS);
    };

	//! Set minimum starting color for particles
	void setMinStartColor( const video::SColor& color )
	{
	    if (m_emitter)
            m_emitter->setMinStartColor(color);
    };

	//! Set maximum starting color for particles
	void setMaxStartColor( const video::SColor& color )
	{
	    if (m_emitter)
            m_emitter->setMaxStartColor(color);
    };

	//! Get direction the emitter emits particles
	const core::vector3df& getDirection()  const
	{
	    if (m_emitter)
            return m_emitter->getDirection();
        return vector3df(0,0,0);
    };

	//! Get the minimum number of particles the emitter emits per second
	u32 getMinParticlesPerSecond()  const
	{
	    if (m_emitter)
            return m_emitter->getMinParticlesPerSecond();
        return 0;
    };

	//! Get the maximum number of particles the emitter emits per second
	u32 getMaxParticlesPerSecond() const
	{
        if (m_emitter)
            return m_emitter->getMaxParticlesPerSecond();
        return 0;
    };

	//! Get the minimum starting color for particles
	const video::SColor& getMinStartColor() const {
	    if (m_emitter)
            return m_emitter->getMinStartColor();
        return SColor(0,0,0,0);
    };


	const video::SColor& getMaxStartColor() const
	{
	    if (m_emitter)
            return m_emitter->getMaxStartColor();
        return SColor(0,0,0,0);
	};

private:
    u32 m_delay_min;
    u32 m_delay_max;

    f32 m_rotate_min;
    f32 m_rotate_max;

    f32 m_rotate_speed_min;
    f32 m_rotate_speed_max;

    f32 m_scale_min;
    f32 m_scale_max;

    f32 m_weight_min;
    f32 m_weight_max;

    u32 m_delay_time;

    IParticleEmitter* m_emitter;

    u32 m_init_delay;
//    u32 m_delete_time;
    bool m_enabled;

    u32 Time;

};

} // end namespace scene
} // end namespace irr



#endif // CPARTICLEEMITTERMANAGER_H_INCLUDED
