#include "FastLED.h"

const byte pinSwitch = 8;

const int timeShortPress = 250;
const int timeLongPress = 350;

const byte pinData1 = 10;
const byte pinData2 = 11;
const byte pinData3 = 12;

const byte numLEDs = 16;

CRGB ledRings[3][numLEDs];

struct stateVariables
{
  byte          number;
  char          name[16];
  unsigned long interval;
  byte          ring0Colour[3];
  byte          ring1Colour[3];
  byte          ring2Colour[3];
};

stateVariables states[5] =
{
  {0, "RED",            9000, {0, 255, 192},      {0, 0, 0},      {0, 0, 0}},
  {1, "RED_YELLOW",     2000, {0, 255, 192}, {32, 255, 255},      {0, 0, 0}},
  {2, "GREEN",          6000,     {0, 0, 0},      {0, 0, 0}, {80, 255, 168}},
  {3, "YELLOW",         2000,     {0, 0, 0}, {32, 255, 255},      {0, 0, 0}},
  {4, "YELLOW_FLASHING", 600,     {0, 0, 0}, {32, 255, 255},      {0, 0, 0}}
} ;

byte lastSwitchState = HIGH;

unsigned long timePressed  = 0;
unsigned long timeReleased = 0;

unsigned long interval = 0;

bool normalMode = true;
bool flashingMode = false;

byte systemState = 0;

void setup()
{
  Serial.begin (9600);

  pinMode (pinSwitch, INPUT_PULLUP);

  pinMode(pinData1, OUTPUT);
  pinMode(pinData2, OUTPUT);
  pinMode(pinData3, OUTPUT);

  FastLED.addLeds<NEOPIXEL, pinData1>(ledRings[0], numLEDs);
  FastLED.addLeds<NEOPIXEL, pinData2>(ledRings[1], numLEDs);
  FastLED.addLeds<NEOPIXEL, pinData3>(ledRings[2], numLEDs);

  for (byte i = 0; i < 3; i++)
  {
    fill_solid(ledRings[i], numLEDs, 0);
  }
  FastLED.show();

  delay (3000);
}

void loop()
{
  checkSwitch();
  eventProcessing();
}

void eventProcessing()
{
  static unsigned long timeNow = 0;

  if (millis() - timeNow <= interval && normalMode)
  {
    return;
  }
  else if (!normalMode)
  {
    systemState = 4;
  }

  switch (systemState)
  {
    case 0:
      Serial.println (states[systemState].name);
      interval = states[systemState].interval;
      switchRings(systemState);
      systemState++;
      break;

    case 1:
      Serial.println (states[systemState].name);
      interval = states[systemState].interval;
      switchRings(systemState);
      systemState++;
      break;

    case 2:
      Serial.println (states[systemState].name);
      interval = states[systemState].interval;
      switchRings(systemState);
      systemState++;
      break;

    case 3:
      Serial.println (states[systemState].name);
      interval = states[systemState].interval;
      switchRings(systemState);
      systemState = 0;
      break;

    case 4:
      Serial.println (states[systemState].name);
      interval = states[systemState].interval;
      switchRings(systemState);
      break;
  }
  timeNow = millis();
}

void switchRings(byte state)
{
  if (normalMode)
  { 
    fill_solid(ledRings[0], numLEDs, CHSV(states[state].ring0Colour[0], states[state].ring0Colour[1], states[state].ring0Colour[2]));
    fill_solid(ledRings[1], numLEDs, CHSV(states[state].ring1Colour[0], states[state].ring1Colour[1], states[state].ring1Colour[2]));
    fill_solid(ledRings[2], numLEDs, CHSV(states[state].ring2Colour[0], states[state].ring2Colour[1], states[state].ring2Colour[2]));
  }
  else if (!normalMode)
  {
    static unsigned long timeNow = 0;
    if (millis() - timeNow >= states[systemState].interval)
    {
      if (flashingMode == true)
      {
        fill_solid(ledRings[0], numLEDs, 0);
        fill_solid(ledRings[1], numLEDs, CHSV(states[state].ring1Colour[0], states[state].ring1Colour[1], states[state].ring1Colour[2]));
        fill_solid(ledRings[2], numLEDs, 0);
        flashingMode = false;
      }
      else
      {
        fill_solid(ledRings[1], numLEDs, 0);
        flashingMode = true;
      }
      timeNow = millis();
    }
  }
  FastLED.show();
}

void checkSwitch()
{
  byte switchState = digitalRead (pinSwitch);
  if (switchState != lastSwitchState)
  {
    if (switchState == LOW)
    {
      timePressed = millis();
    }
    else
    {
      timeReleased = millis();
      unsigned long pressDuration = timeReleased - timePressed;
      if (pressDuration < timeShortPress)
      {
        Serial.print ("Flashing mode; short press milliseconds "); Serial.println (pressDuration);
        normalMode = false;
      }
      else if (pressDuration > timeLongPress )
      {
        Serial.print ("Normal mode; long press milliseconds "); Serial.println (pressDuration);
        normalMode = true;
        systemState = 0;
      }
    }
    lastSwitchState = switchState;
  }
}