//
//  Code based on FASTLED "Pacifica"
//  Gentle, blue-green ocean waves.
//

#define FASTLED_ALLOW_INTERRUPTS 0
#include <FastLED.h>
FASTLED_USING_NAMESPACE

#define MODE_PROTOLIGHTBOX 2
#define DATA_PIN 3
#define NUM_LEDS 25
#define NUM_LEDS_B 18
#define MAX_POWER_MILLIAMPS 1000
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB

//////////////////////////////////////////////////////////////////////////

CRGB leds[NUM_LEDS];

void setup()
{
  delay(3000); // 3 second delay for boot recovery, and a moment of silence
  FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS)
      .setCorrection(TypicalLEDStrip);
  FastLED.setMaxPowerInVoltsAndMilliamps(5, MAX_POWER_MILLIAMPS);

  fill_solid(&(leds[18]), 5, CRGB::Red);

  //Serial.begin(9600);
}

void loop()
{
  EVERY_N_MILLISECONDS(20)
  {
    pacifica_loop();

    singles_loop();

    FastLED.show();
  }
}

void singles_loop()
{
  static unsigned long lastTime;
  static unsigned long lastTime2;
  unsigned long currentTime;
  currentTime = millis();

  //Serial.print("Time: ");
  //Serial.println(currentTime); //prints time since program started

  unsigned long deltaTime = currentTime - lastTime;
  unsigned long deltaTime2 = currentTime - lastTime2;

  static short MODE = 1;
  static int B = 0; //Brigthness
  static bool SOLO[5] = {1, 0, 1, 0, 0};
  if (deltaTime > 1000)
  {
    lastTime = currentTime;
    //Serial.print("   1sec    ");
    int c = CRGB::Green;
  }
  for (int k = 0; k < 5; k++)
  {
    int i = k + 18;
    if (SOLO[k])
    {
      switch(MODE_PROTOLIGHTBOX)
      {
        case 1:
          leds[i] = CHSV(CRGB::GreenYellow, 255, B);
        break;
        case 2:
          leds[i] = CHSV(CRGB::BlanchedAlmond, 255, B);
        break;
        case 3:
          leds[i] = CHSV(CRGB::YellowGreen, 255, B);
        break;
      }
    }
    //leds[i] = HSV(leds[i].color, leds[i].saturation, 127);
  }
  if (MODE)
  {
    if ((B += 2) > 255)
    {
      B = 255;
      MODE = 0;
    }
  }
  else //!MODE
  {
    if ((B -= 6) < 30)
    {
      B = 30;
      MODE = 1;
      //Serial.print("   GEN---    ");
      for (int k = 0; k < 5; k++)
      {
        leds[k + 18] = 0;
        SOLO[k] = random(2) - 1;
        //Serial.print(SOLO[k]);
      }
    }
  }

  //Serial.print("   Brightness");
  //Serial.print(B);

  if (deltaTime2 > 5000)
  {
    //Serial.print("   5sec    ");
    lastTime2 = currentTime;
  }
}

//////////////////////////////////////////////////////////////////////////
//
// The code for this animation is more complicated than other examples, and
// while it is "ready to run", and documented in general, it is probably not
// the best starting point for learning.  Nevertheless, it does illustrate some
// useful techniques.
//
//////////////////////////////////////////////////////////////////////////
//
// In this animation, there are four "layers" of waves of light.
//
// Each layer moves independently, and each is scaled separately.
//
// All four wave layers are added together on top of each other, and then
// another filter is applied that adds "whitecaps" of brightness where the
// waves line up with each other more.  Finally, another pass is taken
// over the led array to 'deepen' (dim) the blues and greens.
//
// The speed and scale and motion each layer varies slowly within independent
// hand-chosen ranges, which is why the code has a lot of low-speed 'beatsin8' functions
// with a lot of oddly specific numeric ranges.
//
// These three custom blue-green color palettes were inspired by the colors found in
// the waters off the southern coast of California, https://goo.gl/maps/QQgd97jjHesHZVxQ7
//
CRGBPalette16 pacifica_palette_1 =
    {0x000507, 0x000409, 0x00030B, 0x00030D, 0x000210, 0x000212, 0x000114, 0x000117,
     0x000019, 0x00001C, 0x000026, 0x000031, 0x00003B, 0x000046, 0x14554B, 0x28AA50};
CRGBPalette16 pacifica_palette_2 =
    {0x000507, 0x000409, 0x00030B, 0x00030D, 0x000210, 0x000212, 0x000114, 0x000117,
     0x000019, 0x00001C, 0x000026, 0x000031, 0x00003B, 0x000046, 0x0C5F52, 0x19BE5F};
CRGBPalette16 pacifica_palette_3 =
    {0x000208, 0x00030E, 0x000514, 0x00061A, 0x000820, 0x000927, 0x000B2D, 0x000C33,
     0x000E39, 0x001040, 0x001450, 0x001860, 0x001C70, 0x002080, 0x1040BF, 0x2060FF};

void pacifica_loop()
{
  // Increment the four "color index start" counters, one for each wave layer.
  // Each is incremented at a different speed, and the speeds vary over time.
  static uint16_t sCIStart1, sCIStart2, sCIStart3, sCIStart4;
  static uint16_t sCIStart1_B, sCIStart2_B, sCIStart3_B, sCIStart4_B;
  static uint32_t sLastms = 0;
  uint32_t ms = GET_MILLIS();
  uint32_t deltams = ms - sLastms;
  sLastms = ms;
   uint16_t speedfactor1, speedfactor2, speedfactor1_B, speedfactor2_B;
  if(MODE_PROTOLIGHTBOX == 1 )
  {
  speedfactor1 = beatsin16(3, 179, 269) << 2;
  speedfactor2 = beatsin16(4, 179, 269) << 2;
  }  
  if(MODE_PROTOLIGHTBOX == 2 || MODE_PROTOLIGHTBOX == 3)
  {
  speedfactor1 = beatsin16(3, 179, 269) << 1;
  speedfactor2 = beatsin16(4, 179, 269) << 1;
  }
  if(MODE_PROTOLIGHTBOX == 1|| MODE_PROTOLIGHTBOX == 2)
  {
  speedfactor1_B = beatsin16(0, 179, 269) >> 2;
  speedfactor2_B = beatsin16(0, 179, 269) >> 2;
  }
  if(MODE_PROTOLIGHTBOX == 3)
  {
  speedfactor1_B = beatsin16(0, 179, 269) >> 10;
  speedfactor2_B = beatsin16(0, 179, 269) >> 10;
  }
  
  uint32_t deltams1 = (deltams * speedfactor1) / 256;
  uint32_t deltams2 = (deltams * speedfactor2) / 256;
  uint32_t deltams21 = (deltams1 + deltams2) / 2;
  uint32_t deltams1_B = (deltams * speedfactor1_B) / 256;
  uint32_t deltams2_B = (deltams * speedfactor2_B) / 256;
  uint32_t deltams21_B = (deltams1_B + deltams2_B) / 2;
  sCIStart1 += (deltams1 * beatsin88(1011, 10, 13));
  sCIStart2 -= (deltams21 * beatsin88(777, 8, 11));
  sCIStart3 -= (deltams1 * beatsin88(501, 5, 7));
  sCIStart4 -= (deltams2 * beatsin88(257, 4, 6));
  sCIStart1_B += (deltams1_B * beatsin88(1011, 10, 13));
  sCIStart2_B -= (deltams21_B * beatsin88(777, 8, 11));
  sCIStart3_B -= (deltams1_B * beatsin88(501, 5, 7));
  sCIStart4_B -= (deltams2_B * beatsin88(257, 4, 6));

  // Clear out the LED array to a dim background blue-green
  fill_solid(leds, NUM_LEDS_B, CRGB(2, 6, 10));

  // Render each of four layers, with different scales and speeds, that vary over time
  //Bottom row  - slow speed
  pacifica_one_layer(0, pacifica_palette_1, sCIStart1_B, beatsin16(3, 11 * 256, 14 * 256), beatsin8(10, 70, 130), 0 - beat16(301));
  pacifica_one_layer(0, pacifica_palette_2, sCIStart2_B, beatsin16(4, 6 * 256, 9 * 256), beatsin8(17, 40, 80), beat16(401));
  pacifica_one_layer(0, pacifica_palette_3, sCIStart3_B, 6 * 256, beatsin8(9, 10, 38), 0 - beat16(503));
  pacifica_one_layer(0, pacifica_palette_3, sCIStart4_B, 5 * 256, beatsin8(8, 10, 28), beat16(601));
  //Top row - Normal speed
  pacifica_one_layer(1, pacifica_palette_1, sCIStart1, beatsin16(3, 11 * 256, 14 * 256), beatsin8(10, 70, 130), 0 - beat16(301));
  pacifica_one_layer(1, pacifica_palette_2, sCIStart2, beatsin16(4, 6 * 256, 9 * 256), beatsin8(17, 40, 80), beat16(401));
  pacifica_one_layer(1, pacifica_palette_3, sCIStart3, 6 * 256, beatsin8(9, 10, 38), 0 - beat16(503));
  pacifica_one_layer(1, pacifica_palette_3, sCIStart4, 5 * 256, beatsin8(8, 10, 28), beat16(601));

  // Add brighter 'whitecaps' where the waves lines up more
  pacifica_add_whitecaps();

  // Deepen the blues and greens a bit
  pacifica_deepen_colors();
}

// Add one layer of waves into the led array
void pacifica_one_layer(bool ROW, CRGBPalette16 &p, uint16_t cistart, uint16_t wavescale, uint8_t bri, uint16_t ioff)
{
  uint16_t ci = cistart;
  uint16_t waveangle = ioff;
  uint16_t wavescale_half = (wavescale / 2) + 20;
  for (uint16_t i = 0; i < 9 /*NUM_LEDS*/; i++)
  {
    waveangle += 250;
    uint16_t s16 = sin16(waveangle) + 32768;
    uint16_t cs = scale16(s16, wavescale_half) + wavescale_half;
    ci += cs;
    uint16_t sindex16 = sin16(ci) + 32768;
    uint8_t sindex8 = scale16(sindex16, 240);
    CRGB c = ColorFromPalette(p, sindex8, bri, LINEARBLEND);
    if (ROW) ///Top row
      leds[17 - i] += c;
    else // Bottom row
      leds[i] += c;
  }
}

// Add extra 'white' to areas where the four layers of light have lined up brightly
void pacifica_add_whitecaps()
{
  uint8_t basethreshold = beatsin8(9, 55, 65);
  uint8_t wave = beat8(7);

  for (uint16_t i = 0; i < NUM_LEDS_B; i++)
  {
    uint8_t threshold = scale8(sin8(wave), 20) + basethreshold;
    wave += 7;
    uint8_t l = leds[i].getAverageLight();
    if (l > threshold)
    {
      uint8_t overage = l - threshold;
      uint8_t overage2 = qadd8(overage, overage);
      leds[i] += CRGB(overage, overage2, qadd8(overage2, overage2));
    }
  }
}

// Deepen the blues and greens
void pacifica_deepen_colors()
{
  for (uint16_t i = 0; i < NUM_LEDS_B; i++)
  {
    leds[i].blue = scale8(leds[i].blue, 145);
    leds[i].green = scale8(leds[i].green, 200);
    leds[i] |= CRGB(2, 5, 7);
  }
}