#include "FastLED.h"
// Fastled constants
#define DATA_PIN    2
#define COLOR_ORDER GRB
#define NUM_LEDS    32
#define LED_TYPE    WS2812B
#define BRIGHTNESS  32
CRGB leds[NUM_LEDS];
#define LED_PIN 1  // Built in LED

// Couleurs
#define N_COUL 7
CRGB couleur[] = { CRGB::Red, CRGB::Green, CRGB::Blue, CRGB::Turquoise,
                   CRGB::Magenta, CRGB::Orange, CRGB::Purple, CRGB::Violet
                 };

// Animations
void anim1(CRGB color) {
  // Clignotement toutes LEDs
  byte cligno = 2 + random(3);
  for (int i = 0; i < cligno; i++) {
    byte numcoul = random(N_COUL);
    fill_solid (leds, NUM_LEDS, couleur[numcoul]);
    FastLED.show();
    delay(200);
  }
}

void anim2(CRGB color) {
  // N LED allumées qui se déplacent sur chaque oeil
  byte offset = random(NUM_LEDS / 2);
  byte nleds  = random(NUM_LEDS / 4);
  for (int k = 0; k < 1 + random(3); k++) {
    // animation jouée plusieurs fois
    for (int i = 0; i < NUM_LEDS / 2; i++) {
      // déplacement des leds
      FastLED.clear();
      for (int j = 0; j < nleds; j++) {
        byte pos1 = (offset + i + j) % (NUM_LEDS / 2);
        byte pos2 = NUM_LEDS - pos1;
        if (pos2 == NUM_LEDS) pos2 = NUM_LEDS / 2;
        leds[pos1] = color;
        leds[pos2] = color;
      }
      FastLED.show();
      delay(30);
    }
  }
  FastLED.clear();
}

void anim3(CRGB color) {
  // Clignotement une LED sur deux
  for (int k = 0; k < 6 + random(6); k++) {
    FastLED.clear();
    for (int i = 0; i < NUM_LEDS; i++) {
      if ((i + k) % 2 == 0) leds[i] = color;
    }
    FastLED.show();
    delay(100);
  }
}

void anim4(CRGB color) {
  // N LEDs allumées qui se déplacent sur chaque oeil en sens contraire
  byte offset = random(NUM_LEDS / 2);
  byte nleds  = random(NUM_LEDS / 4);
  for (int k = 0; k < 1 + random(3); k++) {
    // animation jouée plusieurs fois
    for (int i = 0; i < NUM_LEDS / 2; i++) {
      // déplacement des leds
      FastLED.clear();
      for (int j = 0; j < nleds; j++) {
        byte pos1 = (offset + i + j) % (NUM_LEDS / 2);
        byte pos2 = (offset + NUM_LEDS / 2 - i - j) % (NUM_LEDS / 2);
        leds[pos1] = color;
        leds[pos2] = color;
        byte pos3 = NUM_LEDS - pos1;
        if (pos3 == NUM_LEDS) pos3 = NUM_LEDS / 2;
        byte pos4 = NUM_LEDS - pos2;
        if (pos4 == NUM_LEDS) pos4 = NUM_LEDS / 2;
        leds[pos3] = color;
        leds[pos4] = color;
      }
      FastLED.show();
      delay(50);
    }
  }
  FastLED.clear();
}

void anim5 (CRGB color) {
  // Deux vagues qui se remplissent sur chaque oeil
  if (random(2)) FastLED.clear();
  byte offset = random(NUM_LEDS / 2);
  for (int i = 0; i < NUM_LEDS / 2; i++) {
    byte pos1 = (offset + i) % (NUM_LEDS / 2);
    byte pos2 = (offset + NUM_LEDS / 2 - i) % (NUM_LEDS / 2);
    leds[pos1] = color;
    leds[pos2] = color;
    byte pos3 = NUM_LEDS - pos1;
    if (pos3 == NUM_LEDS) pos3 = NUM_LEDS / 2;
    byte pos4 = NUM_LEDS - pos2;
    if (pos4 == NUM_LEDS) pos4 = NUM_LEDS / 2;
    leds[pos3] = color;
    leds[pos4] = color;
    FastLED.show();
    delay(50);
  }
}

void anim6 (CRGB color) {
  // Remplissage ordre aléatoire
  if (random(2)) FastLED.clear();
  byte index[NUM_LEDS];
  for (int i = 0; i < NUM_LEDS; i++) index[i] = i;
  for (int i = 0; i < NUM_LEDS * 5; i++) { // Mélange
    byte i1 = random(NUM_LEDS);
    byte i2 = random(NUM_LEDS);
    byte a = index[i1];
    index[i1] = index[i2];
    index[i2] = a;
  }
  for (int i = 0; i < NUM_LEDS; i++) { // Allumage
    leds[index[i]] = color;
    FastLED.show();
    delay(30);
  }
}

void anim7 (CRGB color) {
  // Clignotement un oeil puis l'autre
  byte cligno = 2 + random(3);
  for (int k = 0; k < cligno; k++) {
    // animation jouée plusieurs fois
    FastLED.clear();
    color = couleur[random(N_COUL)];
    for (int i = 0; i < NUM_LEDS / 2; i++) leds[i] = color;
    FastLED.show();
    delay(300);
    FastLED.clear();
    color = couleur[random(N_COUL)];
    for (int i = NUM_LEDS / 2; i < NUM_LEDS; i++) leds[i] = color;
    FastLED.show();
    delay(300);
  }
}

void anim8 (CRGB color) {
  // Remplissage ordre et couleur aléatoires
  if (random(2)) FastLED.clear();
  byte index[NUM_LEDS];
  for (int i = 0; i < NUM_LEDS; i++) index[i] = i;
  for (int i = 0; i < NUM_LEDS * 5; i++) { // Mélange
    byte i1 = random(NUM_LEDS);
    byte i2 = random(NUM_LEDS);
    byte a = index[i1];
    index[i1] = index[i2];
    index[i2] = a;
  }
  for (int i = 0; i < NUM_LEDS; i++) { // Allumage
    leds[index[i]] = couleur[random(N_COUL)];
    FastLED.show();
    delay(30);
  }
}

void anim9 (CRGB color) {
  // Une vague qui se remplit sur chaque oeil (et se vide si hasard)
  byte offset = random(NUM_LEDS / 2);
  if (random(2)) FastLED.clear();
  for (int i = 0; i < NUM_LEDS / 2; i++) { // Allume une par une
    byte pos1 = (offset + i) % (NUM_LEDS / 2);
    byte pos2 = NUM_LEDS - pos1;
    if (pos2 == NUM_LEDS) pos2 = NUM_LEDS / 2;
    leds[pos1] = color;
    leds[pos2] = color;
    FastLED.show();
    delay(40);
  }
  if (random(2)) { // On éteint les leds une par une
    for (int i = NUM_LEDS / 2 - 1; i >= 0 ; i--) {
      byte pos1 = (offset + i) % (NUM_LEDS / 2);
      byte pos2 = NUM_LEDS - pos1;
      if (pos2 == NUM_LEDS) pos2 = NUM_LEDS / 2;
      leds[pos1] = 0;
      leds[pos2] = 0;
      FastLED.show();
      delay(40);
    }
  }
}

void anim10 (CRGB color) {
  // Animation arc en ciel
  for (int i = 0; i < 255; i = i + 10) {
    fill_rainbow(leds, NUM_LEDS, i, 7);
    FastLED.show();
    delay(40);
  }
}

void anim11 (CRGB color) {
  // Remplit un oeil, le vide et remplit l'autre, vide l'autre
  FastLED.clear();
  for (int i = 0; i < NUM_LEDS / 2; i++) {
    leds[i] = color;
    FastLED.show();
    delay(30);
  }
  for (int i = 0; i < NUM_LEDS / 2; i++) {
    leds[i] = 0;
    leds[i + NUM_LEDS / 2] = color;
    FastLED.show();
    delay(30);
  }
  for (int i = 0; i < NUM_LEDS / 2; i++) {
    leds[i + NUM_LEDS / 2] = 0;
    FastLED.show();
    delay(30);
  }
}


#define N_ANIM 11
void (*animation[])(CRGB couleur) = {anim1, anim2, anim3, anim4, anim5,
                                     anim6, anim7, anim8, anim9, anim10,
                                     anim11
                                    };

void setup() {
  //  delay(1000);
  FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS);
  FastLED.setCorrection(TypicalLEDStrip);
  FastLED.setBrightness(BRIGHTNESS);
  FastLED.clear();
  pinMode(LED_PIN, OUTPUT);
  //  Serial.begin(115200);
}

void loop() {
  int numAnim = random(N_ANIM);
  int numCoul = random(N_COUL);
  digitalWrite(LED_PIN, HIGH); // Eteint la LED bleue
  animation[numAnim](couleur[numCoul]);
  digitalWrite(LED_PIN, LOW);  // Allume la LED bleue 20 ms
  delay(20);
}

