
#include <Adafruit_NeoPixel.h> // Bibliothèque pour les LED
#include <stdlib.h> // Necessaire pour tronquer une string 

// Bibliothèque pour établir la connexion avec la page internet
#include <Bridge.h>
#include <BridgeServer.h>
#include <BridgeClient.h>

BridgeServer server;

#define PIN 6 // Pin ou l'on sort la Data pour les LED
#define nb_led 100 // Nombre de LED que l'on veux allumer dans le ruban ( ici les 100 première led
Adafruit_NeoPixel strip = Adafruit_NeoPixel(nb_led, PIN, NEO_GRB + NEO_KHZ800); // Déclaration de notre ruban de led

void setup() {
  Serial.begin(9600);
  // Bridge startup
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);
  Bridge.begin();
  digitalWrite(13, HIGH);

  strip.begin();
  strip.show(); // Initialize all pixels to 'off'

  // Listen for incoming connection only from localhost
  // (no one from the external network could connect)
  server.listenOnLocalhost();
  server.begin();
}

void loop() {
  // Get clients coming from server
  BridgeClient client = server.accept();

  // Test si il y a un nouveau client
  if (client) {
    // Process request
    process(client);

    // Fermeture de la connexion et libération des ressources
    client.stop();
  }

  delay(50); // Verification toutes les 50 ms
}

// On récupère la requête
void process(BridgeClient client) {
  // lecture de la commande
  String command = client.readStringUntil('=');
  //On vérifie quelle est la commande demandée
  if (command == "color") {
    // On fait appel a notre fonction pour allumer les leds
    ledCommand(client);
  }
}

// On analyse et récupère morceau par morceau la requête
void ledCommand(BridgeClient client) {
  String LED = client.readString();
  // client.println(F("Commande recue : "));
  long anneau = (long)strtol(&LED.substring(0, 1)[0], NULL, 0); // On récupère la valeur de l'anneau 

  // Selon la valeur de l'anneau on lance des fonctions différentes

  // Les 3 première conditions représentent les modes aléatoires
  if (anneau == 6)
    aleatoireCommand1(client);
  else
  {
    if ( anneau == 7)
      aleatoireCommand2(client);
    else
    { if ( anneau == 8)
        arcenciel(client);
      else
      {
        // Dans ce mode on allume les anneaux en fonction de la couleur envoyée dans la requête
        long number = (long) strtol(&LED[2], NULL, 16); // On recupère la couleur sous le format strin (ex : FF00FF) et on la convertie en long
        long LEDr =  number >> 16; // On récupère les 8 premier bits
        long LEDg = number >> 8 & 0xFF; // On récupère les 8 bits suivants
        long LEDb =  number & 0xFF; // On récupère les 8 dernier bits
        
        //client.print(F("Anneau : ")); // Affiche dans le navigateur les valeurs reçues
//        if (anneau == 5)
//        {
//          client.println("tous");
//        }
//        else
//        {
//          client.println(anneau);
//        }
//        client.print(F("LED rouge : "));
//        client.println(LEDr);
//        client.print(F("LED verte : "));
//        client.println(LEDg);
//        client.print(F("LED bleu : "));
//        client.println(LEDb);

        // On allumer les LED en fontion de l'anneau, la led rouge, led bleue et la led verte
        write_leds(anneau, LEDr, LEDg, LEDb);
      }
    }
  }
}

// Premier mode aléatoire ou l'on donne une couleur aléatoire à tout le reuban de led 
void aleatoireCommand1(BridgeClient client)
{
  // client.print(F("Mode aleatoire 1 "));
  ruban_entier(strip.Color(random(0, 255), random(0, 255), random(0, 255))); // couleur aleatoire sur tout le ruban
  
  // D'autres exemples 
    //  colorWipe(strip.Color(255, 0, 0), 50); // Red
  //  colorWipe(strip.Color(0, 255, 0), 50); // Green
  //  colorWipe(strip.Color(0, 0, 255), 50); // Blue
}

// Dexième mode aléatoire ou l'on donne une couleur aléatoire anneau par anneau
void aleatoireCommand2(BridgeClient client)
{
  //client.print(F("Mode aleatoire 2 "));
  ruban_portion(strip.Color(random(0, 255), random(0, 255), random(0, 255)), 1); // Anneau 1
  ruban_portion(strip.Color(random(0, 255), random(0, 255), random(0, 255)), 2); // Anneau 2
  ruban_portion(strip.Color(random(0, 255), random(0, 255), random(0, 255)), 3); // Anneau 3
  ruban_portion(strip.Color(random(0, 255), random(0, 255), random(0, 255)), 4); // Anneau 4
}

// Troisième mode aléatoire : mode arc en ciel qui fait varier la couleur des leds en dynamique
void arcenciel(BridgeClient client)
{
  rainbowCycle(20); // Le changement des leds se fait toutes les 20 ms
}

// On éclaire des leds
void write_leds(uint8_t anneau, long r, long v, long b) {
  ruban_portion(strip.Color(r, v, b), anneau); // La fonciton strip.color permet d'obtenir une couleur compréhensible par le ruban
}

// fontion permetant d'allumer toutes les LED du ruban
void ruban_entier(uint32_t  c)
{
  for (uint16_t i = 0; i < strip.numPixels(); i++)
  {
    strip.setPixelColor(i, c);
    strip.show();
  }
}

// Fontion permettant de configurer le debut et la fin des différent anneaux 
void ruban_portion(uint32_t  c, uint8_t anneau)
{
  uint8_t led_debut;
  uint8_t led_fin;
  if (anneau == 1)
  {
    led_debut = 6;
    led_fin = 25;
  } else {
    if (anneau == 2)
    {
      led_debut = 30;
      led_fin = 50;
    } else {
      if (anneau == 3)
      {
        led_debut = 60;
        led_fin = 80;
      } else {
        if (anneau == 4)
        {
          led_debut = 80;
          led_fin = 102;
        } else {
          if (anneau == 5)
            led_debut = 0;
          led_fin = 105;
        }
      }
    }
  }

  // Une fois la longueur des anneaux définis on éclaire les led
  for (uint8_t i = led_debut; i < led_fin + 1; i++)
  {
    strip.setPixelColor(i, c); // DIs a la led numero i de s'allumer de la couleur c 
    strip.show(); // Necessaire pour afficher la couleur désiré car sinon pas mis a jour
  }
}

// fontion permattant d'afficher le ruban d'une même couleur mais pas en simultané (les leds vont s'allumer une par une toutes les x_secondes
void colorWipe(uint32_t c, uint8_t x_secondes) {
  for (uint16_t i = 0; i < strip.numPixels(); i++) {
    strip.setPixelColor(i, c);
    strip.show();
    delay(x_secondes);
  }
}

// Fontion arc en ciel statique
void rainbow(uint8_t wait) {
  uint16_t i, j;

  for (j = 0; j < 256; j++) {
    for (i = 0; i < strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i + j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

// Fonction arc en ciel dynamique les led changent toutes les  x_secondes
void rainbowCycle(uint8_t x_secondes) {
  uint16_t i, j;

  for (j = 0; j < 256 * 5; j++) { // 5 cycles of all colors on wheel
    for (i = 0; i < strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
    }
    strip.show();
    delay(x_secondes);
  }
}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  if (WheelPos < 85) {
    return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } else if (WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else {
    WheelPos -= 170;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
}
