#ifndef CCALLBACKPARTICLEEMITTER_H_INCLUDED
#define CCALLBACKPARTICLEEMITTER_H_INCLUDED


// This Internal Callback-EventReceiver helps to push the Events
// directly to to CallBack-Method.
#include "IParticleEmitter.h"
#include "irrArray.h"


typedef bool(*ParticleEmitterCallbackPtr)(SParticle*,long, long);

namespace irr
{
namespace scene
{
class CCallbackParticleEmitter : public IParticleEmitter
{
public:
    //! constructor
    CCallbackParticleEmitter(ParticleEmitterCallbackPtr callBack,
		core::vector3df direction = core::vector3df(0.0f,0.03f,0.0f),
		u32 minParticlesPerSecond = 20,
		u32 maxParticlesPerSecond = 40,
		video::SColor minStartColor = video::SColor(255,0,0,0),
		video::SColor maxStartColor = video::SColor(255,255,255,255),
		u32 lifeTimeMin=2000,
		u32 lifeTimeMax=4000,
		s32 maxAngleDegrees=0) :
    callback(callBack)
    {
        seed = 0x0f0f0f0f;
    }

    virtual ~CCallbackParticleEmitter() {};


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

        u32 pps = (MaxParticlesPerSecond - MinParticlesPerSecond);
        f32 perSecond = pps ? (f32)MinParticlesPerSecond + (randomizerRand() % pps) : MinParticlesPerSecond;
        f32 everyWhatMillisecond = 1000.0f / perSecond;

        if(Time > everyWhatMillisecond)
        {
            Particles.set_used(0);
            s32 amount = (s32)((Time / everyWhatMillisecond) + 0.5f);
            Time = 0;
            SParticle p;

            if(amount > (s32)MaxParticlesPerSecond*2)
                amount = MaxParticlesPerSecond * 2;

            for(s32 i=0; i<amount; ++i) {
                p.startTime = now;
                p.vector = Direction;
                if(MaxLifeTime - MinLifeTime == 0)
                    p.endTime = now + MinLifeTime;
                else
                    p.endTime = now + MinLifeTime + (randomizerRand() % (MaxLifeTime - MinLifeTime));
                p.color = MinStartColor.getInterpolated(
                    MaxStartColor, (randomizerRand() % 100) / 100.0f);

                p.startColor = p.color;
                p.startVector = p.vector;

                bool bAddParticle = callback(&p, amount, i);

                p.startVector = p.vector;

                if (bAddParticle)
                    Particles.push_back(p);
            }
            outArray = Particles.pointer();
            return Particles.size();

		}
        return 0;

    };

	//! Get emitter type
	virtual E_PARTICLE_EMITTER_TYPE getType() const { return EPET_BOX; }


//! Writes attributes of the object.
    virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options)
{
/*
	core::vector3df b = Box.getExtent();
	b *= 0.5f;
	out->addVector3d("Box", b);
	out->addVector3d("Direction", Direction);
	out->addInt("MinParticlesPerSecond", MinParticlesPerSecond);
	out->addInt("MaxParticlesPerSecond", MaxParticlesPerSecond);
	out->addColor("MinStartColor", MinStartColor);
	out->addColor("MaxStartColor", MaxStartColor);
	out->addInt("MinLifeTime", MinLifeTime);
	out->addInt("MaxLifeTime", MaxLifeTime);
	out->addInt("MaxAngleDegrees", MaxAngleDegrees);
*/
}

//! Reads attributes of the object.
virtual s32 deserializeAttributes(s32 startIndex, io::IAttributes* in, io::SAttributeReadWriteOptions* options)
{
	// read data and correct input values here
/*
	core::vector3df b = in->getAttributeAsVector3d("Box");

	if (b.X <= 0)
		b.X = 1.0f;
	if (b.Y <= 0)
		b.Y = 1.0f;
	if (b.Z <= 0)
		b.Z = 1.0f;

	Box.MinEdge.X = -b.X;
	Box.MinEdge.Y = -b.Y;
	Box.MinEdge.Z = -b.Z;
	Box.MaxEdge.X = b.X;
	Box.MaxEdge.Y = b.Y;
	Box.MaxEdge.Z = b.Z;

	Direction = in->getAttributeAsVector3d("Direction");
	if (Direction.getLength() == 0)
		Direction.set(0,0.01f,0);

	MinParticlesPerSecond = in->getAttributeAsInt("MinParticlesPerSecond");
	MaxParticlesPerSecond = in->getAttributeAsInt("MaxParticlesPerSecond");

	MinParticlesPerSecond = core::max_<s32>(1, MinParticlesPerSecond);
	MaxParticlesPerSecond = core::max_<s32>(MaxParticlesPerSecond, 1);
	MaxParticlesPerSecond = core::min_<s32>(MaxParticlesPerSecond, 200);
	MinParticlesPerSecond = core::min_<s32>(MinParticlesPerSecond, MaxParticlesPerSecond);

	MinStartColor = in->getAttributeAsColor("MinStartColor");
	MaxStartColor = in->getAttributeAsColor("MaxStartColor");
	MinLifeTime = in->getAttributeAsInt("MinLifeTime");
	MaxLifeTime = in->getAttributeAsInt("MaxLifeTime");
	MaxAngleDegrees = in->getAttributeAsInt("MaxAngleDegrees");

	MinLifeTime = core::max_<s32>(0, MinLifeTime);
	MaxLifeTime = core::max_<s32>(MaxLifeTime, MinLifeTime);
	MinLifeTime = core::min_<s32>(MinLifeTime, MaxLifeTime);
*/
	return in->findAttribute("MaxAngleDegrees");
}


protected:
    ParticleEmitterCallbackPtr callback;
private:
    core::array<SParticle> Particles;

	core::vector3df Direction;
	u32 MinParticlesPerSecond, MaxParticlesPerSecond;
	video::SColor MinStartColor, MaxStartColor;
	u32 MinLifeTime, MaxLifeTime;

	u32 Time;
	u32 Emitted;
	s32 MaxAngleDegrees;

	f32 MinimumDistance;
	f32 MaximumDistance;

    //randomizer abhängigkeit reduzieren
	s32 seed;

	//! generates a pseudo random number
	s32 randomizerRand()
	{
		const s32 m = 2147483399;	// a non-Mersenne prime
		const s32 a = 40692;		// another spectral success story
		const s32 q = m/a;
		const s32 r = m%a;		// again less than q

		seed = a * (seed%q) - r* (seed/q);
		if (seed<0) seed += m;

		return seed;
	}

	//! resets the randomizer
	void ranomizerReset()
	{
		seed = 0x0f0f0f0f;
	}

};

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



#endif // CCALLBACKPARTICLEEMITTER_H_INCLUDED
