// from https://gist.github.com/jnslsrwy/08c7b3b52d73dfb1c146f2128232a8d7


#define ISSUE668_WORKAROUND true

#include <FastLED.h>
// #include <aREST.h>

#define NUM_FANS   3
#define NUM_STRIP 25
#define D_FANS     4
#define D_STRIP    5
#define POW        3

// Set total ammount of LEDs
const int num = NUM_FANS + NUM_STRIP;

// Create LED array
CRGB leds[num];

// Create rest instance
//aREST rest = aREST();

// Set Globals
int activeColor[3] = {255,0,0};
int brightness = 0;
int fadeMode = 0;
int fadeModeCache = 0;
int hue = 0;
int targetBrightness, fadeAmount;

void setup() {
  Serial.begin(115200);
  pinMode(POW, OUTPUT);
  FastLED.addLeds<WS2812B,D_STRIP,GRB>(leds, NUM_STRIP).setCorrection(TypicalLEDStrip);
  FastLED.addLeds<WS2812B,D_FANS,GRB>(leds, NUM_STRIP, NUM_FANS).setCorrection(TypicalLEDStrip);

  fadeMode = 3;
  FastLED.show();
  // rest.function("fade",fadeAll);
  // rest.function("color",setColor);
}

void loop() {
  // rest.handle(Serial);

  // Fade brightness with activeColor & POW LED in / out
  if (fadeMode == 1 | fadeMode == 2){
    EVERY_N_MILLISECONDS(1){
      for (int j = 0; j < num; j++){
        leds[j].setRGB(activeColor[0],activeColor[1],activeColor[2]);
        leds[j].maximizeBrightness(brightness);
      }
      analogWrite(POW,brightness);
      brightness = brightness + fadeAmount;
    }
    FastLED.show();

    if (brightness == targetBrightness){
      fadeMode = 0;
    }
  }

  // Fade through hue
  if (fadeMode == 3){
    EVERY_N_MILLISECONDS(100){
      if (ISSUE668_WORKAROUND) {
        fill_rainbow2(leds, num, hue, 255/3/3); // 3 Fans display a 3rd of the hue band
        fill_rainbow2(leds, NUM_STRIP, hue, 255/25/3); // 25 Neopixel display a 3rd of the hue band
      } else {
        fill_rainbow(leds, num, hue, 255/3/3); // 3 Fans display a 3rd of the hue band
        fill_rainbow(leds, NUM_STRIP, hue, 255/25/3); // 25 Neopixel display a 3rd of the hue band
      }

      FastLED.show();

      // Reset if through one time else increase
      if (hue == 254){
      hue = 0;
      } else {
        hue++;
      }
    }
  }
}

int fadeAll(String command){
  int parsedCommand = command.toInt();
  
  if (parsedCommand != fadeModeCache){
    if (parsedCommand == 1){
      fadeMode = 1;
      fadeAmount = 1;
      targetBrightness = 255;
    } else if (parsedCommand == 2) {
      fadeMode = 2;
      fadeAmount = -1;
      targetBrightness = 0;
    } else {
      fadeMode = parsedCommand;
    }
    fadeModeCache = fadeMode;
  }
  
  return 0;
}

int setColor(String command){
  int commandLen = command.length()+1;
  char commandChar[commandLen];
  command.toCharArray(commandChar,commandLen);
  
  char* token = strtok (commandChar, ",");
  
  for (int i = 0; i < 3; i++){
    activeColor[i] = atoi(token);
    token = strtok (NULL, ",");
  }
  
  return 0;
}


void fill_rainbow2( struct CRGB * pFirstLED, int numToFill,
                  uint8_t initialhue,
                  uint8_t deltahue )
{
    CHSV hsv;
    hsv.hue = initialhue;
    hsv.val = 255;
    hsv.sat = 255;
    for( int i = 0; i < numToFill; ++i) {
        pFirstLED[i] = hsv;
        hsv.hue += deltahue;
    }
}