/*
FastLED example code comes from the FastLED library. I am afraid I do not know who deserves that credit.

  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp32-date-time-ntp-client-server-arduino/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/


// LED initialization
#include <FastLED.h>
using namespace fl;
// How many leds in your strip?
#define NUM_LEDS 392 
// For led chips like Neopixels, which have a data line, ground, and power, you just
// need to define DATA_PIN.  For led chipsets that are SPI based (four wires - data, clock,
// ground, and power), like the LPD8806, define both DATA_PIN and CLOCK_PIN
#define DATA_PIN 4
#define CLOCK_PIN 13
// Define the array of leds
CRGB leds[NUM_LEDS];

#include <EEPROM.h>
#define EEPROM_SIZE 64

// Wifi and time initialization
#include <WiFi.h>
#include "time.h"
const char* ssid     = "UseYourNetworkNameHere";
const char* password = "UseYourPasswordHere";
const char* ntpServer = "pool.ntp.org";
const long  gmtOffset_sec = 0;
const int   daylightOffset_sec = 3600;
String colorString;
// Set web server port number to 80
WiFiServer server(80);
// Variable to store the HTTP request
String header;
// Current time
unsigned long currentTime = millis();
// Previous time
unsigned long previousTime = 0; 
// Define timeout time in milliseconds (example: 2000ms = 2s)
const long timeoutTime = 2000;

// Global variables and constants
int secondCounter = 0;
bool secondTriggered = false;
int sixtiethCounter = 0;
bool sixtiethTriggered = false;
int minuteCounter = 0;
int hourCounter = 0;
int previousHourCounter = 0;
int previousMinuteCounter = 0;
bool hourRollover = false;
bool minuteRollover = false;
long flashTimeout = 0;
int flashLength = 300;
int sixtiethColor = 64;
int secondColor = 200;
int minuteColor = 255;
int hourColor = 200;
byte timeZone = 0;
const int timeZoneEEPROMAddress = 0;
int expiredMinuteColor = 100;
int currentMode = 1;
const int modeEEPROMAddress = 2;
int LEDBrightness = 1;
int colorScheme = 0;

/*
  NOTE: The serialEvent() feature is not available on the Leonardo, Micro, or
  other ATmega32U4 based boards.
  created 9 May 2011
  by Tom Igoe
  This example code is in the public domain.
  https://www.arduino.cc/en/Tutorial/BuiltInExamples/SerialEvent
*/

String inputString = "";         // a String to hold incoming data
bool stringComplete = false;  // whether the string is complete


int colorCounter = 0;

const byte quadrantCount = 4;
const byte quadrantSize = 98;
const byte ringCount = 10;
const byte ringSize[ringCount] = {1, 3, 5, 7, 9, 10, 13, 15, 16, 19};
const int ringAddress[ringCount][19] = {
  {0},
  {1, 2, 3},
  {4, 5, 6, 7, 8},
  {9, 10, 11, 12, 13, 14, 15},
  {16, 17, 18, 19, 20, 21, 22, 23, 24},
  {25, 26, 27, 28, 29, 30, 31, 32, 33, 34},
  {35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47},
  {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62},
  {63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78},
  {79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97}
};



void setup(){
  // Serial setup
	Serial.begin(115200);
  Serial.print(F("\n\n\nWelcome to Vibe Clock\n"));
  printHelpMenu();
  // reserve 200 bytes for the inputString:
  inputString.reserve(200);

  // FastLED setup
	FastLED.addLeds<WS2812,DATA_PIN,RGB>(leds,NUM_LEDS);
	FastLED.setBrightness(LEDBrightness);
  clearLEDs();
  
  circleBurst();
  
  if (!EEPROM.begin(EEPROM_SIZE)){
    Serial.println(F("failed to initialise EEPROM"));
  }
  timeZone = EEPROM.read(timeZoneEEPROMAddress);
  if (timeZone > 24){
    timeZone = 0;
  }
  currentMode = EEPROM.read(modeEEPROMAddress);
  
  Serial.print(F("Time Zone: "));
  Serial.print(timeZone);
  Serial.print("\n");
  
 // Wi-Fi setup
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected.");
  // Init and get the time
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  printLocalTime();
  // Print local IP address and start web server
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  server.begin();
  
  clearLEDs();
}

void loop() {
  gatherSerialData();
  currentModeSwitch();
  WiFiClient client = server.available();   // Listen for incoming clients
  if (client){
    currentTime = millis();
    previousTime = currentTime;
    Serial.println("New Client.");          // print a message out in the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
    while (client.connected() && currentTime - previousTime <= timeoutTime) {  // loop while the client's connected
      currentTime = millis();
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
        Serial.write(c);                    // print it out the serial monitor
        header += c;
        if (c == '\n') {                    // if the byte is a newline character
          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            // and a content-type so the client knows what's coming, then a blank line:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();
            
            // Do something with the incoming data
            if(header.indexOf("GET /mode") >= 0) {
              currentMode++;
              if(currentMode > 3){
                currentMode = 0;
                clearLEDs();
              }
              EEPROM.write(modeEEPROMAddress, currentMode);
              EEPROM.commit();
            }else if(header.indexOf("GET /brightness") >= 0) {
              LEDBrightness = LEDBrightness + 16;
              if(LEDBrightness == 256){
                LEDBrightness = 255;
              }
              if(LEDBrightness > 256){
                LEDBrightness = 1;
              }
              FastLED.setBrightness(LEDBrightness);
              Serial.print("Brightness:\t");
              Serial.print(LEDBrightness);
              Serial.print("\n");
            }else if(header.indexOf("GET /timezone") >= 0) {
              timeZone++;
              if(timeZone > 23){
                timeZone = 0;
              }
              EEPROM.write(timeZoneEEPROMAddress, timeZone);
              EEPROM.commit();
              Serial.print("Time zone:\t");
              Serial.print(timeZone);
              Serial.print("\n");
            }else if(header.indexOf("GET /scheme") >= 0) {
              colorScheme++;
              if(colorScheme > 3){
                colorScheme = 0;
              }
              if(colorScheme == 0){
                secondColor = 200;
                minuteColor = 255;
                expiredMinuteColor = 100;
                hourColor = 65;
              }else if(colorScheme == 1){
                secondColor = 200;
                minuteColor = 231;
                expiredMinuteColor = 135;
                hourColor = 65;
              }else if(colorScheme == 2){
                secondColor = 200;
                minuteColor = 88;
                expiredMinuteColor = 75;
                hourColor = 65;
              }else if(colorScheme == 3){
                secondColor = 200;
                minuteColor = 160;
                expiredMinuteColor = 220;
                hourColor = 65;
              }
            }else if(header.indexOf("GET /prandom") >= 0) {
              secondColor = random(0, 255);
              minuteColor = random(0, 255);
              hourColor = random(0, 255);
              expiredMinuteColor = random(0, 255);
            }
            
            // Display the HTML web page
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<link rel=\"icon\" href=\"data:,\">");
            // CSS to style the on/off buttons 
            // Feel free to change the background-color and font-size attributes to fit your preferences
            client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
            client.println(".button { background-color: #4CAF50; border: none; color: white; padding: 16px 40px;");
            client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
            client.println(".button2 {background-color: #555555;}</style></head>");
            
            // Web Page Heading
            client.println("<body><h1>Vibe Clock Settings</h1>");
            
            // Display the current mode 
            String currentModeString = String(currentMode);
            client.println("<p>Bezel " + currentModeString + "</p>");
            // Show the "mode" button
            client.println("<p><a href=\"/mode\"><button class=\"button\">Bezel</button></a></p>");
            
            // Display the current brightness 
            String brightnessString = String(LEDBrightness/16);
            client.println("<p><br />LED Level " + brightnessString + " / 15</p>");
            // Show the "Brightness" button
            client.println("<p><a href=\"/brightness\"><button class=\"button\">Brightness</button></a></p>");
            
            // Change between pre-made color schemes
            String colorSchemeString = String(colorScheme);
            client.println("<p><br />Color Scheme " + colorSchemeString + "</p>");
            // Show the "Colors" button
            client.println("<p><a href=\"/scheme\"><button class=\"button\">Colors</button></a></p>");
            
            // Randomize the colors
            client.println("<p><br />Pseudo-randomize colors</p>");
            // Show the "PRandom" button
            client.println("<p><a href=\"/prandom\"><button class=\"button\">PRandom</button></a></p>");
            
            // Display the current brightness 
            String timeZoneString = String(timeZone);
            client.println("<p><br />Time zone " + timeZoneString + " / 23</p>");
            // Show the "Time Zone" button
            client.println("<p><a href=\"/timezone\"><button class=\"button\">Time Zone</button></a></p>");
            
               
            client.println("</body></html>");
            
            // The HTTP response ends with another blank line
            client.println();
            // Break out of the while loop
            break;
          } else { // if you got a newline, then clear currentLine
            currentLine = "";
          }
        } else if (c != '\r') {  // if you got anything else but a carriage return character,
          currentLine += c;      // add it to the end of the currentLine
        }
      }
    }
    // Clear the header variable
    header = "";
    // Close the connection
    client.stop();
    Serial.println("Client disconnected.");
    Serial.println("");
  }
}



/*
  SerialEvent occurs whenever a new data comes in the hardware serial RX. This
  routine is run between each time loop() runs, so using delay inside loop can
  delay response. Multiple bytes of data may be available.
*/
void serialEvent(){
  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    // add it to the inputString:
    inputString += inChar;
    // if the incoming character is a newline, set a flag so the main loop can
    // do something about it:
    if (inChar == '\n') {
      stringComplete = true;
    }
  }
}

void printLocalTime(){
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo)){
    Serial.println("Failed to obtain time");
    return;
  }
  Serial.print(&timeinfo, "%A, %B %d %Y %H:%M:%S");
  Serial.print("\n");
  Serial.print(F("ISO Format date\t"));
  Serial.print(&timeinfo, "%Y-%m-%d");
  Serial.print("\n");
  Serial.print(F("ISO Format time\tT"));
  Serial.print(&timeinfo, "%H:%M:%S%z");
  Serial.print("\n");
  //http://www.cplusplus.com/reference/ctime/strftime/
}


void gatherSerialData(){
  if (stringComplete) {
    // Remove the newline or carriage return from inputString
    inputString.trim();
    String firstEleven = inputString.substring(0,11);
    String firstTen = inputString.substring(0,10);
    String firstNine = inputString.substring(0,9);
    String colorNumerals = inputString.substring(11,15);
    String brightnessNumerals = inputString.substring(10,13);
    String timeZoneNumerals = inputString.substring(9,12);
    if(firstEleven == F("secondColor") || firstEleven == F("second Colo") || firstEleven == F("Second Colo") || firstEleven == F("secondcolor") || firstEleven == F("second colo")){
      
      secondColor = colorNumerals.toInt();
      Serial.print(F("Second color:\t"));
      Serial.print(secondColor);
      Serial.print("\n");
    }else if(firstEleven == F("minuteColor") || firstEleven == F("minute Colo") || firstEleven == F("Minute Colo") || firstEleven == F("minutecolor") || firstEleven == F("minute colo")){
      
      minuteColor = colorNumerals.toInt();
      Serial.print(F("Minute color:\t"));
      Serial.print(minuteColor);
      Serial.print("\n");
    }else if(firstEleven == F("expMinColor") || firstEleven == F("expMin Colo") || firstEleven == F("ExpMin Colo") || firstEleven == F("expmincolor") || firstEleven == F("expmin colo")){
      
      expiredMinuteColor = colorNumerals.toInt();
      Serial.print(F("Expired minute color:\t"));
      Serial.print(expiredMinuteColor);
      Serial.print("\n");
    }else if(firstEleven == F("hrhandcolor") || firstEleven == F("hour hand c") || firstEleven == F("Hour hand c") || firstEleven == F("Hour Hand C") || firstEleven == F("HRHandColor") || firstEleven == F("HrHandColor") || firstEleven == F("HrhandColor") || firstEleven == F("HRHandcolor") || firstEleven == F("HrHandColor")){
      
      hourColor = colorNumerals.toInt();
      Serial.print(F("Hour hand color:\t"));
      Serial.print(hourColor);
      Serial.print("\n");
    }else if(firstTen == F("Brightness") || firstTen == F("brightness")){
      LEDBrightness = brightnessNumerals.toInt();
      FastLED.setBrightness(LEDBrightness);
    }else if(inputString == F("Color") || inputString == F("color")){
      Serial.print(F("Second hand color    :\t"));
      Serial.print(secondColor);
      Serial.print(F("\nMinute hand color    :\t"));
      Serial.print(minuteColor);
      Serial.print(F("\nExpired minutes color:\t"));
      Serial.print(expiredMinuteColor);
      Serial.print(F("\nHour color           :\t"));
      Serial.print(hourColor);
      Serial.print("\n");
    }else if(inputString == F("ResetColor") || inputString == F("Reset Color") || inputString == F("resetcolor") || inputString == F("reset color")){
      secondColor = 200;
      minuteColor = 255;
      expiredMinuteColor = 100;
      hourColor = 65;
    }else if(inputString == F("m0") || inputString == F("M0") || inputString == F("mode 0") || inputString == F("Mode 0")){
      currentMode = 0;
      Serial.print(F("Mode 0 - no bezel activity.\n"));
      EEPROM.write(modeEEPROMAddress, currentMode);
      EEPROM.commit();
    }else if(inputString == F("m1") || inputString == F("M1") || inputString == F("mode 1") || inputString == F("Mode 1")){
      currentMode = 1;
      Serial.print(F("Mode 1 - flash the bezel every hour.\n"));
      EEPROM.write(modeEEPROMAddress, currentMode);
      EEPROM.commit();
    }else if(inputString == F("m2") || inputString == F("M2") || inputString == F("mode 2") || inputString == F("Mode 2")){
      currentMode = 2;
      Serial.print(F("Mode 2 - flash the bezel every minute.\n"));
      EEPROM.write(modeEEPROMAddress, currentMode);
      EEPROM.commit();
    }else if(inputString == F("m3") || inputString == F("M3") || inputString == F("mode 3") || inputString == F("Mode 3")){
      currentMode = 3;
      Serial.print(F("Mode 3 - toggle the bezel rings every second.\n"));
      EEPROM.write(modeEEPROMAddress, currentMode);
      EEPROM.commit();
    }else if(inputString == F("mode") || inputString == F("Mode") || inputString == F("MODE")){
      Serial.print(F("Mode "));
      Serial.print(currentMode);
      Serial.print("\n");
      EEPROM.write(modeEEPROMAddress, currentMode);
      EEPROM.commit();
    }else if(inputString == F("h") || inputString == F("H") || inputString == F("?")){
      printHelpMenu();
    }else if(inputString == F("time") || inputString == F("Time") || inputString == F("TIME")){
      printLocalTime();
    }else if(firstNine == F("Time zone") || firstNine == F("Time Zone") || firstNine == F("time zone") || firstNine == F("time Zone") || firstNine == F("TIME ZONE")){
      timeZone = timeZoneNumerals.toInt();
      EEPROM.write(timeZoneEEPROMAddress, timeZone);
      EEPROM.commit();
      Serial.print(F("Time Zone: "));
      byte funTempTimeZone = EEPROM.read(timeZoneEEPROMAddress);
      Serial.print(funTempTimeZone);
      Serial.print("\n");
    }else{
      Serial.print(F("!!!!!!!!!!!!!!\nUnrecognized:\t"));
      Serial.print(inputString);
      printHelpMenu();
    }
    // clear the string:
    inputString = "";
    stringComplete = false;
  }
}

void printHelpMenu(){
  Serial.print("\n");
  Serial.print(F("?          \tShow help menu\n"));
  Serial.print(F("Time       \tShow current time\n"));
  Serial.print(F("SecondColor\tFollow with a number, no spaces, 0-255 to change the second hand color\n"));
  Serial.print(F("MinuteColor\tFollow with a number, no spaces, 0-255 to change the minutes color\n"));
  Serial.print(F("ExpMinColor\tFollow with a number, no spaces, 0-255 to change the expired minutes color\n"));
  Serial.print(F("hrhandcolor\tFollow with a number, no spaces, 0-255 to change the hour hand minutes color\n"));
  Serial.print(F("Reset color\tUse the default colors\n"));
  Serial.print(F("Brightness \tFollow with a number, 0-255, to set the brightness\n"));
  Serial.print(F("Time Zone  \tFollow with a number, 0-23, to set the time zone correction\n"));
  Serial.print(F("Color      \tPrint the colors in use\n"));
  Serial.print(F("Mode 0     \tMode 0: Turn off the LEDs\n"));
  Serial.print(F("Mode 1     \tMode 1: Wipe blue to red\n"));
  Serial.print(F("Mode 2     \tMode 2: Wipe off to red\n"));
  Serial.print(F("Mode 3     \tMode 3: Wipe green to off\n"));
  Serial.print("\n");
}


void updateClockFace(){
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo)){
    Serial.println("Failed to obtain time");
    return;
  }
  char funCharSeconds[3];
  strftime(funCharSeconds,3, "%S", &timeinfo);
  secondCounter = atoi(funCharSeconds);
  char funCharMinutes[3];
  strftime(funCharMinutes,3, "%M", &timeinfo);
  minuteCounter = atoi(funCharMinutes);
  char funCharHours[3];
  strftime(funCharHours,3, "%H", &timeinfo);
  hourCounter = atoi(funCharHours);
  
  if(previousHourCounter != hourCounter){
    hourRollover = true;
    flashTimeout = millis() + flashLength;
  }
  previousHourCounter = hourCounter;
  if((previousMinuteCounter != minuteCounter)){
    minuteRollover = true;
    flashTimeout = millis() + flashLength;
  }
  previousMinuteCounter = minuteCounter;
  
  if(millis() > flashTimeout){
    hourRollover = false;
    minuteRollover = false;
  }
  
  if((currentMode == 0)){
    // No bezel activity
    fillCircles();
    minuteFill();
    hourHand();
    if((millis()%10000 == 0)){
      clearBezel();
    }
  }
  if(currentMode == 1){
    // Flash the bezel every hour
    fillCircles();
    minuteFill();
    hourHand();
    if(hourRollover){
      innerBezel(65);
      outerBezel(65);
    }else{
      clearBezel();
    }
  }
  if(currentMode == 2){
    // Flash the bezel every minute
    fillCircles();
    minuteFill();
    hourHand();
    if(minuteRollover){
      innerBezel(65);
      outerBezel(65);
    }else{
      clearBezel();
    }
  }
  if(currentMode == 3){
    // Toggle the bezel rings every second
    fillCircles();
    minuteFill();
    hourHand();
    clearBezel();
    if((millis()%2000 < 1000)){
      innerBezel(65);
    }else{
      outerBezel(65);
    }
  }
  FastLED.show();
}

void clearBezel(){
  // i is the quadrant
  // k is the inner and outer rings
  // n is the ring in question
  for(int i=0;i<4;i++){
    for(int k=8;k<10;k++){
      for(int n=0;n<ringSize[k];n++){
        int funLEDAddress = ringAddressLocation(k, n);
        leds[funLEDAddress + i*98] = CHSV(0, 0, 0);
      }
    }
  }
}

void innerBezel(int funColor){
  // i is the quadrant
  // k is the inner and outer rings
  // n is the ring in question
  for(int i=0;i<4;i++){
    for(int k=8;k<9;k++){
      for(int n=0;n<ringSize[k];n++){
        int funLEDAddress = ringAddressLocation(k, n);
        leds[funLEDAddress + i*98] = CHSV(funColor, 255, 255);
      }
    }
  }
}

void outerBezel(int funColor){
  // i is the quadrant
  // k is the inner and outer rings
  // n is the ring in question
  for(int i=0;i<4;i++){
    for(int k=9;k<10;k++){
      for(int n=0;n<ringSize[k];n++){
        int funLEDAddress = ringAddressLocation(k, n);
        leds[funLEDAddress + i*98] = CHSV(funColor, 255, 255);
      }
    }
  }
}

void hourHand(){
  struct tm timeinfo;
  char funCharHours[3];
  strftime(funCharHours,3, "%H", &timeinfo);
  hourCounter = atoi(funCharHours);
  hourCounter = hourCounter + timeZone;
  while(hourCounter>=12){
    hourCounter = hourCounter - 12;
  }
  while(hourCounter<0){
    hourCounter = hourCounter + 12;
  }
  
  if((hourCounter == 0) || (hourCounter == 3) || (hourCounter == 6) || (hourCounter == 9) || (hourCounter == 12)){
    int funTimeMultiplier = hourCounter - 0;
    funTimeMultiplier = funTimeMultiplier/3;
    funTimeMultiplier = funTimeMultiplier * 98;
    leds[0 + funTimeMultiplier] = CHSV(hourColor, 255, 255);
    leds[1 + funTimeMultiplier] = CHSV(hourColor, 255, 255);
    leds[4 + funTimeMultiplier] = CHSV(hourColor, 255, 255);
    leds[9 + funTimeMultiplier] = CHSV(hourColor, 255, 255);
    leds[16 + funTimeMultiplier] = CHSV(hourColor, 255, 255);
    
  }
  if((hourCounter == 1) || (hourCounter == 4) || (hourCounter == 7) || (hourCounter == 10)){
    int funTimeMultiplier = hourCounter - 1;
    funTimeMultiplier = funTimeMultiplier/3;
    funTimeMultiplier = funTimeMultiplier * 98;
    leds[0 + funTimeMultiplier] = CHSV(hourColor, 255, 255);
    leds[11 + funTimeMultiplier] = CHSV(hourColor, 255, 255);
    leds[18 + funTimeMultiplier] = CHSV(hourColor, 255, 255);
    leds[19 + funTimeMultiplier] = CHSV(hourColor, 255, 255);
  }
  if((hourCounter == 2) || (hourCounter == 5) || (hourCounter == 8) || (hourCounter == 11)){
    int funTimeMultiplier = hourCounter - 2;
    funTimeMultiplier = funTimeMultiplier/3;
    funTimeMultiplier = funTimeMultiplier * 98;
    leds[0 + funTimeMultiplier] = CHSV(hourColor, 255, 255);
    leds[13 + funTimeMultiplier] = CHSV(hourColor, 255, 255);
    leds[21 + funTimeMultiplier] = CHSV(hourColor, 255, 255);
    leds[22 + funTimeMultiplier] = CHSV(hourColor, 255, 255);
  }
}

void minuteFill(){
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo)){
    Serial.println("Failed to obtain time");
    return;
  }
  char funCharMinutes[3];
  strftime(funCharMinutes,3, "%M", &timeinfo);
  minuteCounter = atoi(funCharMinutes);
  
  for(int i=0;i<=7;i++){
    float funMinuteFloat = (ringSize[i] / 15.0) * minuteCounter;
    int funMinuteInt = funMinuteFloat;
    int funLEDAddress = ringAddressLocation(i, funMinuteInt);
    for(int k=0; k<=funMinuteInt; k++){
      funLEDAddress = ringAddressLocation(i, k);
      leds[funLEDAddress] = CHSV(expiredMinuteColor, 255, 255);
    }
  }
}



void clearLEDs(){
  for (int i=0; i < NUM_LEDS; i++){
    leds[i] = CHSV(0, 0, 0);
  }
  FastLED.show();
}

void currentModeSwitch(){
  switch(currentMode){
    case 0:
      updateClockFace();
      break;
    case 1:
      updateClockFace();
      break;
    case 2:
      updateClockFace();
      break;
    case 3:
      updateClockFace();
      break;
    default:
      break;
  }
}

void circleBurst(){
  for(int i=0;i<ringCount;i++){
    for(int k=0;k<ringSize[i];k++){
      for(int n=0;n<quadrantCount;n++){
        leds[ringAddress[i][k] + quadrantSize*n] = CHSV(colorCounter, 255, 255);
      }
    }
    incrementColor(255/10);
    FastLED.show();
  }
}

void incrementColor(int funIncrement){
  if(funIncrement == 0){
    funIncrement = 1;
  }
  colorCounter = colorCounter + funIncrement;
  if(colorCounter>255){
    colorCounter = 0;
  }
}


void OBSOLETE01secondsLine(){
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo)){
    Serial.println("Failed to obtain time");
    return;
  }
  char funCharSeconds[3];
  strftime(funCharSeconds,3, "%S", &timeinfo);
  secondCounter = atoi(funCharSeconds);
  int funIntSeconds00 = (funCharSeconds[0] - '0');
  int funIntSeconds01 = (funCharSeconds[1] - '0');
  int funIntSeconds = funIntSeconds00*10 + funIntSeconds01;
  Serial.print("Seconds: ");
  Serial.print(funIntSeconds);
  Serial.print("\n");
  
}

void secondsLine(){
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo)){
    Serial.println(F("Failed to obtain time"));
    return;
  }
  char funCharSeconds[3];
  strftime(funCharSeconds,3, "%S", &timeinfo);
  secondCounter = atoi(funCharSeconds);
  
  int funLEDAddress = ringAddressLocation(7, secondCounter);
  int funPreviousLED = ringAddressLocation(7, secondCounter-1);
  leds[funPreviousLED] = CHSV(secondColor, 0, 0);
  leds[funLEDAddress] = CHSV(secondColor, 255, 255);
  FastLED.show();
}

void fillCircles(){
  for(int i=0;i<4;i++){
    for(int k=0;k<63;k++){
      leds[k + i*98] = CHSV(minuteColor, 255, 255);
    }
  }
}

int ringAddressLocation(int funRing, int funRotation){
  int funReturnAddress = 999;
  if((funRing < 0) || (funRing > ringCount) || (funRotation < -1) || (funRotation > 19*4)){
    return funReturnAddress;
  }
  if(funRotation == -1){
    funReturnAddress = ringAddress[funRing][ringSize[funRing] - 1] + quadrantSize*3;
    return funReturnAddress;
  }
  int funQuadrant = funRotation / ringSize[funRing];
  if(funQuadrant >= quadrantCount){
    return 999;
  }
  funReturnAddress = ringAddress[funRing][funRotation - (ringSize[funRing] * funQuadrant)] + (98 * funQuadrant);
  return funReturnAddress;
}

void secondsFill(){
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo)){
    Serial.println(F("Failed to obtain time"));
    return;
  }
//  char funCharMinutes[3];
//  strftime(funCharMinutes,3, "%M", &timeinfo);
//  minuteCounter = atoi(funCharMinutes);
  char funCharSeconds[3];
  strftime(funCharSeconds,3, "%S", &timeinfo);
  secondCounter = atoi(funCharSeconds);
  char funCharHours[3];
  strftime(funCharHours,3, "%H", &timeinfo);
  hourCounter = atoi(funCharHours);
  if(previousHourCounter != hourCounter){
    // Use this to update the hour hand position
    Serial.print("Hour: ");
    Serial.print(hourCounter);
    Serial.print("\n");
  }
  previousHourCounter = hourCounter;

  if(secondCounter == 0){
    fillCircles();
  }
  
  for(int i=0;i<=7;i++){
    float funSecondFloat = (ringSize[i] / 15.0) * secondCounter;
    int funSecondInt = funSecondFloat;
    
    int funLEDAddress = ringAddressLocation(i, funSecondFloat);
    int funPreviousLED = ringAddressLocation(i, funSecondFloat-1);
//    leds[funPreviousLED] = CHSV(expiredMinuteColor, 255, 255);
    leds[funLEDAddress] = CHSV(expiredMinuteColor, 255, 255);
  }
  FastLED.show();
}
