// A NeoPixel strip running light program.

// NEOPIXEL BEST PRACTICES for most reliable operation:
// - Add 1000 uF CAPACITOR between NeoPixel strip's + and - connections.
// - MINIMIZE WIRING LENGTH between microcontroller board and first pixel.
// - NeoPixel strip's DATA-IN should pass through a 300-500 OHM RESISTOR.
// - AVOID connecting NeoPixels on a LIVE CIRCUIT. If you must, ALWAYS
//   connect GROUND (-) first, then +, then data.
// - When using a 3.3V microcontroller with a 5V-powered NeoPixel strip,
//   a LOGIC-LEVEL CONVERTER on the data line is STRONGLY RECOMMENDED.
// (Skipping these may work OK on your workbench but can fail in the field)

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
 #include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif

#define DEBUG true
#define Serial if(DEBUG)Serial

// Which pin on the Arduino is connected to the NeoPixels?
// On a Trinket or Gemma we suggest changing this to 1:
#define LED_PIN     6
// #define BTN_PIN     2

const int BTN_PIN = 2;
unsigned long btnTime = 0;
int btnState = 0;


// How many NeoPixels are attached to the Arduino?
#define LED_COUNT 96

// Declare our NeoPixel strip object:
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
// Argument 1 = Number of pixels in NeoPixel strip
// Argument 2 = Arduino pin number (most are valid)
// Argument 3 = Pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
//   NEO_RGBW    Pixels are wired for RGBW bitstream (NeoPixel RGBW products)

const int rainbowColors[][3] = {
  {255, 0, 0}, // Red
  {255, 32, 0}, // 
  {255, 64, 0}, // 
  {255, 96, 0}, // 
  {255, 128, 0}, // 
  {255, 160, 0}, // 
  {255, 192, 0}, // 
  {255, 224, 0}, // 
  {255, 255, 0}, // yellow
  {224, 255, 0}, // 
  {192, 255, 0}, // 
  {160, 255, 0}, // 
  {128, 255, 0}, // 
  {96, 255, 0}, // 
  {64, 255, 0}, // 
  {32, 255, 0}, // 
  {0, 255, 0}, // green
  {0, 255, 32}, // 
  {0, 255, 64}, // 
  {0, 255, 96}, // 
  {0, 255, 128}, // 
  {0, 255, 160}, // 
  {0, 255, 192}, // 
  {0, 255, 224}, // 
  {0, 255, 255}, // cyan
  {0, 224, 255}, // 
  {0, 192, 255}, // 
  {0, 160, 255}, // 
  {0, 128, 255}, // 
  {0, 96, 255}, // 
  {0, 64, 255}, // 
  {0, 32, 255}, // 
  {0, 0, 255}, // blue
  {32, 0, 255}, // 
  {64, 0, 255}, // 
  {96, 0, 255}, // 
  {128, 0, 255}, // 
  {160, 0, 255}, // 
  {192, 0, 255}, // 
  {224, 0, 255}, // 
  {255, 0, 255}, // magenta
  {255, 0, 224}, // 
  {255, 0, 192}, // 
  {255, 0, 160}, // 
  {255, 0, 128}, // 
  {255, 0, 96}, // 
  {255, 0, 64}, // 
  {255, 0, 32}, // 
};
const int numColors = sizeof(rainbowColors)/sizeof(rainbowColors[0]);

int mixedColors[numColors][3] = {};


int           patternCount = 12;
int           patternInterval = 10000;  // Pattern Interval (ms)
unsigned long patternPrevious = 0;      // Previous Pattern Millis

int           pixelCycle = 0;           // Pattern Pixel Cycle
uint16_t      pixelNumber = LED_COUNT;  // Total Number of Pixels

unsigned long past = 0;      // milli seconds memory for the pattern cycles

// setup() function -- runs once at startup --------------------------------
void setup(){
  // These lines are specifically to support the Adafruit Trinket 5V 16 MHz.
  // Any other board, you can remove this part (but no harm leaving it):
#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
  clock_prescale_set(clock_div_1);
#endif
  // END of Trinket-specific code.

  pinMode(BTN_PIN, INPUT);

  strip.begin();           // INITIALIZE NeoPixel strip object (REQUIRED)
  strip.show();            // Turn OFF all pixels ASAP
  strip.setBrightness(50); // Set BRIGHTNESS to about 1/5 (max = 255)

  Serial.begin(9600);

  for(int i = 0; i < numColors-1; i++){
    int rand = random(numColors-1);
    mixedColors[i][0] = rainbowColors[rand][0];
    mixedColors[i][1] = rainbowColors[rand][1];
    mixedColors[i][2] = rainbowColors[rand][2];
  }
}

// loop() function -- runs repeatedly as long as board is on ---------------
void loop(){
  switch(getMode()){
    case 1: // Fill along the length of the strip in various colors...
      for(int ci=0; ci < numColors; ci++){
        colorWipe(mixedColors[ci], 10);
      }
    break;
    case 2: // Do a theater marquee effect in various colors...
      for(int ci=0; ci < numColors; ci++){
        theaterChase(mixedColors[ci], 30);
      }
    break;
    case 3: // Do a random rainbow colors flash effect
      for(int ci=0; ci < numColors; ci++){
        colorFlash(mixedColors[ci], 10);
      }
    break;
    case 4: // Rainbow-enhanced theaterChase variant
      theaterChaseRainbow(100);
    break;
    case 5: // Flowing rainbow cycle along the whole strip
      rainbow_gradient(25);
    break;
    case 6: // Flowing rainbow cycle along the whole strip
      rgb_gradient(5);
    break;
    case 7:
      curtain(10);
    break;
    case 8:
      curtainExtended(10);
    break;
    case 9: // night rider infra red scanner effect
      nightRider(500);
    break;
    case 10:
      superNova(3);
    break;
    case 11:
      rainbowBuilder(1);
    break;
    case 12: // night rider infra red scanner effect
      rainbowWorm(200);
    break;
    case 13: // night rider infra red scanner effect
      nightRiderExtended(250);
    break;
    case 14: // night rider infra red scanner effect
      stroboCurtain(100);
    break;
    default:
      int white[3] = {200, 200, 200};
      theaterChase(white, 100);
    break;
  }
}
int patternCurrent = 9;       // Current Pattern Number

void nightRiderExtended(int t){
  if(cycleDelay(t))
    nightRiderExtendedForward();
    nightRiderExtendedRewind();
}
void nightRiderExtendedForward(){
  int rgb[3], ctc = 16, ci = 0;
  for(int pi = 0; pi < strip.numPixels()+ctc; pi++){
    rgb[0] = rainbowColors[ci][0];
    rgb[1] = rainbowColors[ci][1];
    rgb[2] = rainbowColors[ci][2];
    for(int cti = 1; cti <= ctc; cti++){
      for(int cvi = 0; cvi < 3; cvi++){
        if(rainbowColors[ci][cvi] == 255){
          rgb[cvi] = 256 - ctc*cti;
        }
        if(rainbowColors[ci][cvi] == 192){
          rgb[cvi] = 192 - ctc*cti/4*3;
        }
        if(rainbowColors[ci][cvi] == 128){
          rgb[cvi] = 128 - ctc*cti/2;
        }
        if(rainbowColors[ci][cvi] == 64){
          rgb[cvi] = 64 - ctc*cti/4;
        }
      }
      strip.setPixelColor(pi - cti, strip.Color(rgb[0], rgb[1], rgb[2]));
    }
    ci+=2;
    if(ci == numColors) ci = 0;
    strip.show();
  }
}
void nightRiderExtendedRewind(){
  int rgb[3], ctc = 16, ci = 0;
  for(int pi = strip.numPixels(); pi > 0-ctc; pi--){
    rgb[0] = rainbowColors[ci][0];
    rgb[1] = rainbowColors[ci][1];
    rgb[2] = rainbowColors[ci][2];
    for(int cti = 1; cti <= ctc; cti++){
      for(int cvi = 0; cvi < 3; cvi++){
        if(rainbowColors[ci][cvi] == 255){
          rgb[cvi] = 256 - ctc*cti;
        }
        if(rainbowColors[ci][cvi] == 192){
          rgb[cvi] = 192 - ctc*cti/4*3;
        }
        if(rainbowColors[ci][cvi] == 128){
          rgb[cvi] = 128 - ctc*cti/2;
        }
        if(rainbowColors[ci][cvi] == 64){
          rgb[cvi] = 64 - ctc*cti/4;
        }
      }
      strip.setPixelColor(pi + cti, strip.Color(rgb[0], rgb[1], rgb[2]));
    }
    ci+=2;
    if(ci == numColors) ci = 0;
    strip.show();
  }
}

void rainbowWorm(int t){
  if(cycleDelay(t))
    rainbowWormForward();
    rainbowWormRewind();
}
void rainbowWormForward(){
  int rgb[3], ctc = 16, ci = 0;
  for(int pi = 0; pi < strip.numPixels()+ctc; pi++){
    rgb[0] = rainbowColors[ci][0];
    rgb[1] = rainbowColors[ci][1];
    rgb[2] = rainbowColors[ci][2];
    for(int cti = 1; cti <= ctc; cti++){
      for(int cvi = 0; cvi < 3; cvi++){
        if(rainbowColors[ci][cvi] == 255){
          rgb[cvi] = 256 - ctc*cti;
        }
        if(rainbowColors[ci][cvi] == 192){
          rgb[cvi] = 192 - ctc*cti/4*3;
        }
        if(rainbowColors[ci][cvi] == 128){
          rgb[cvi] = 128 - ctc*cti/2;
        }
        if(rainbowColors[ci][cvi] == 64){
          rgb[cvi] = 64 - ctc*cti/4;
        }
      }
      strip.setPixelColor(pi - cti, strip.Color(rgb[0], rgb[1], rgb[2]));
      ci+=2;
      if(ci == numColors) ci = 0;
    }
    strip.show();
  }
}
void rainbowWormRewind(){
  int rgb[3], ctc = 16, ci = 0;
  for(int pi = strip.numPixels(); pi > 0-ctc; pi--){
    rgb[0] = rainbowColors[ci][0];
    rgb[1] = rainbowColors[ci][1];
    rgb[2] = rainbowColors[ci][2];
    for(int cti = 1; cti <= ctc; cti++){
      for(int cvi = 0; cvi < 3; cvi++){
        if(rainbowColors[ci][cvi] == 255){
          rgb[cvi] = 256 - ctc*cti;
        }
        if(rainbowColors[ci][cvi] == 192){
          rgb[cvi] = 192 - ctc*cti/4*3;
        }
        if(rainbowColors[ci][cvi] == 128){
          rgb[cvi] = 128 - ctc*cti/2;
        }
        if(rainbowColors[ci][cvi] == 64){
          rgb[cvi] = 64 - ctc*cti/4;
        }
      }
      strip.setPixelColor(pi + cti, strip.Color(rgb[0], rgb[1], rgb[2]));
      ci+=2;
      if(ci == numColors) ci = 0;
    }
    strip.show();
  }
}

// unfinished
void rainbowBuilder(int t){
  int ctc = 16;
  if(cycleDelay(t))
    for(int ci = 0; ci < numColors; ci++){
      for(int pi = 0; pi < strip.numPixels(); pi++){
        strip.setPixelColor(pi-ci, strip.Color(rainbowColors[ci][0], rainbowColors[ci][1], rainbowColors[ci][2]));
        strip.setPixelColor(pi-ci-1, strip.Color(0, 0, 0));
        strip.show();
      }
    }
}

// unfinished
void superNova(int t){
  int ctc = 16;
  for(int ci = 0; ci < numColors; ci++){
    int pxCount = strip.numPixels()-1;
    for(int pi = 0; pi < pxCount; pi++){
      strip.setPixelColor(pi-ci, strip.Color(rainbowColors[ci][0], rainbowColors[ci][1], rainbowColors[ci][2]));
      strip.setPixelColor(pi-ci-1, strip.Color(0, 0, 0));
      strip.setPixelColor(pxCount+ci , strip.Color(rainbowColors[ci][0], rainbowColors[ci][1], rainbowColors[ci][2]));
      strip.setPixelColor(pxCount+ci+1, strip.Color(0, 0, 0));
      strip.show();
      delay(t);
      pxCount--;
    }
  }
}

// unfinished
void gradientCurtain(int t){
  int ctc = 16;
  int** ct;
  for(int ci = 0; ci < numColors; ci+=2){
    int pxCount = strip.numPixels()-1;
    ct = colorDarker(rainbowColors[ci]);
    Serial.println((String)ct[1][0]+" - "+(String)ct[1][1]+" - "+(String)ct[1][2]);
    for(int pi = 0; pi < pxCount; pi++){
      for(int cti = 0; cti < sizeof(ct)/sizeof(ct[0]); cti++){
        strip.setPixelColor(pi - cti, strip.Color(ct[cti][0], ct[cti][1], ct[cti][2]));
        strip.setPixelColor(pxCount-- , strip.Color(ct[cti][0], ct[cti][1], ct[cti][2]));
      }
      strip.show();
      delay(t);
    }
  }
}
int colorDarker(int c[3]){
  int** ct = new int*[17];
  int ctc = 16;
  int* rgb = new int[3];
  ct[0] = c;
  for(int cti = 1; cti <= ctc; cti++){
    for(int cvi = 0; cvi < 3; cvi++){
      rgb[cvi] = 0;
      if(c[cvi] == 255){
        rgb[cvi] = 256 - ctc*cti;
      }
      if(c[cvi] == 192){
        rgb[cvi] = 192 - ctc*cti/4*3;
      }
      if(c[cvi] == 128){
        rgb[cvi] = 128 - ctc*cti/2;
      }
      if(c[cvi] == 64){
        rgb[cvi] = 64 - ctc*cti/4;
      }
    }
    ct[cti] = rgb;
    // Serial.println((String)ct[cti][0]+" - "+(String)ct[cti][1]+" - "+(String)ct[cti][2]);
  }
  return ct;
}


/**************************************************/
/*      getMode global calulation                 */
/**************************************************/
int getMode(){
  unsigned long currentMillis = millis();                     //  Update current time
  if((currentMillis - patternPrevious) >= patternInterval){  //  Check for expired time
    patternPrevious = currentMillis;
    patternCurrent++;                                         //  Advance to next pattern
    if(patternCurrent > patternCount)
      patternCurrent = 0;
  }
  if(digitalRead(BTN_PIN) == HIGH){
    Serial.println("1");
    btnTime = millis(); 
    btnState = 1;                                         //  Advance to next pattern
  }
  if(millis() - btnTime > 100 && btnState){
    Serial.println("2");
    patternCurrent++;
    btnState = 0;                                         //  Advance to next pattern
  }
  return patternCurrent;
}

// creating animated effects

void nightRider(int t){
  int c = 1;
  if(cycleDelay(t))
     for(int ci = 0; ci < numColors; ci+=2){
      if(c&1){
        nightRiderForwards(rainbowColors[ci]);
      }else{
        nightRiderRewind(rainbowColors[ci]);
      }
      c++;
    }
}
void nightRiderForwards(int c[3]){
  int rgb[3], ctc = 16;
  // int** ct = colorDarker(c);
  for(int pi = 0; pi < strip.numPixels()+ctc; pi++){
    // for(int cti = 0; cti < sizeof(ct)/sizeof(ct[0]); cti++){
    //   strip.setPixelColor(pi - cti, strip.Color(ct[cti][0], ct[cti][1], ct[cti][2]));
    // }
    rgb[0] = c[0];
    rgb[1] = c[1];
    rgb[2] = c[2];
    for(int cti = 1; cti <= ctc; cti++){
      for(int cvi = 0; cvi < 3; cvi++){
        if(c[cvi] == 255){
          rgb[cvi] = 256 - ctc*cti;
        }
        if(c[cvi] == 192){
          rgb[cvi] = 192 - ctc*cti/4*3;
        }
        if(c[cvi] == 128){
          rgb[cvi] = 128 - ctc*cti/2;
        }
        if(c[cvi] == 64){
          rgb[cvi] = 64 - ctc*cti/4;
        }
      }
      strip.setPixelColor(pi - cti, strip.Color(rgb[0], rgb[1], rgb[2]));
    }
    strip.show();
  }
}
void nightRiderRewind(int c[3]){
  int rgb[3], ctc = 16;
  // int** ct = colorDarker(c);
  for(int pi = strip.numPixels(); pi > 0-ctc; pi--){
    // for(int cti = 0; cti < sizeof(ct)/sizeof(ct[0]); cti++){
    //   strip.setPixelColor(pi + cti, strip.Color(ct[cti][0], ct[cti][1], ct[cti][2]));
    // }
    rgb[0] = c[0];
    rgb[1] = c[1];
    rgb[2] = c[2];
    for(int cti = 1; cti <= ctc; cti++){
      for(int cvi = 0; cvi < 3; cvi++){
        if(c[cvi] == 255){
          rgb[cvi] = 256 - ctc*cti;
        }
        if(c[cvi] == 192){
          rgb[cvi] = 192 - ctc*cti/4*3;
        }
        if(c[cvi] == 128){
          rgb[cvi] = 128 - ctc*cti/2;
        }
        if(c[cvi] == 64){
          rgb[cvi] = 64 - ctc*cti/4;
        }
      }
      strip.setPixelColor(pi + cti, strip.Color(rgb[0], rgb[1], rgb[2]));
    }
    strip.show();
  }
}

void curtain(int t){
  int ci2 = numColors-1;
  for(int ci = 0; ci < numColors; ci++){
    if(ci&1){
      curtainInner2Outer(rainbowColors[ci2--], t);
    }else{
      curtainOuter2Inner(rainbowColors[ci], t);
    }
  }
}
void curtainOuter2Inner(int c[3], int t){
  int pxCount = strip.numPixels()-1;
  for(int pi = 0; pi < pxCount; pi++){
    strip.setPixelColor(pi, strip.Color(c[0], c[1], c[2]));
    strip.setPixelColor(pxCount--, strip.Color(c[0], c[1], c[2]));
    strip.show();
    delay(t);
  }
  pxCount = strip.numPixels()-1;
  for(int pi = 0; pi < pxCount; pi++){
    strip.setPixelColor(pi, strip.Color(0, 0, 0));
    strip.setPixelColor(pxCount--, strip.Color(0, 0, 0));
    strip.show();
    delay(t);
  }
}
void curtainInner2Outer(int c[3], int t){
  int pxCount = strip.numPixels()/2;
  for(int pi = pxCount-1; pi >= 0; pi--){
    strip.setPixelColor(pi, strip.Color(c[0], c[1], c[2]));
    strip.setPixelColor(pxCount++, strip.Color(c[0], c[1], c[2]));
    strip.show();
    delay(t);
  }
  pxCount = strip.numPixels()-1;
  for(int pi = 0; pi < pxCount; pi++){
    strip.setPixelColor(pi, strip.Color(0, 0, 0));
    strip.setPixelColor(pxCount--, strip.Color(0, 0, 0));
    strip.show();
    delay(t);
  }
}

void curtainExtended(int t){
  int c = 1;
  for(int ci = 0; ci < numColors; ci++){
    if(c&1){
      curtainExtendedOuter2Inner(rainbowColors[ci], t);
      curtainExtendedOuter2Inner(rainbowColors[ci+3], t);
   }else{
      curtainExtendedInner2Outer(rainbowColors[ci], t);
      curtainExtendedInner2Outer(rainbowColors[ci+3], t);
    }
    c++;
  }
}
void curtainExtendedOuter2Inner(int c[3], int t){
  int pxCount = strip.numPixels()-1;
  for(int pi = 0; pi < pxCount; pi++){
    strip.setPixelColor(pi, strip.Color(c[0], c[1], c[2]));
    strip.setPixelColor(pxCount--, strip.Color(c[0], c[1], c[2]));
    strip.show();
    delay(t);
  }
}
void curtainExtendedInner2Outer(int c[3], int t){
  int pxCount = strip.numPixels()/2;
  for(int pi = pxCount-1; pi >= 0; pi--){
    strip.setPixelColor(pi, strip.Color(c[0], c[1], c[2]));
    strip.setPixelColor(pxCount++, strip.Color(c[0], c[1], c[2]));
    strip.show();
    delay(t);
  }
}

void stroboCurtain(int t){
    // curtain(rainbowColors[ci], rainbowColors[ci2], t);
    // strobo(rainbowColors[ci], rainbowColors[ci2], t);
  closeCurtain(rainbowColors[0], rainbowColors[32], t);
  for(int ci = 0; ci < 20; ci++){
    strobo(rainbowColors[0], rainbowColors[32], t);
  }
  openCurtain(rainbowColors[0], rainbowColors[32], t);
}
void closeCurtain(int c1[3], int c2[3], int t){
  int pxCount = strip.numPixels()-1;
  for(int pi = 0; pi < pxCount; pi+=2){
    strip.setPixelColor(pi, strip.Color(c1[0], c1[1], c1[2]));
    strip.setPixelColor(pxCount-pi, strip.Color(c2[0], c2[1], c2[2]));
    strip.show();
    delay(t);
  }
}
void openCurtain(int c1[3], int c2[3], int t){
  int pxCount = strip.numPixels()-1;
  for(int pi = pxCount; pi > 0; pi-=2){
    strip.setPixelColor(pi, strip.Color(0, 0, 0));
    strip.setPixelColor(pxCount-pi, strip.Color(0, 0, 0));
    strip.show();
    delay(t);
  }
}
void strobo(int c1[3], int c2[3], int t){
  int pxCount = strip.numPixels()-1;
  for(int pi = 0; pi < pxCount; pi+=2){
    strip.setPixelColor(pi, strip.Color(0, 0, 0));
    strip.setPixelColor(pxCount-pi, strip.Color(c2[0], c2[1], c2[2]));
  }
  strip.show();
  delay(t);
  for(int pi = 0; pi < pxCount; pi+=2){
    strip.setPixelColor(pi, strip.Color(c1[0], c1[1], c1[2]));
    strip.setPixelColor(pxCount-pi, strip.Color(0, 0, 0));
  }
  strip.show();
  delay(t);
}

// Fill strip pixels one after another with a color. Strip is NOT cleared
// first; anything there will be covered pixel by pixel. Pass in color
// (as a single 'packed' 32-bit value, which you can get by calling
// strip.Color(red, green, blue) as shown in the loop() function above),
// and a delay time (in milliseconds) between pixels.
void colorWipe(int c[3], int t) {
  if(cycleDelay(t)){
    for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
      strip.setPixelColor(i, strip.Color(c[0], c[1], c[2]));         //  Set pixel's color (in RAM)
      strip.show();                          //  Update strip to match
    }
  }
  if(cycleDelay(t)){
    for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
      strip.setPixelColor(i, strip.Color(0, 0, 0));         //  Set pixel's color (in RAM)
      strip.show();                          //  Update strip to match
    }
  }
}

// Fill strip pixels one after another with a color. Strip is NOT cleared
// first; anything there will be covered pixel by pixel. Pass in color
// (as a single 'packed' 32-bit value, which you can get by calling
// strip.Color(red, green, blue) as shown in the loop() function above),
// and a delay time (in milliseconds) between pixels.
void colorFlash(int c[3], int t){
  if(cycleDelay(t)){
    for(int i=0; i<strip.numPixels(); i++){ // For each pixel in strip...
      strip.setPixelColor(i, strip.Color(c[0], c[1], c[2]));         //  Set pixel's color (in RAM)
    }
    strip.show();                          //  Update strip to match
  }
  if(cycleDelay(t)){
    for(int i=0; i<strip.numPixels(); i++){ // For each pixel in strip...
      strip.setPixelColor(i, strip.Color(0, 0, 0));         //  Set pixel's color (in RAM)
    }
    strip.show();                          //  Update strip to match
  }
}

// Theater-marquee-style chasing lights. Pass in a color (32-bit value,
// a la strip.Color(r,g,b) as mentioned above), and a delay time (in ms)
// between frames.
void theaterChase(int color[3], int t){
  if(cycleDelay(t))
    for(int a=0; a<10; a++){ // Repeat 10 times...
      for(int b=0; b<3; b++){ //  'b' counts from 0 to 2...
        strip.clear(); //   Set all pixels in RAM to 0 (off)
        // 'c' counts up from 'b' to end of strip in steps of 6...
        for(int c=b; c<strip.numPixels(); c+=6){
          strip.setPixelColor(c, strip.Color(color[0], color[1], color[2])); // Set pixel 'c' to value 'color'
        }
        strip.show(); // Update strip with new contents
      }
    }
}

// Rainbow cycle along whole strip. Pass delay time (in ms) between frames.
void rgb_gradient(int t){
  // Hue of first pixel runs 5 complete loops through the color wheel.
  // Color wheel has a range of 65536 but it's OK if we roll over, so
  // just count from 0 to 5*65536. Adding 256 to firstPixelHue each time
  // means we'll make 5*65536/256 = 1280 passes through this loop:
  for(long firstPixelHue = 0; firstPixelHue < 5*65536; firstPixelHue += 256){
    // strip.rainbow() can take a single argument (first pixel hue) or
    // optionally a few extras: number of rainbow repetitions (default 1),
    // saturation and value (brightness) (both 0-255, similar to the
    // ColorHSV() function, default 255), and a true/false flag for whether
    // to apply gamma correction to provide 'truer' colors (default true).
    strip.rainbow(firstPixelHue);
    // Above line is equivalent to:
    // strip.rainbow(firstPixelHue, 1, 255, 255, true);
    strip.show(); // Update strip with new contents
    delay(t);  // Pause for a moment
  }
}

// Rainbow cycle along whole strip. Pass delay time (in ms) between frames.
void rainbow_gradient(int t){                
  if(cycleDelay(t))
    for(uint16_t i=0; i < pixelNumber; i++) {
      strip.setPixelColor(i, Wheel((i + pixelCycle) & 255)); //  Update delay time  
    }
    strip.show();                             //  Update strip to match
    pixelCycle++;                             //  Advance current cycle
    if(pixelCycle >= 256)
      pixelCycle = 0;                         //  Loop the cycle back to the begining
}

// Rainbow-enhanced theater marquee. Pass delay time (in ms) between frames.
void theaterChaseRainbow(int t){
  int firstPixelHue = 0;     // First pixel starts at red (hue 0)
  if(cycleDelay(t))
    for(int a=0; a<30; a++) {  // Repeat 30 times...
      for(int b=0; b<3; b++) { //  'b' counts from 0 to 2...
        strip.clear();         //   Set all pixels in RAM to 0 (off)
        // 'c' counts up from 'b' to end of strip in increments of 3...
        for(int c=b; c<strip.numPixels(); c+=3) {
          // hue of pixel 'c' is offset by an amount to make one full
          // revolution of the color wheel (range 65536) along the length
          // of the strip (strip.numPixels() steps):
          int      hue   = firstPixelHue + c * 65536L / strip.numPixels();
          uint32_t color = strip.gamma32(strip.ColorHSV(hue)); // hue -> RGB
          strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
        }
        strip.show();                // Update strip with new contents
        firstPixelHue += 65536 / 90; // One cycle of color wheel over 90 frames
      }
    }
}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

bool cycleDelay(int t){
  unsigned long now = millis();
  if((now - past) >= t){  //  Check for expired time
    past = now;
    return true;
  }else{
    return false;
  }
}