// https://forum.arduino.cc/t/programming-led-lights-for-a-performance/1272933/17
// https://forum.arduino.cc/t/circular-matrix/1164773/6
// https://forum.arduino.cc/t/led-gyro-ball-diy-help/1239872
// https://www.youtube.com/watch?v=Q5d8gTppuYo
// https://www.instructables.com/RGB-LED-Sphere/
// https://youtu.be/DMBejIlcKSM

#include <FastLED.h>

#define STRINGS 16
#define STRING_SIZE 16
#define NUM_LEDS (STRINGS * STRING_SIZE) // 16 * 16 = 256
#define MATRIX_PIN 2
#define BRIGHTNESS 255 // max brightness
CRGB leds[NUM_LEDS];

#define BUTTON 3

void setup() {
  randomSeed(analogRead(A0)); // allow for pseudo-random colors
  Serial.begin(115200);

  FastLED.addLeds<WS2812B, MATRIX_PIN, GRB>(leds, NUM_LEDS);
  FastLED.setBrightness(BRIGHTNESS);
  FastLED.clear();
  FastLED.show();

  pinMode(BUTTON, INPUT_PULLUP);
  Serial.println("Mash the RED button to start.");
  while (digitalRead(BUTTON));

  // pixie();
}

void loop() {
  // rainbow();
  // fade_black_to_white();
  // everyone();
  latitude();
  // longitude();
  // onebyone();
  // pewpew();
  // swirl_1();
  // swirl_2();
  // twinkle();
  // thealgorithm();
}

void rainbow() {
  uint8_t thisHue = beatsin16(10, 0, 255);
  fill_rainbow(leds, NUM_LEDS, thisHue, 10);
  FastLED.show();
}

void latlon() {
  // synchronous latitude and longitude
}

void latitude() {
  int r = random(256) * random(2), g = random(256) * random(2), b = random(256) * random(2);
  for (int i = 0; i < STRING_SIZE; i++) {
    for (int j = 0; j < STRINGS; j++) {
      leds[i + j * STRING_SIZE] =  CRGB(r, g, b);
    }
    FastLED.show();
    delay(25);
    FastLED.clear();
  }
}

void longitude() {
  int r = random(256) * random(2), g = random(256) * random(2), b = random(256) * random(2);
  for (int j = 0; j < STRINGS; j++) {
    for (int i = 0; i < STRING_SIZE; i++)
      leds[i + STRING_SIZE * j] = CRGB(r,  g, b);
    FastLED.show();
    delay(25);
    FastLED.clear();
  }
}

void fade_black_to_white() {
  for (int i = 0; i < 256; i++) {
    fill_solid(leds, NUM_LEDS, CRGB(i - 255, i - 255, i - 255));
    FastLED.show();
  }
}

void pewpew() {
  int i = random(16);
  for (int j = 0; j < STRING_SIZE; j++) {
    leds[j + i * 16] = CRGB(255, 255, 255);
    FastLED.show();
  }
  delay(100);
  FastLED.clear();
}

void swirl_1() {
  int i = 0;
  for (int j = 0; j < STRINGS; j++) {
    int dot = (j * STRING_SIZE) + j + (i * STRINGS);
    for (int k = 0; k < STRINGS; k++) {
      if (dot + k * STRING_SIZE > STRINGS * STRING_SIZE)
        dot = dot - STRINGS * STRING_SIZE;
      leds[dot + k * STRING_SIZE] =  CRGB(
                                       128 + k * 16, // red
                                       255 - (128 + k * 16), // green
                                       64 + k * 8); // blue
      // alto777 code
      // leds[dot + k * STRING_SIZE] = CRGB(
      //   ((sin( 2 * PI * j / NUM_LEDS + 0 * PI / 3 ) * 127 + 128) / 255) * 255,
      //   ((sin( 2 * PI * j / NUM_LEDS + 2 * PI / 3 ) * 127 + 128) / 255) * 255,
      //   ((sin( 2 * PI * j / NUM_LEDS + 4 * PI / 3 ) * 127 + 128) / 255) * 255);
    }
    FastLED.show();
    delay(100);
  }
  // delay(100);
  FastLED.clear();
}

void swirl_2() {
  for (int i = 0; i < 2; i++) {
    for (int j = 0; j < STRINGS; j++) {

      int dot = (j * STRING_SIZE) + j + (i * STRINGS);

      if (dot + 00 > STRINGS * STRING_SIZE)
        dot = dot - STRINGS * STRING_SIZE;
      leds[dot + 00] =  CRGB(255, 000, 000);
      if (dot + 16 > STRINGS * STRING_SIZE)
        dot = dot - STRINGS * STRING_SIZE;
      leds[dot + 16] =  CRGB(255, 255, 000);
      if (dot + 32 > STRINGS * STRING_SIZE)
        dot = dot - STRINGS * STRING_SIZE;
      leds[dot + 32] =  CRGB(000, 000, 255);
      if (dot + 48 > STRINGS * STRING_SIZE)
        dot = dot - STRINGS * STRING_SIZE;
      leds[dot + 48] =  CRGB(255, 000, 255);
      if (dot + 64 > STRINGS * STRING_SIZE)
        dot = dot - STRINGS * STRING_SIZE;
      leds[dot + 64] =  CRGB(000, 255, 000);
      if (dot + 80 > STRINGS * STRING_SIZE)
        dot = dot - STRINGS * STRING_SIZE;
      leds[dot + 80] =  CRGB(000, 255, 255);
      if (dot + 96 > STRINGS * STRING_SIZE)
        dot = dot - STRINGS * STRING_SIZE;
      leds[dot + 96] =  CRGB(255, 255, 255);
      if (dot + 112 > STRINGS * STRING_SIZE)
        dot = dot - STRINGS * STRING_SIZE;
      leds[dot + 112] =  CRGB(255, 165, 000);

      FastLED.show();
      delay(100);
    }
  }
  delay(100);
  FastLED.clear();
}

void thealgorithm() {
  for (int i = 0; i < STRING_SIZE; i++) {
    for (int j = 0; j < STRINGS; j++) {
      leds[i + j * (16 + i)] =  CRGB(0, 127, 255);
      FastLED.show();
      delay(100);
    }
  }
  delay(100);
  FastLED.clear();
}

void twinkle() {
  int x = random(NUM_LEDS);
  leds[x] = CRGB(255, 255, 255);
  FastLED.show();
  delay(100);
  FastLED.clear();
  FastLED.show();
}

void onebyone() {
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CRGB(random(256), random(256), random(256));
    FastLED.show();
  }
}

void everyone() {
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CRGB(random(256), random(256), random(256));
  }
  FastLED.show();
}