#include <FastLED.h> // http://fastled.io/docs/files.html

#define ROWS 8 // rows in the matrix
#define COLS 8 // columns in the matrix
#define NUMPIX (ROWS * COLS) // the full matrix
#define PIXPIN 6 // Arduino data/digital pin
#define MAXBRIGHT 255 // pixels brightness, 0 - 255 

CRGB led[NUMPIX]; // create an object named "led" to control [NUMPIX] using FastLED (CRGB)

int cases = 6; // number of functions available

//*****************************************************************
// INTERRUPT SERVICE ROUTINE
//*****************************************************************
volatile bool button; // type volatile for interrupt handler
int buttonPin = 2; // interrupt pin INT0
int count = 0; // indicates the button was pressed

int buttonISR() {
  noInterrupts(); // disable interrupts while in the ISR
  button = 1; // set the flag that the button was pressed
  interrupts(); // enable interrupts when leaving the ISR
}
//*****************************************************************

void setup() {
  Serial.begin(9600); // debugging - not needed
  randomSeed(analogRead(A0)); // for more random randomness

  pinMode(buttonPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(buttonPin), buttonISR, FALLING); // INT#, ISR, TRIGGER

  FastLED.addLeds<WS2812B, PIXPIN, GRB>(led, NUMPIX);
  FastLED.setBrightness(MAXBRIGHT); // Adjust the brightness value as needed
  FastLED.clear(); // clear pixel buffer
  FastLED.show(); // display cleared buffer

  welcome();
}

void loop() {
  checkButton();
  switch (count) {
    case 0: mark(); break;
    case 1: corners(); break;
    case 2: blues(); break;
    case 3: scan(); break;
    case 4: randomColor(); break;
    case 5: fade(); break;
    case 6: blinkPanel();
    // case 7: async(); break;
  }
}

//*****************************************************************
// UTILITY FUNCTIONS
//*****************************************************************

void checkButton() {
  if (button) { // check button flag after returning from ISR
    delay(150); // debounce the button
    button = 0; // reset ISR flag for the next interrupt/button press
    count++; // increment selected pattern/case
    if (count > cases) { // if counter reached last case...
      count = 1; // ... reset counter to first case
    }
    Serial.print(count);
  }
}

//*****************************************************************
// PIXEL CALCULATION
//*****************************************************************

/*
    0*8+0=0            0*8+7=7
    led[0]              led[7]
    +------------------------+
    |0                      7|
    |                        |
    |                        |
    | PIX = row * COLS + col |
    |                        |
    |                        |
    +56____________________63+
    led[56]            led[63]
    7*8+0=56          7*8+7=63
*/

//*****************************************************************
// PIXEL FUNCTIONS
//*****************************************************************

void mark() { // at startup, pixel 0 shines R, G, B
  led[0] = CRGB(random(2) * random(MAXBRIGHT),
                random(2) * random(MAXBRIGHT),
                random(2) * random(MAXBRIGHT));
  FastLED.show();
  delay(300);
}

void async() {
  long interval[NUMPIX]; // each pixel gets an interval
  long oldTime[] = {0, 0, 0, 0, 0}; // clear event timers
  long newTime; // for all intervals

  for (int i = 0; i < NUMPIX; i++) {
    interval[i] = 100 * (random(20) + 1);
  }
}

void blinkPanel() {
  // byte r  = random(256), g = random(256), b = random(256);
  byte r  = random(2) * 255, g = random(2) * 255, b = random(2) * 255;
  for (int i = 0; i < NUMPIX; i++) {
    led[i] = CRGB(r, g, b);
  }
  FastLED.show();
  delay(250);
  FastLED.clear();
  FastLED.show();
  delay(250);
}

void fade() {
  int a = random(128);
  for (int i = 0; i < ROWS; i++) {
    for (int j = 0; j < COLS; j++) {
      led[i * COLS + j] = CRGB(0,  0, i * j * 4);
    }
  }
  FastLED.show();
}

void corners() {
  // row * col + col
  led[0 * 8 + 0] =  CRGB(255, 000, 000); // top, left
  led[0 * 8 + 7] =  CRGB(000, 000, 255); // top, right
  led[7 * 8 + 0] =  CRGB(255, 255, 000); // bottom, left
  led[7 * 8 + 7] =  CRGB(000, 255, 000); // bottom, right
  FastLED.show();
}

void blues() {
  for (int i = 0; i < ROWS; i++) {
    for (int j = 0; j < COLS; j++) {
      led[i * COLS + j] = CRGB(0, random(128, 256), random(128, 256));
    }
  }
  FastLED.show();
  delay(250);
}

void randomColor() { // random location with random PRIMARY (RGB) or SECONDARY (CMY) color
  led[random(ROWS * COLS)] = CRGB(random(2) * 255, random(2) * 255, random(2) * 255);
  FastLED.show(); // random pixel in random color
  delay(10);
}

void scan() {
  byte r = random(255);
  byte g = random(255);
  byte b = random(255);
  for (int i = 0; i < ROWS; i++) {
    for (int j = 0; j < COLS; j++) {
      led[i * ROWS + j] = CRGB(127, 127, 127); // color the pixel
      FastLED.show();
      delay(15);
      led[i * ROWS + j] = CRGB(r, g, b); // wait for next loop to uncolor pixel
    }
  }
}

//*****************************************************************
// WELCOME
//*****************************************************************

void welcome() {
  Serial.print("Press the button to change animations.\nAnimation: ");
  Serial.print(count);
}

// https://www.tweaking4all.com/hardware/arduino/arduino-all-ledstrip-effects-in-one/