#include <FastLED.h>

#define LED_PIN     5
#define NUM_LEDS    30
#define BRIGHTNESS  64
#define LED_TYPE    WS2811
#define COLOR_ORDER GRB
CRGB leds[NUM_LEDS];


const int numSparks = 12; 

//Set up palette.
//We are using the palette to track the 
// color if the spark during its life spanp

CRGBPalette16 initPalette()
{
    CRGB col1  = CRGB::White ;
    CRGB col2  = CRGB:: Orange; 
    CRGB col3  = CRGB::Orange; 
    CRGB black  = CRGB::Black;

    CRGBPalette16 pal;
    pal = CRGBPalette16(
                        black,  
                        col1,  
                        col1,
                        col2,
                        
                        col2, 
                        col2,
                        col2,
                        col2,
                        
                        col2,
                        col2,
                        col3,
                        col3,
                        
                        col3,
                        col3,
                        black,
                        black );
    return pal;
}

// Fireworks
//

class rocket {
    private:
    const int tail =7;
    int pos = 1;
    
    int speed = 20;


    
    public:
    rocket() {
    }

    // Render the rocket
    void display() {
        static int pass=0;
        pass++;

        if (pass > speed) {
            leds[pos] = CHSV(0,255,255);
            pos++;
            if (pos >= NUM_LEDS) pos = 1;
            pass = 0;
            for (int i = 2; i<tail; i++) {
                if (pos>i) {
                    leds[pos-i].fadeToBlackBy(random8(200)); 
                }
            }
            if (pos>=tail) leds[pos-tail] = CRGB::Black;
        }
    }
};

// class representing a spar
class spark {

    private:
    float speed;
    float fPos;
    int pos;
    int oldPos;
    int life;
    int lifeExp; 
    CRGB color;
    bool lit; 
    CRGBPalette16 pal;

    public:
    spark(){
        lit = false;   
    };

    void light(float h, float s, CRGBPalette16  p ){
        lit  = true;
        fPos = h; 
        speed = s;
        pal = p; 
        lifeExp = random8(200) + 2000;
        life = lifeExp; 
    };

    bool display(){
        int index; 
        if (!lit ) return lit ;
        fPos+=speed;
        life--;
        index =255.0f - ((float)life/(float)lifeExp * 255.0f); 
        color =  ColorFromPalette(pal,index);
        // apply gravity to speed
        // Make gravity have less of an effect as
        // the spark reaches the end of its lifespan
         // i.e.as it gets lighter and floats  
        speed += .000025 * (float)life/(float)lifeExp; 
        oldPos = pos;
        pos = (long)fPos;
        leds[oldPos] = CRGB::Black;
        // put the spark out if it reaches the edge
        // or reaches the end of its lifespan
        if (fPos<0 || fPos>=NUM_LEDS || life<0){
            lit  = false;
            return lit;
        }
        leds[pos] = color;    
    }
 };

rocket Rocket;
spark Spark[numSparks];
//spark Spark2[numSparks];

void setup() {
    //delay( 3000 ); // power-up safety delay
    FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
    FastLED.setBrightness(  BRIGHTNESS );
    
    bool res;
    float speed;

    CRGBPalette16  pal = initPalette(); 
    
    for(int i=0; i<numSparks; i++){
        speed = .025f * (float)i/numSparks;
        if (random(2) ==1) speed *= -1;
        //Ignite each spark
        Spark[i].light(15.0f, speed, pal); 
    }
}
     
void loop()
{   
    // advance and display each spark 
    for (int c=0; c < numSparks; c++){
        Spark[c].display();
    }
    
    FastLED.show();
    
}

uno:A5.2
uno:A4.2
uno:AREF
uno:GND.1
uno:13
uno:12
uno:11
uno:10
uno:9
uno:8
uno:7
uno:6
uno:5
uno:4
uno:3
uno:2
uno:1
uno:0
uno:IOREF
uno:RESET
uno:3.3V
uno:5V
uno:GND.2
uno:GND.3
uno:VIN
uno:A0
uno:A1
uno:A2
uno:A3
uno:A4
uno:A5
neopixels:DOUT
neopixels:VDD
neopixels:VSS
neopixels:DIN