/**
 * =========================================================================
 * File        : DefaultEmitter.cpp
 * Project     : 0 A.D.
 * Description : Default particle emitter implementation.
 * =========================================================================
 */

#include "precompiled.h"
#include "maths/MathUtil.h"
#include "DefaultEmitter.h"

CDefaultEmitter::CDefaultEmitter(const int MAX_PARTICLES, const int lifetime) : CEmitter(MAX_PARTICLES, lifetime)
{
    Setup();
}

CDefaultEmitter::~CDefaultEmitter(void)
{
}

bool CDefaultEmitter::Setup()
{
    // XYZ Position
    pos.X = 0.0f;
    pos.Y = 20.0f;
    pos.Z = 0.0f;

    yaw = DEGTORAD(0.0f);
    yawVar = DEGTORAD(360.0f);
    pitch = DEGTORAD(90.0f);
    pitchVar = DEGTORAD(45.0f);
    speed = 0.05f;
    speedVar = 0.001f;

    blend_mode      = 1;
    particleCount   = 0;
    emitsPerFrame   = 100;
    emitVar = 15;
    life = 90;
    lifeVar = 65;
    startColor.r = 100;
    startColor.g = 100;
    startColor.b = 100;
    startColorVar.r = 15;
    startColorVar.g = 15;
    startColorVar.b = 15;
    endColor.r = 0;
    endColor.g = 0;
    endColor.b = 0;
    endColorVar.r = 15;
    endColorVar.g = 15;
    endColorVar.b = 15;

    force.X = 0.000f;
    force.Y = -0.001f;
    force.Z = 0.0f;
    return true;
}

bool CDefaultEmitter::Update()
{
    int emits;
    // walk through the used list, and update each of the particles
    tParticle *tempParticle = usedList;         // start at the beginning of the used list
    tParticle *prev = usedList;                 
    while(tempParticle)                             // loop on a valid particle
    {
        // don't update if the particle is supposed to be dead
        if(tempParticle->life > 0)
        {
            // update the particle
            // Calculate the new pos
            tempParticle->pos.X += tempParticle->dir.X;
            tempParticle->pos.Y += tempParticle->dir.Y;
            tempParticle->pos.Z += tempParticle->dir.Z;

            // Add global force to direction
            tempParticle->dir.X += force.X;
            tempParticle->dir.Y += force.Y;
            tempParticle->dir.Z += force.Z;

            // Get the new color
            tempParticle->color.r += tempParticle->deltaColor.r;
            tempParticle->color.g += tempParticle->deltaColor.g;
            tempParticle->color.b += tempParticle->deltaColor.b;

            // fade it out
            if(decrementAlpha)
                tempParticle->alpha -= tempParticle->alphaDelta;

            // gets a little older
            if(decrementLife)
                tempParticle->life--;

            // move to the next particle in the list
            prev = tempParticle; 
            tempParticle = tempParticle->next;
        }
        else    // this means the particle lifetime is over
        {
            // if this is the first particle in usedList
            // then set the pointers to the next in the usedList
            // and open up the tempParticle
            if(tempParticle == usedList)
            {   
                usedList = tempParticle->next;
                tempParticle->next = openList;
                // set the open list head to the particle
                openList = tempParticle;
                prev = usedList;
                tempParticle = usedList;
            }
            else
            {

                //// We need to pull the particle out of the 
                //// used list and insert it into the open list
                
                // fix the previous node in the list to skip over the one we are pulling out
                prev->next = tempParticle->next;
                // set the particle to point to the head of the open list
                tempParticle->next = openList;
                // set the open list head to the particle
                openList = tempParticle;
                // move on to the next iteration
                tempParticle = prev->next;
            }
            // and there is one less
            particleCount--;
        }
    }   // end of while
    if(emitterLife > 0 || emitterLife == -1)
    {
        // Emit particles for this frame
        emits = emitsPerFrame + (int)((float)emitVar * RandomNum());

        // if the particle life is -1 that means it's infinite
        if(emitterLife != -1)
            emitterLife--;
        
        for(int i = 0; i < emits; i++)
            AddParticle();
        return true;
    }
    else
    {
        if(particleCount > 0)
        {   
            return true;
        }
        else
        {
            isFinished = true;
            return false;       // this will be checked for and then it will be deleted
        }
    }
}