//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  100

// 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 )
{
  255, 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     2

// 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() {
  Serial.begin( 9600);
  Serial.println( "The sketch has started");

  // 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);

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

  // Check free memory
  Serial.print( "freeMemory() = ");
  Serial.println( freeMemory());
}

void loop()
{
  switch (patternCounter) {
    case 0:
      SteadyOn();   // all leds steady green
      break;
    case 1:
      ThreeSteadyOn();  // segments of 3 leds steady green
      break;
    case 2:
      // Chase3();     // chase 3 pixels at a time
      ChaseNonBlocking(250);     // chase 3 pixels at a time, every 250ms
      break;
    case 3:
      // Chase3Fast(); // chase 3 pixels faster
      ChaseNonBlocking(100);     // chase 3 pixels at a time, every 100ms
      break;
    case 4:
      Glow();       // glow green
      break;
    case 5:
      Pulse();    // 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

  Serial.print( "Button has been pressed. patternCounter = ");
  Serial.println( patternCounter);
}

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

void ThreeSteadyOn() {
  fill_solid( leds, NUM_LEDS, CRGB(0, 0, 0));
  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) {
  static uint16_t base_position = 0;
  static uint32_t last_change = 0;
  if (millis() - last_change < delay)
    return;
  last_change = millis();
  base_position = (base_position + 1) % NUM_LEDS;

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

void Glow() {
  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 Pulse() {
  //Fill the colorIndex array with random numbers
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = ColorFromPalette(greentwinkle, colorIndex[i]);
  }

  EVERY_N_MILLISECONDS(10) {
    for (int i = 0; i < NUM_LEDS; i++) {
      colorIndex[i]++;
    }
  }
  FastLED.show();
}

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


//============================================================
// freeMemory() from Adafruit
// https://learn.adafruit.com/memories-of-an-arduino/measuring-free-memory#sram-370031-5
// Adapted to work with Wokwi
//============================================================
extern char *__brkval;

int freeMemory() 
{
  char top;
  return __brkval ? &top - __brkval : &top - __malloc_heap_start;
}
//============================================================