//bring up libraries
#include <FastLED.h>
#include <OneButton.h>

// set number of strips, leds per strip, total leds, and brightness
#define NUM_STRIPS 3
#define NUM_LEDS_A    33
#define NUM_LEDS_B    15
#define NUM_LEDS_C    12
#define NUM_LEDS ((NUM_LEDS_A)+(NUM_LEDS_B)+(NUM_LEDS_C))
#define BRIGHTNESS  50

// set parameters for patterns later
int fadeAmount = 1;
int brightness = 0;

uint8_t colorIndex[NUM_LEDS];

// create integer for pattern counter, keeps track of which pattern showing
uint8_t patternCounter = 0;

DEFINE_GRADIENT_PALETTE( greentwinkle_gp )
{
  0, 0, 0, 0,
  64, 21, 249, 7,
  128, 80, 255, 67,
  197, 21, 249, 7,
  255, 0, 0, 0
};
//Activate the palette
CRGBPalette16 greentwinkle = greentwinkle_gp;

// set button to data pin 10
#define BTN_PIN     10

// create an array of all the leds
CRGB leds[NUM_LEDS];

// push button connected to pin 12 and GND with internal pull-up, so LOW is "on"
OneButton btn = OneButton(BTN_PIN, true, true);

void setup() {

  // tell FastLED there's 33 NEOPIXEL leds on pin 6, starting at index 0 in the led array
  FastLED.addLeds<NEOPIXEL, 6>(leds, 0, NUM_LEDS_A);

  // tell FastLED there's 15 NEOPIXEL leds on pin 7, starting at index 33 in the led array
  FastLED.addLeds<NEOPIXEL, 7>(leds, NUM_LEDS_A, NUM_LEDS_B);

  // tell FastLED there's 12 NEOPIXEL leds on pin 8, starting at index 48 in the led array
  FastLED.addLeds<NEOPIXEL, 8>(leds, NUM_LEDS_A + NUM_LEDS_B, NUM_LEDS_C);

  // set brightness level
  FastLED.setBrightness(BRIGHTNESS);

  // clear the LEDS
  FastLED.clear();

  // call next pattern when button is clicked
  btn.attachClick(nextPattern);

}

void loop()
{
  switch (patternCounter) {
    case 0:
      SteadyOn();   // all leds steady green
      break;
    case 1:
      ThreeSteadyOn();  // segments of 3 leds steady green
      break;
    case 2:
      ChaseNonBlocking(250, 3, 3);     // chase 3 on + 3 off pixels every 250ms
      break;
    case 3:
      ChaseNonBlocking(100, 5, 4);     // chase 5 on + 4 off pixels every 100ms
      break;
    case 4:
      Glow();       // glow green
      break;
    case 5:
      Twinkle();    // twinkle green
      break;
    case 6:
      Blackout();   // all leds off
      break;
  }


  FastLED.show();
  btn.tick();       // checks the button each loop, MUST HAVE

}

void nextPattern() {
  patternCounter = (patternCounter + 1) % 7;    // Advance the pattern; Change number after % to number of patterns
}

void SteadyOn() {
  for (int i = 0; i < NUM_LEDS; i++ )
  {
    leds[i].setRGB(0, 255, 0); // Set Color here
  }
}

void ThreeSteadyOn() {
  FastLED.clear();
  leds[44] = CRGB::Green;
  leds[43] = CRGB::Green;
  leds[42] = CRGB::Green;
  leds[38] = CRGB::Green;
  leds[37] = CRGB::Green;
  leds[36] = CRGB::Green;
  leds[32] = CRGB::Green;
  leds[31] = CRGB::Green;
  leds[30] = CRGB::Green;
  leds[26] = CRGB::Green;
  leds[25] = CRGB::Green;
  leds[24] = CRGB::Green;
  leds[20] = CRGB::Green;
  leds[19] = CRGB::Green;
  leds[18] = CRGB::Green;
  leds[14] = CRGB::Green;
  leds[13] = CRGB::Green;
  leds[12] = CRGB::Green;
  leds[8] = CRGB::Green;
  leds[7] = CRGB::Green;
  leds[6] = CRGB::Green;
  leds[2] = CRGB::Green;
  leds[1] = CRGB::Green;
  leds[0] = CRGB::Green;
}

void ChaseNonBlocking(uint16_t delay, uint8_t on_count, uint8_t off_count) {
  static uint16_t base_position = 0;
  static uint32_t last_change = 0;
  if (millis() - last_change >= delay) {
    last_change = millis();
    base_position = (base_position + 1) % NUM_LEDS;
  }

  uint16_t this_pos = base_position;
  uint16_t total_count = on_count + off_count;
  for (uint16_t ledno = 0; ledno < NUM_LEDS; ledno++) {
    if (this_pos % total_count < on_count)
      leds[ledno] = CRGB::Green;
    else
      leds[ledno] = CRGB::Black;
    this_pos++;
  }
}

void Glow() {
  EVERY_N_MILLISECONDS(9) {
    for (int i = 0; i < NUM_LEDS; i++ )
    {
      leds[i].setRGB(0, 255, 0); // Set Color HERE!!!
      leds[i].fadeLightBy(brightness);
    }
    brightness = brightness + fadeAmount;
    // reverse the direction of the fading at the ends of the fade:
    if (brightness == 0 || brightness == 255)
    {
      fadeAmount = -fadeAmount ;
    }
  }
  // delay(9);  // This delay sets speed of the fade. I usually do from 5-75 but you can always go higher.
}

void Twinkle() {
  static bool setup = true;
  if (setup) {
    setup = false;
    //Fill the colorIndex array with random numbers
    for (int i = 0; i < NUM_LEDS; i++) {
      colorIndex[i] = random8();
    }
  }
  //color each pixel from the palette using the index from colorIndex
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = ColorFromPalette(greentwinkle, colorIndex[i]);
  }

  EVERY_N_MILLISECONDS(2) {
    //switch on an led at random, choosing a random color from the palette
    //leds[random8(0, NUM_LEDS - 1)] = ColorFromPalette(greentwinkle, random8(), 255, LINEARBLEND);
    for (int i = 0; i < NUM_LEDS; i++) {
      colorIndex[i]++;
    }
  }

  //fade all LEDS down by 1 in brightness each time this is called
  fadeToBlackBy(leds, NUM_LEDS, 10);
}

void Blackout() {
  fill_solid( leds, NUM_LEDS, CRGB(0, 0, 0));
}