// Source: https://github.com/FastLED/FastLED/blob/master/examples/ColorPalette/ColorPalette.ino

#include <FastLED.h>

#define LED_PIN     3
#define NUM_LEDS    12  // 2 rings (Dout ring 1 to Din ring 2) = total leds
#define BRIGHTNESS  255
#define LED_TYPE    WS2813
#define COLOR_ORDER GRB
CRGB leds[NUM_LEDS];

static int UPDATES_PER_SECOND = 60;
static int SPEED_RING = 0;

// delai entre deux lectures pin (A0 et A1)
int msIntervalRead = 250; // ms

// This example shows several ways to set up and use 'palettes' of colors
// with FastLED.
//
// These compact palettes provide an easy way to re-colorize your
// animation on the fly, quickly, easily, and with low overhead.
//
// USING palettes is MUCH simpler in practice than in theory, so first just
// run this sketch, and watch the pretty lights as you then read through
// the code.  Although this sketch has eight (or more) different color schemes,
// the entire sketch compiles down to about 6.5K on AVR.
//
// FastLED provides a few pre-configured color palettes, and makes it
// extremely easy to make up your own color schemes with palettes.
//
// Some notes on the more abstract 'theory and practice' of
// FastLED compact palettes are at the bottom of this file.



CRGBPalette16 currentPalette;
TBlendType    currentBlending;

extern CRGBPalette16 myRedWhiteBluePalette;
extern const TProgmemPalette16 myRedWhiteBluePalette_p PROGMEM;

void setup()
{
  pinMode( A2, INPUT_PULLUP );
  pinMode( A3, INPUT_PULLUP );
  pinMode( 4, INPUT_PULLUP );
  pinMode( 5, INPUT_PULLUP );

  FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
  FastLED.setBrightness(  BRIGHTNESS );
  FastLED.show();

  currentPalette = RainbowColors_p;
  currentBlending = LINEARBLEND;
  Serial.begin(115200);
  //infos();
}


void infos()
{
  Serial.print( "infos: " );
  Serial.print( FastLED.getBrightness() );
  Serial.print( " " );
  Serial.println( FastLED.getFPS() );
}


int decalageZero = 0;

void loop()
{
  EVERY_N_MILLISECONDS( msIntervalRead )
  {
    FastLED.setBrightness( readBright() );
    UPDATES_PER_SECOND = readSpeed();

    
  }
  //Serial.print( " " );
  //Serial.println( FastLED.getFPS() );
  
  if( readStop() == 0 ) feuxStop();
  if( readDir() == 0 ) feuxCli();
  if( readA() == 0 ) feuxRecule();
  if( readB() == 0 ) feuxPluie();
  
  //ChangePalettePeriodically();

  //myProccess();
  //myProccess_2();
  //myProccess_3(); // base effets.
  
  // tests rotation eyes ok
  //myProccess_4();

  // test
  //myProccess_5();
}

bool readStop()
{
  return digitalRead( A2 );
}

bool readDir()
{
  return digitalRead( A3 );
}

bool readA()
{
  return digitalRead( 4 );
}

bool readB()
{
  return digitalRead( 5 );
}

void feuxStop()
{
  stroboFlash( 2, CRGB::Red );
}

void feuxCli()
{
  stroboFlash( 2, CRGB::Orange );
}

void feuxRecule()
{
  stroboFlash( 2, CRGB::LightSlateGray );
}

void feuxPluie()
{
  stroboFlash( 4, CRGB::AliceBlue );
}

void myProccess()
{
  static uint8_t startIndex = 0;  // compteur.
  
  //
  //SPEED_RING = readSpeed();
  //FastLED.setBrightness( readBright() );
  
  if( startIndex < 1 ) leds[ decalageZero ] = CRGB(0, 255, 0);
  else leds[ startIndex ] = CRGB(255, 140, 0);

  //Serial.println( startIndex );
  
  if( startIndex > NUM_LEDS )
  {
    fill_solid( leds, NUM_LEDS, CRGB::Black );
    startIndex = 0;
  }
  else startIndex += 1; /* motion speed */

  FastLED.show();

  FastLED.delay(1000 / UPDATES_PER_SECOND);
}

void myProccess_2()
{
  int j = 0;
  for( int i = 0; i < NUM_LEDS; i++ )
  {
    leds[ i ] = CRGB(255, 0, 0);

    j = i + ( NUM_LEDS / 2 );
    leds[ j ] = CRGB(255, 0, 0);
    FastLED.show();
    delay( 1000 / UPDATES_PER_SECOND );
    
  }
  
}

void myProccess_3()
{
  serpentDoubleRainbow();
  
  stroboFlash( 4, CRGB(255, 255, 255) );
  stroboFlash( 5, CRGB(0, 255, 255) );
  stroboFlash( 2, CRGB(255, 0, 255) );
  stroboFlash( 3, CRGB(255, 255, 0) );

  serpentDoubleRainbow();

  stroboFlash( 4, CRGB(155, 255, 10) );
  stroboFlash( 5, CRGB(8, 90, 212) );
  stroboFlash( 2, CRGB(246, 0, 74) );
  stroboFlash( 3, CRGB(205, 150, 250) );
}

void myProccess_4()
{
  // faire boucle
  rotaryEyes( 0 );
  delay( 25 );
  rotaryEyes( 1 );
  delay( 25 );
  rotaryEyes( 1 );
  delay( 25 );
  rotaryEyes( 0 );
}

void myProccess_5()
{
  // clignotant detresse
  CRGB c1 = CRGB(243, 131, 3);
  CRGB c2 = CRGB(250, 244, 235);

  int n = 13;
  detresse( n, c1, c2 );
}

void detresse( int n, CRGB c1, CRGB c2 )
{
  CRGB color;
  int nbr = n;
  int tmp = 0;
  
  // boucle 2 couleurs fixes en groupe alternees.
  for( int i = 0; i < NUM_LEDS; i += nbr )
  {
    if( tmp == 0 ) color = c1;
    else color = c2;
    
    for( int j = 0; j < nbr; j++ )
    {
      if( i + j < NUM_LEDS ) leds[ i + j ] = color;
    }
    if( tmp == 0 ) tmp = 1;
    else tmp = 0;

    FastLED.show();
    FastLED.delay( 50 );
  }

  for( int i = 0; i < NUM_LEDS; i += nbr )
  {
    if( tmp == 1 ) color = c2;
    else color = c1;
    
    for( int j = 0; j < nbr; j++ )
    {
      if( i + j < NUM_LEDS ) leds[ i + j ] = color;
    }
    if( tmp == 1 ) tmp = 0;
    else tmp = 1;

    FastLED.show();
    FastLED.delay( 50 );
  }
}

void fadeAll()
{
  for( int i = 0; i < NUM_LEDS; i++ )
  {
    leds[ i ].nscale8( 250 );
  }
}

void serpentDoubleRainbow()
{
  static uint8_t hue;
  static int t;
  // 
  for( int i = 0; i < NUM_LEDS; i++ )
  {
    //
    leds[ i ] = CHSV( hue++, 255, 255 - (i*2) );
    leds[ NUM_LEDS - (i + 1) ] = CHSV( hue += 4, 255, 255 - (i*2) );
    FastLED.show();
    delay( 1000 / UPDATES_PER_SECOND );

    if( t == 10 )
    {
      leds[ i - t ] = CRGB::Black;
      leds[ NUM_LEDS - (i + t + 1) ] = CRGB::Black;
      FastLED.show();
      delay( 1000 / UPDATES_PER_SECOND );
    }
    t++;
  }
}

void stroboFlash( int t, CRGB color )
{
  for( int i = t - 1; i >= 0; i-- )
  {
    fill_solid( leds, NUM_LEDS, color );
    FastLED.delay( 1000 / UPDATES_PER_SECOND );
    fill_solid( leds, NUM_LEDS, CRGB::Black );
    FastLED.delay( 1000 / UPDATES_PER_SECOND );
  }
}

void flash()
{
  FastLED.clear();

  for( int i = 0; i < 5; i++ )
  {
    FastLED.setBrightness( 255 );
    fill_solid( leds, NUM_LEDS, CRGB::Gray );
    delay( 25 );
    fill_solid( leds, NUM_LEDS, CRGB::Black );
    delay( 25 );
  }
  // retour base.
  FastLED.setBrightness( BRIGHTNESS );
}

void rotaryEyes( int d )
{
  int dir = d;  // 0 or 1 (CCW or CW).
  int tempo = 1;

  if( dir == 1 )
  {
    // nombre total de leds / 2
    for( int i = 0; i < ( NUM_LEDS / 2 ); i++ )
    {
      // allume les opposees ON
      leds[ i ] = CRGB::Aqua;
      leds[ i + ( NUM_LEDS / 2 ) ] = CRGB(255, 230, 0);
      FastLED.show();
      if( tempo != 0 ) FastLED.delay( 1000 / UPDATES_PER_SECOND );
      // eteint les opposees OFF
      leds[ i ] = CRGB::Black;
      leds[ i + ( NUM_LEDS / 2 ) ] = CRGB::Black;
      FastLED.show();
      if( tempo != 0 ) FastLED.delay( 1000 / UPDATES_PER_SECOND );
    }
  }
  else
  {
    for( int i = ( NUM_LEDS / 2 ); i >= 0; i-- )
    {
      // allume les opposees ON
      leds[ i + ( NUM_LEDS / 2 ) ] = CRGB(0, 255, 72);
      leds[ i ] = CRGB(255, 145, 0);
      FastLED.show();
      if( tempo != 0 ) FastLED.delay( 1000 / UPDATES_PER_SECOND );
      // eteint les opposees OFF
      leds[ i + ( NUM_LEDS / 2 ) ] = CRGB::Black;
      leds[ i ] = CRGB::Black;
      FastLED.show();
      if( tempo != 0 ) FastLED.delay( 1000 / UPDATES_PER_SECOND );
    }
  }
}

// lecture sur pin A0 ( luminescence )
int readBright()
{
  int bright = map( analogRead( A0 ), 0, 1023, 0, 255 );
  //Serial.print( "bright: " );
  //Serial.println( bright );
  return bright;
}

// lecture sur pin A1 ( frequence, vitesse )
int readSpeed()
{
  int freq = map( analogRead( A1 ), 0, 1023, 5, 1500 );
  //Serial.print( "speed: " );
  //Serial.println( freq );
  return freq;
}

void FillLEDsFromPaletteColors( uint8_t colorIndex)
{
  uint8_t brightness = 255;

  for ( int i = 0; i < NUM_LEDS; i++) {
    leds[i] = ColorFromPalette( currentPalette, colorIndex, brightness, currentBlending);
    colorIndex += 3;
  }
}


// There are several different palettes of colors demonstrated here.
//
// FastLED provides several 'preset' palettes: RainbowColors_p, RainbowStripeColors_p,
// OceanColors_p, CloudColors_p, LavaColors_p, ForestColors_p, and PartyColors_p.
//
// Additionally, you can manually define your own color palettes, or you can write
// code that creates color palettes on the fly.  All are shown here.

void ChangePalettePeriodically()
{
  uint8_t secondHand = (millis() / 1000) % 60;
  static uint8_t lastSecond = 99;

  if ( lastSecond != secondHand) {
    lastSecond = secondHand;
    if ( secondHand ==  0)  {
      currentPalette = RainbowColors_p;
      currentBlending = LINEARBLEND;
    }
    if ( secondHand == 10)  {
      currentPalette = RainbowStripeColors_p;
      currentBlending = NOBLEND;
    }
    if ( secondHand == 15)  {
      currentPalette = RainbowStripeColors_p;
      currentBlending = LINEARBLEND;
    }
    if ( secondHand == 20)  {
      SetupPurpleAndGreenPalette();
      currentBlending = LINEARBLEND;
    }
    if ( secondHand == 25)  {
      SetupTotallyRandomPalette();
      currentBlending = LINEARBLEND;
    }
    if ( secondHand == 30)  {
      SetupBlackAndWhiteStripedPalette();
      currentBlending = NOBLEND;
    }
    if ( secondHand == 35)  {
      SetupBlackAndWhiteStripedPalette();
      currentBlending = LINEARBLEND;
    }
    if ( secondHand == 40)  {
      currentPalette = CloudColors_p;
      currentBlending = LINEARBLEND;
    }
    if ( secondHand == 45)  {
      currentPalette = PartyColors_p;
      currentBlending = LINEARBLEND;
    }
    if ( secondHand == 50)  {
      currentPalette = myRedWhiteBluePalette_p;
      currentBlending = NOBLEND;
    }
    if ( secondHand == 55)  {
      currentPalette = myRedWhiteBluePalette_p;
      currentBlending = LINEARBLEND;
    }
  }
}

// This function fills the palette with totally random colors.
void SetupTotallyRandomPalette()
{
  for ( int i = 0; i < 16; i++) {
    currentPalette[i] = CHSV( random8(), 255, random8());
  }
}

// This function sets up a palette of black and white stripes,
// using code.  Since the palette is effectively an array of
// sixteen CRGB colors, the various fill_* functions can be used
// to set them up.
void SetupBlackAndWhiteStripedPalette()
{
  // 'black out' all 16 palette entries...
  fill_solid( currentPalette, 16, CRGB::Black);
  // and set every fourth one to white.
  currentPalette[0] = CRGB::White;
  currentPalette[4] = CRGB::White;
  currentPalette[8] = CRGB::White;
  currentPalette[12] = CRGB::White;

}

// This function sets up a palette of purple and green stripes.
void SetupPurpleAndGreenPalette()
{
  CRGB purple = CHSV( HUE_PURPLE, 255, 255);
  CRGB green  = CHSV( HUE_GREEN, 255, 255);
  CRGB black  = CRGB::Black;

  currentPalette = CRGBPalette16(
                     green,  green,  black,  black,
                     purple, purple, black,  black,
                     green,  green,  black,  black,
                     purple, purple, black,  black );
}


// This example shows how to set up a static color palette
// which is stored in PROGMEM (flash), which is almost always more
// plentiful than RAM.  A static PROGMEM palette like this
// takes up 64 bytes of flash.
const TProgmemPalette16 myRedWhiteBluePalette_p PROGMEM =
{
  CRGB::Red,
  CRGB::Gray, // 'white' is too bright compared to red and blue
  CRGB::Blue,
  CRGB::Black,

  CRGB::Red,
  CRGB::Gray,
  CRGB::Blue,
  CRGB::Black,

  CRGB::Red,
  CRGB::Red,
  CRGB::Gray,
  CRGB::Gray,
  CRGB::Blue,
  CRGB::Blue,
  CRGB::Black,
  CRGB::Black
};



// Additional notes on FastLED compact palettes:
//
// Normally, in computer graphics, the palette (or "color lookup table")
// has 256 entries, each containing a specific 24-bit RGB color.  You can then
// index into the color palette using a simple 8-bit (one byte) value.
// A 256-entry color palette takes up 768 bytes of RAM, which on Arduino
// is quite possibly "too many" bytes.
//
// FastLED does offer traditional 256-element palettes, for setups that
// can afford the 768-byte cost in RAM.
//
// However, FastLED also offers a compact alternative.  FastLED offers
// palettes that store 16 distinct entries, but can be accessed AS IF
// they actually have 256 entries; this is accomplished by interpolating
// between the 16 explicit entries to create fifteen intermediate palette
// entries between each pair.
//
// So for example, if you set the first two explicit entries of a compact
// palette to Green (0,255,0) and Blue (0,0,255), and then retrieved
// the first sixteen entries from the virtual palette (of 256), you'd get
// Green, followed by a smooth gradient from green-to-blue, and then Blue.
nano:12
nano:11
nano:10
nano:9
nano:8
nano:7
nano:6
nano:5
nano:4
nano:3
nano:2
nano:GND.2
nano:RESET.2
nano:0
nano:1
nano:13
nano:3.3V
nano:AREF
nano:A0
nano:A1
nano:A2
nano:A3
nano:A4
nano:A5
nano:A6
nano:A7
nano:5V
nano:RESET
nano:GND.1
nano:VIN
nano:12.2
nano:5V.2
nano:13.2
nano:11.2
nano:RESET.3
nano:GND.3
ring1:GND
ring1:VCC
ring1:DIN
ring1:DOUT
ring2:GND
ring2:VCC
ring2:DIN
ring2:DOUT
pot1:GND
pot1:SIG
pot1:VCC
pot2:GND
pot2:SIG
pot2:VCC
btn1:1.l
btn1:2.l
btn1:1.r
btn1:2.r
btn2:1.l
btn2:2.l
btn2:1.r
btn2:2.r
btn3:1.l
btn3:2.l
btn3:1.r
btn3:2.r
btn4:1.l
btn4:2.l
btn4:1.r
btn4:2.r
btn5:1.l
btn5:2.l
btn5:1.r
btn5:2.r