#include <FastLED.h>

#define every EVERY_N_MILLISECONDS
#define pot A7
#define rocker 8
#define push 7
#define leds 10
#define uvled 9
#define data 3
#define uv 11


uint8_t brite = 255;
uint8_t Hue = 0;
uint8_t Sat = 255;
uint8_t Val = 255;
uint8_t start = 0;
uint8_t shelf1 = 0;
uint8_t shelf2 = 64;
uint8_t shelf3 = 128;
uint8_t shelf4 = 192;
uint8_t shelf5 = 255;
unsigned long lastPress = 0;
int const len = 30;
int mode = 0;
bool check = true;
CRGB colors[len];

CRGBPalette16 thunderer = CRGBPalette16(
  CRGB(12, 12, 32),
  CRGB(12, 12, 32),
  CRGB(12, 12, 32),
  CRGB(12, 12, 32),
  CRGB(12, 12, 32),
  CRGB(12, 12, 32),
  CRGB(12, 12, 32),
  CRGB(12, 12, 32),
  CRGB(16, 16, 48),
  CRGB(16, 16, 48),
  CRGB(16, 16, 48),
  CRGB(16, 16, 48),
  CRGB(16, 16, 48),
  CRGB(16, 16, 48),
  CRGB::LightSlateGray,
  CRGB::Azure);

CRGBPalette16 blues = CRGBPalette16(
  CRGB::BlueViolet,
  CRGB::SlateBlue,
  CRGB::MediumSlateBlue,
  CRGB::CornflowerBlue,
  CRGB::DodgerBlue,
  CRGB::DeepSkyBlue,
  CRGB::Turquoise,
  CRGB::Cyan,
  CRGB::Cyan,
  CRGB::Turquoise,
  CRGB::DeepSkyBlue,
  CRGB::DodgerBlue,
  CRGB::CornflowerBlue,
  CRGB::MediumSlateBlue,
  CRGB::SlateBlue,
  CRGB::BlueViolet);

void storm(int spd = 4, int scale = 20) {
  for (int i = 0; i < len; i++) {
    uint8_t index = inoise8(i * scale, millis() / spd);
    index = map(index, 50, 220, 0, 255) * 1;
    colors[i] = ColorFromPalette(thunderer, index, Val);
  }
  FastLED.show();
}

void wave(int time = 30) {
  fill_palette(colors, len, start, 16, blues, Val, LINEARBLEND);
  every(time) {
    start++;
  }
  FastLED.show();
}

void colorShift() {
  fill_solid(colors, len, CHSV(Hue, Sat, Val));
  EVERY_N_MILLIS_I(t, 30) {
    t.setPeriod(map(brite, 0, 255, 1, 50));
    Hue++;
  }
  FastLED.show();
}

void shelfColors() {
  EVERY_N_MILLIS_I(t, 30) {
    t.setPeriod(map(brite, 0, 255, 1, 100));
    for(int i = 30; i > 0; i = i - 6) {
      fill_solid(colors, i, CHSV(Hue, Sat, Val));
      Hue = Hue + 51;
    }
    Hue = Hue + 2;
  }
  FastLED.show();
}

void shelves(int spd = 5, int scale = 2) {
  uint8_t index = inoise8(scale, millis() / spd);
  index = map(index, 0, 255, -63, 512) * 1;
  fill_solid(colors, len, CHSV(index, Sat, Val));
  every(10) {Serial.println(index);}
  FastLED.show();
}

void rainbow(int time = 30) {
  fill_rainbow_circular(colors, len, start);
  every(time) {
    start++;
  }
  FastLED.show();
}

void checkMode() {
  bool btnRead = digitalRead(push);
  if(btnRead == HIGH && millis() - lastPress > 500) {   //check for button press with 500 mS debounce
    mode++;
    lastPress = millis();   //reset debounce
    //Serial.print("Button Pressed. Mode:");
    //Serial.println(mode);
    do {
      btnRead = digitalRead(push);
      delay(50);
      } while(btnRead == HIGH);
  }
}

void setup() {
  pinMode(rocker, INPUT);
  pinMode(push, INPUT);
  pinMode(leds, OUTPUT);
  pinMode(uvled, OUTPUT);
  pinMode(data, OUTPUT);
  pinMode(uv, OUTPUT);

  FastLED.addLeds<NEOPIXEL, data>(colors, len);
  FastLED.setBrightness(brite);
  Serial.begin(9600);

  brite = map(analogRead(pot), 0, 1023, 0, 255);
  checkMode();
  //Serial.print("Mode:");
  //Serial.println(mode);
}

void loop() {
  checkMode();
  FastLED.setBrightness(Val);
  if(digitalRead(rocker) == HIGH) {
    brite = map(analogRead(pot), 0, 1023, 0, 255);
    if(mode != 0) {analogWrite(leds, brite);}
    if(mode != 0 && mode != 2) {analogWrite(uvled, brite);}
  }
  else{
    Val = map(analogRead(pot), 0, 1023, 1, 255);
    digitalWrite(leds, LOW);
    digitalWrite(uvled, LOW);
  }
  //rainbow(10);
  //colorShift();
  //shelfColors();
  //shelves();
  switch(mode) {
    case 0:   //Off mode
      digitalWrite(leds, LOW);
      digitalWrite(uvled, LOW);
      fill_solid(colors, len, CRGB::Black);
      FastLED.show();
      checkMode;
      break;
    case 1:   //White lights only mode
      checkMode;
      break;
    case 2:   //UV light mode
      analogWrite(uv, Val);
      digitalWrite(uvled, LOW);
      checkMode;
      break;
    case 3:   //Storm mode
      digitalWrite(uv, LOW);
      rainbow(30);
      break;
    default:
      mode = 0;
      break;
  }
}