// The following are necessary inclusions 
#include <Wire.h>
#include "Adafruit_MPR121.h"

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

#ifndef _BV
#define _BV(bit) (1 << (bit))
#endif

// Which pin on the Arduino is connected to the NeoPixels?
#define LED_PIN    6

// How many NeoPixels are attached to the Arduino?
// Not total, but max per string
#define LED_COUNT 8

// You can have up to 4 on one i2c bus but one is enough for testing!
Adafruit_MPR121 cap = Adafruit_MPR121();

uint16_t currtouched = 0;

// Declare our NeoPixel strip object:
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

int state = 0;  //There are 10 states (including off and 9 display modes)
int pixel;      //The individual NeoPixel being written to
int duration;		//Used by Storm Mode to define length of lightning flash
int flash;			//Used by Storm Mode to define the number of lightning flashes
long nowTime;		//Space to store current time 
long changeTime;	//Used by Storm Mode to store time of next lightning flash
long touchTime;		//Used by touchSense to store time of touch
long totalTime;		//Used by touchSense to store duration of touch
int wait = 50;		//Used throughout for standard wait time
int hold;			//Used to define space between lightning displays
int start = 0;		//Used by storm cloud to determin if startup display should execute
int changeMode;		//Used throughout to change between modes

void setup() {

  Serial.begin(9600);

  while (!Serial) { // needed to keep leonardo/micro from starting too fast!
    delay(10);
  }

  Serial.println("Adafruit MPR121 Capacitive Touch sensor test");

  if (!cap.begin(0x5A)) {
    Serial.println("MPR121 not found, check wiring?");
    while (1);
  }

  Serial.println("MPR121 found!");

  strip.begin();           // INITIALIZE NeoPixel strip object (REQUIRED)
  strip.show();            // Turn OFF all pixels ASAP
  strip.setBrightness(255); // Set BRIGHTNESS (max = 255)
}


void loop() {		// The following states call the different display modes

  if (state == 0) {
    start = 0;
    darkMode(wait);
  }
  else if (state == 1) {
    happyCloud(wait);
  }
  else if (state == 2) {
    stormCloud(wait);
  }
  else if (state == 3) {
    rainbow(wait);
  }
  else if (state == 4) {
    redMode(wait);
  }
  else if (state == 5) {
    yellowMode(wait);
  }
  else if (state == 6) {
    greenMode(wait);
  }
  else if (state == 7) {
    cyanMode(wait);
  }
  else if (state == 8) {
    blueMode(wait);
  }
  else if (state == 9) {
    purpleMode(wait);
  }
  else {
    state = 0;//if state is anything greater than 9, reset to 0 (OFF)
  }
}

void darkMode(int wait) //This mode turns the display off
{
  for (int i = 0; i < 9; i++) { // For each pixel in strip...
    strip.setPixelColor(i, strip.Color(0, 0, 0));
    strip.show();

    currtouched = cap.touched();
    touchSense();
    if (changeMode == 1)
    {
      changeMode = 0;
      return;
    }
    delay(wait);                           
  }
}

void happyCloud(int wait) //This mode turns the display on White
{
  for (int i = 0; i < 9; i++) { // For each pixel in strip...
	//Different materials filter light differently
	//You can adjust these values to 'tune' the color white
    strip.setPixelColor(i, strip.Color(255, 255, 255)); 
    strip.show();

    currtouched = cap.touched();
    touchSense();
    if (changeMode == 1)
    {
      changeMode = 0;
      return;
    }
    delay(wait);                       
  }
}

void stormCloud(int wait) //This mode simulates a storm
{
  if (start == 0) //Only on first time through for startup display
  {
    for (int i = 0; i < 9; i++) { // For each pixel in strip...
      strip.setPixelColor(i, strip.Color(0,   0,   255));
      strip.show();
    }

    flash = 6;

    for (int i = 0; i < flash; i++)
    {
      pixel = random(9);
      duration = random (200);
      strip.setPixelColor(pixel, strip.Color(255, 200, 200));
      strip.show();
      delay(duration);
      strip.setPixelColor(pixel, strip.Color(0, 0, 255));
      strip.show();
    }
    start = 1;
  }

  for (int i = 0; i < 9; i++) { // For each pixel in strip...
    strip.setPixelColor(i, strip.Color(0,   0,   255));
    strip.show();
  }

  flash = random(4, 8); // Choose a random number of flashes between 4 and 8
  hold = random(10000); // Choose a random time to wait between lighting displays 
  nowTime = millis(); //Store time now
  changeTime = nowTime + hold; //Set time of next display

  while (nowTime < changeTime)
  {
    nowTime = millis();
    delay(wait);
    currtouched = cap.touched(); //Check for sensor touch while waiting for changeTime
    touchSense();
    if (changeMode == 1)
    {
      changeMode = 0;
      return;
    }
  }

  for (int i = 0; i < flash; i++)
  {
    pixel = random(9); //Choose a random NeoPixel
    duration = random (300); //Choose a flash Duration
    strip.setPixelColor(pixel, strip.Color(255, 200, 200)); //Set pixel
    strip.show(); //Display changes
    delay(duration);
    strip.setPixelColor(pixel, strip.Color(0, 0, 255)); //Reset Pixel
    strip.show(); //Display changes
  }
}

void rainbow(int wait) //This mode gently fades each NeoPixel through rainbow colors
{
  for (long firstPixelHue = 0; firstPixelHue < 5 * 65536; firstPixelHue += 256) {
    for (int i = 0; i < strip.numPixels(); i++) { // For each pixel in strip...

      int pixelHue = firstPixelHue + (i * 65536L / strip.numPixels());

      strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue)));
      currtouched = cap.touched(); //Check for touch to change modes
      touchSense();
      if (changeMode == 1)
      {
        changeMode = 0;
        return; //Leave display on sensor touch
      }
    }
    strip.show(); // Update strip with new contents
    delay(wait);  // Pause for a moment
  }
}

void redMode(int wait) //Display Red
{
  for (int i = 0; i < 9; i++) { // For each pixel in strip...
    strip.setPixelColor(i, strip.Color(255, 0, 0));
    strip.show();

    currtouched = cap.touched(); //Check for senesor touch to change mode
    touchSense();
    if (changeMode == 1)
    {
      changeMode = 0;
      return;
    }
    delay(wait);                           
  }
}

void yellowMode(int wait) //Display yellow
{
  for (int i = 0; i < 9; i++) { // For each pixel in strip...
    strip.setPixelColor(i, strip.Color(255, 255, 0));
    strip.show();

    currtouched = cap.touched();//Check for senesor touch to change mode
    touchSense();
    if (changeMode == 1)
    {
      changeMode = 0;
      return;
    }
    delay(wait);                          
  }
}

void greenMode(int wait) //Display Green
{
  for (int i = 0; i < 9; i++) { // For each pixel in strip...
    strip.setPixelColor(i, strip.Color(0, 255, 0));
    strip.show();

    currtouched = cap.touched();//Check for senesor touch to change mode
    touchSense();
    if (changeMode == 1)
    {
      changeMode = 0;
      return;
    }
    delay(wait);                           
  }
}

void cyanMode(int wait) //Display Cyan (Light blue)
{
  for (int i = 0; i < 9; i++) { // For each pixel in strip...
    strip.setPixelColor(i, strip.Color(0, 255, 255));
    strip.show();

    currtouched = cap.touched();//Check for senesor touch to change mode
    touchSense();
    if (changeMode == 1)
    {
      changeMode = 0;
      return;
    }
    delay(wait);                           
  }
}

void blueMode(int wait) //Display blue
{
  for (int i = 0; i < 9; i++) { // For each pixel in strip...
    strip.setPixelColor(i, strip.Color(0, 0, 255));
    strip.show();

    currtouched = cap.touched();//Check for senesor touch to change mode
    touchSense();
    if (changeMode == 1)
    {
      changeMode = 0;
      return;
    }
    delay(wait);                           
  }
}

void purpleMode(int wait) //Display purple (which looks pink)
{
  for (int i = 0; i < 9; i++) { // For each pixel in strip...
    strip.setPixelColor(i, strip.Color(255, 0, 255));
    strip.show();

    currtouched = cap.touched();//Check for senesor touch to change mode
    touchSense();
    if (changeMode == 1)
    {
      changeMode = 0;
      return;
    }
    delay(wait);                           
  }
}

int touchSense() //Used to check for touch sensor press
{
  if (currtouched == 1)//If touch sensed
  {
    changeMode = 1;
    touchTime = millis();//log current time
    while (currtouched == 1)//wait for touch release
    {
      currtouched = cap.touched();
    }
    totalTime = millis() - touchTime;//calculate total touch time

    if (totalTime > 1000)//if touch time is greater than 1 sec - long press
    {
      state = 0; // return to mode 0 (OFF)
      Serial.print("Long press to mode: ");
      Serial.println(state);
      return;
    }
    else //Otherwise advance mode by 1
    {
      state = state + 1;
      Serial.print("Short press to mode: ");
      Serial.println(state);
      return;
    }
  }
}