#include <LCD_I2C.h>
#include "BluetoothSerial.h"
#include <FastLED.h>

LCD_I2C lcd(0x27); // Default address of most PCF8574 modules, change according

#define PIR_PIN     17
#define LED_PIN     16
#define NUM_LEDS    6
#define BRIGHTNESS_4  64
#define BRIGHTNESS_3  48
#define BRIGHTNESS_2  32
#define BRIGHTNESS_1  16
#define BRIGHTNESS_0  0
#define LED_TYPE    WS2811
#define COLOR_ORDER GRB
CRGB I_LEDS[NUM_LEDS];
TBlendType currentBlending;

#define UPDATES_PER_SECOND 100

#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif

BluetoothSerial SerialBT;
boolean confirmRequestPending = true;

unsigned long S_UPTIME = 0;
unsigned long S_LAST_BT_CMD = 0;
unsigned long S_LAST_MOTION = 0;
unsigned long P_LOOP_25MS = 0;
unsigned long P_LOOP_50MS = 0;
unsigned long P_LOOP_100MS = 0;
unsigned long P_LOOP_250MS = 0;
unsigned long P_LOOP_500MS = 0;
unsigned long P_LOOP_1S = 0;
unsigned long P_LOOP_2S = 0;
unsigned long P_LOOP_5S = 0;
unsigned long P_LOOP_10S = 0;
unsigned long P_LOOP_30S = 0;
String V_LCD_Line0S = "...";
String V_LCD_Line0W = "...";
String V_LCD_Line0C = "...";
String V_LCD_Line1S = "...";
String V_LCD_Line1W = "...";
String V_LCD_Line1C = "...";
bool S_SETUP_OK = false;
bool S_LOOPING = false;
byte P_Status_I = 0;
byte P_Status_C = 0;
byte P_Status_W = 0;
byte P_Status_S = 0;



void setup()
{
  S_UPTIME = millis();

  Serial.begin(115200);

  FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(I_LEDS, NUM_LEDS).setCorrection( TypicalLEDStrip );
  FastLED.setBrightness(BRIGHTNESS_4);

  for (int i = 0; i < NUM_LEDS; i++) {
    I_LEDS[i] = CRGB::Black;
  }

  SerialBT.begin("Jeann Lab"); //Bluetooth device name
  Serial.println("The device started, now you can pair it with bluetooth!");

  lcd.begin(); // If you are using more I2C devices using the Wire library use lcd.begin(false)
  // this stop the library(LCD_I2C) from calling Wire.begin()

  V_LCD_Line0S = "Jeann's Lab";
  V_LCD_Line1S = "Loading...";

  lcd.setCursor(0, 0);
  lcd.print(V_LCD_Line0S);

  lcd.setCursor(0, 1);
  lcd.print(V_LCD_Line1S);

  I_LEDS[0] = CRGB::Red;
  I_LEDS[1] = CRGB::Yellow;
  I_LEDS[2] = CRGB::Green;
  I_LEDS[3] = CRGB::Cyan;
  I_LEDS[4] = CRGB::Blue;
  I_LEDS[5] = CRGB::Purple;

  FastLED.show();
  FastLED.delay(1000 / UPDATES_PER_SECOND);

  pinMode(PIR_PIN, INPUT);

  S_SETUP_OK = true;
}

void loop()
{
  S_UPTIME = millis();

  if (S_UPTIME > 5000 && S_LOOPING == false)
  {
    SetStatusS("S0");

    S_LOOPING = true;
  }
  else
  {

    if (S_UPTIME - P_LOOP_100MS > 100)
    {
      P_LOOP_100MS = S_UPTIME;
    }

    if (S_UPTIME - P_LOOP_250MS > 250)
    {
      P_LOOP_250MS = S_UPTIME;
    }

    if (S_UPTIME - P_LOOP_500MS > 500)
    {
      P_LOOP_500MS = S_UPTIME;

      I_PIR_Loop();

      if (S_LAST_MOTION > 0)
      {
        if (S_UPTIME - S_LAST_MOTION < 10000)
        {
          FastLED.setBrightness(BRIGHTNESS_3);
          lcd.backlight();
        }
        else if (S_UPTIME - S_LAST_MOTION < 20000)
        {
          FastLED.setBrightness(BRIGHTNESS_2);
          lcd.backlight();
        }
        else if ((P_Status_S) > 0 || (P_Status_W > 0) || (P_Status_C > 0))
        {
          FastLED.setBrightness(BRIGHTNESS_1);
          lcd.backlight();
        }
        else
        {
          FastLED.setBrightness(BRIGHTNESS_0);
          lcd.noBacklight();
        }


      }
      else
      {
        if (S_UPTIME > 20000)
        {
          if ((P_Status_S) > 0 || (P_Status_W > 0) || (P_Status_C > 0))
          {
            FastLED.setBrightness(BRIGHTNESS_1);
            lcd.backlight();
          }
          else
          {
            FastLED.setBrightness(BRIGHTNESS_0);
            lcd.noBacklight();
          }
        }
      }
    }
  }

  if (S_UPTIME - P_LOOP_1S > 1000)
  {
    P_LOOP_1S = S_UPTIME;
  }

  if (S_UPTIME - P_LOOP_2S > 2500)
  {
    P_LOOP_2S = S_UPTIME;

    if (P_Status_I == 1)
    {
      DisplayStatusW();
    }
    else if (P_Status_I == 2)
    {
      DisplayStatusC();
    }
    else
    {
      DisplayStatusS();
    }
  }

  if (S_UPTIME - P_LOOP_5S > 5000)
  {
    P_LOOP_5S = S_UPTIME;
  }

  if (S_UPTIME - P_LOOP_10S > 10000)
  {
    P_LOOP_10S = S_UPTIME;


  }

  if (S_UPTIME - P_LOOP_30S > 30000)
  {
    P_LOOP_30S = S_UPTIME;
  }

  I_Serial_Loop();
  I_BTS_Loop();

  delay(20);
}


void I_PIR_Loop()
{
  int t_reading = digitalRead(PIR_PIN);

  if (t_reading > 0)
  {
    if (S_UPTIME - S_LAST_MOTION > 5000)
    {
      Serial.println("PIR: Motion!");
      SerialBT.println("M1");
    }

    if (S_UPTIME - S_LAST_MOTION > 1000)
    {
      S_LAST_MOTION = S_UPTIME;
    }
  }
}

void I_Serial_Loop()
{
  if (Serial.available()) {
    String t_Msg = "";

    while (Serial.available())
    {
      t_Msg += (char)Serial.read();
    }

    t_Msg.trim();

    if (t_Msg[0] == 'S')
    {
      SetStatusS(t_Msg);
    }
    else  if (t_Msg[0] == 'W')
    {
      SetStatusW(t_Msg);
    }
    else if (t_Msg[0] == 'C')
    {
      SetStatusC(t_Msg);
    }
    else if (t_Msg[0] == 'R')
    {
      ResetStatus(t_Msg);
    }
    
    Serial.print("S0 Rx << : ");
    Serial.println(t_Msg);
  }
}


void I_BTS_Loop()
{
  if (SerialBT.available()) {
    String t_Msg = "";

    while (SerialBT.available())
    {
      t_Msg += (char)SerialBT.read();
    }

    t_Msg.trim();

    if (t_Msg[0] == 'S')
    {
      SetStatusS(t_Msg);
    }
    else  if (t_Msg[0] == 'W')
    {
      SetStatusW(t_Msg);
    }
    else if (t_Msg[0] == 'C')
    {
      SetStatusC(t_Msg);
    }
    else if (t_Msg[0] == 'R')
    {
      ResetStatus(t_Msg);
    }

    Serial.print("BT Rx << : ");
    Serial.println(t_Msg);
  }
}

void SetStatusS(String LCD_Msg)
{
  S_LAST_BT_CMD = S_UPTIME;

  if (LCD_Msg[1] == '0')
  {
    P_Status_S = 0;
  }
  else if (LCD_Msg[1] == '1')
  {
    P_Status_S = 1;
  }
  else if (LCD_Msg[1] == '2')
  {
    P_Status_S = 2;
  }
  else if (LCD_Msg[1] == '3')
  {
    P_Status_S = 3;
  }
  else if (LCD_Msg[1] == '4')
  {
    P_Status_S = 4;
  }
  else if (LCD_Msg[1] == '5')
  {
    P_Status_S = 5;
  }
  else if (LCD_Msg[1] == '6')
  {
    P_Status_S = 6;
  }
}

void SetStatusW(String LCD_Msg)
{
  S_LAST_BT_CMD = S_UPTIME;

  if (LCD_Msg[1] == '0')
  {
    P_Status_W = 0;
  }
  else if (LCD_Msg[1] == '1')
  {
    P_Status_W = 1;
  }
  else if (LCD_Msg[1] == '2')
  {
    P_Status_W = 2;
  }
}

void SetStatusC(String LCD_Msg)
{
  S_LAST_BT_CMD = S_UPTIME;

  if (LCD_Msg[1] == '0')
  {
    P_Status_C = 0;
  }
  else if (LCD_Msg[1] == '1')
  {
    P_Status_C = 1;
  }
}

void ResetStatus(String LCD_Msg)
{
  S_LAST_BT_CMD = S_UPTIME;

  if (LCD_Msg[1] == '0')
  {
    P_Status_S = 0;
  }
  else if (LCD_Msg[1] == '1')
  {
    P_Status_S = 6;
  }

  P_Status_W = 0;
  P_Status_C = 0;
}

void DisplayStatusS()
{
  if (P_Status_S == 0)
  {
    V_LCD_Line0S = "Closed";
    V_LCD_Line1S = "......";
    I_LEDS[0] = CRGB::White;
    I_LEDS[1] = CRGB::White;
    I_LEDS[2] = CRGB::White;
    I_LEDS[3] = CRGB::White;
    I_LEDS[4] = CRGB::White;
    I_LEDS[5] = CRGB::White;
  }
  else if (P_Status_S == 1)
  {
    V_LCD_Line0S = "Silence Please:";
    V_LCD_Line1S = "In meeting...";
    I_LEDS[0] = CRGB::Red;
    I_LEDS[1] = CRGB::Red;
    I_LEDS[2] = CRGB::Red;
    I_LEDS[3] = CRGB::Red;
    I_LEDS[4] = CRGB::Red;
    I_LEDS[5] = CRGB::Red;
  }
  else if (P_Status_S == 2)
  {
    V_LCD_Line0S = "Focusing:";
    V_LCD_Line1S = "Achieving flow";
    I_LEDS[0] = CRGB::Yellow;
    I_LEDS[1] = CRGB::Yellow;
    I_LEDS[2] = CRGB::Yellow;
    I_LEDS[3] = CRGB::Yellow;
    I_LEDS[4] = CRGB::Yellow;
    I_LEDS[5] = CRGB::Yellow;
  }
  else if (P_Status_S == 3)
  {
    V_LCD_Line0S = "Meditating:";
    V_LCD_Line1S = "Enlightening";
    I_LEDS[0] = CRGB::Cyan;
    I_LEDS[1] = CRGB::Cyan;
    I_LEDS[2] = CRGB::Cyan;
    I_LEDS[3] = CRGB::Cyan;
    I_LEDS[4] = CRGB::Cyan;
    I_LEDS[5] = CRGB::Cyan;
  }
  else if (P_Status_S == 4)
  {
    V_LCD_Line0S = "Relaxing:";
    V_LCD_Line1S = "Hobbies";
    I_LEDS[0] = CRGB::Cyan;
    I_LEDS[1] = CRGB::Green;
    I_LEDS[2] = CRGB::Green;
    I_LEDS[3] = CRGB::Green;
    I_LEDS[4] = CRGB::Green;
    I_LEDS[5] = CRGB::Cyan;
  }
  else if (P_Status_S == 5)
  {
    V_LCD_Line0S = "Music and";
    V_LCD_Line1S = "chilling...";
    I_LEDS[0] = CRGB::Green;
    I_LEDS[1] = CRGB::Green;
    I_LEDS[2] = CRGB::Green;
    I_LEDS[3] = CRGB::Green;
    I_LEDS[4] = CRGB::Green;
    I_LEDS[5] = CRGB::Green;
  }
  else if (P_Status_S == 6)
  {
    V_LCD_Line0S = "Open";
    V_LCD_Line1S = ".......";
    I_LEDS[0] = CRGB::White;
    I_LEDS[1] = CRGB::Cyan;
    I_LEDS[2] = CRGB::Green;
    I_LEDS[3] = CRGB::Green;
    I_LEDS[4] = CRGB::Cyan;
    I_LEDS[5] = CRGB::White;
  }

  lcd.clear();

  lcd.setCursor(0, 0);
  lcd.print(V_LCD_Line0S);

  lcd.setCursor(0, 1);
  lcd.print(V_LCD_Line1S);

  FastLED.show();
  FastLED.delay(1000 / UPDATES_PER_SECOND);

  if (P_Status_W > 0)
  {
    P_Status_I = 1;
  }
  else if (P_Status_C > 0)
  {
    P_Status_I = 2;
  }
}

void DisplayStatusW()
{
  if (P_Status_W == 1)
  {
    V_LCD_Line0W = "WARNING:";
    V_LCD_Line1W = "Laser ON!";
    I_LEDS[0] = CRGB::Blue;
    I_LEDS[1] = CRGB::Red;
    I_LEDS[2] = CRGB::Blue;
    I_LEDS[3] = CRGB::Blue;
    I_LEDS[4] = CRGB::Red;
    I_LEDS[5] = CRGB::Blue;
  }
  else if (P_Status_W == 2)
  {
    V_LCD_Line0W = "WARNING:";
    V_LCD_Line1W = "3D Printing";
    I_LEDS[0] = CRGB::Green;
    I_LEDS[1] = CRGB::Cyan;
    I_LEDS[2] = CRGB::Blue;
    I_LEDS[3] = CRGB::Blue;
    I_LEDS[4] = CRGB::Cyan;
    I_LEDS[5] = CRGB::Green;
  }

  lcd.clear();

  lcd.setCursor(0, 0);
  lcd.print(V_LCD_Line0W);

  lcd.setCursor(0, 1);
  lcd.print(V_LCD_Line1W);

  FastLED.show();
  FastLED.delay(1000 / UPDATES_PER_SECOND);

  if (P_Status_C > 0)
  {
    P_Status_I = 2;
  }
  else
  {
    if (P_Status_S > 0)
    {
      P_Status_I = 0;
    }
  }
}

void DisplayStatusC()
{
  if (P_Status_C == 1)
  {
    V_LCD_Line0C = "Coffee!";
    V_LCD_Line1C = "Please!";
    I_LEDS[0] = CRGB::Red;
    I_LEDS[1] = CRGB::Yellow;
    I_LEDS[2] = CRGB::Green;
    I_LEDS[3] = CRGB::Cyan;
    I_LEDS[4] = CRGB::Blue;
    I_LEDS[5] = CRGB::Purple;
  }

  lcd.clear();

  lcd.setCursor(0, 0);
  lcd.print(V_LCD_Line0C);

  lcd.setCursor(0, 1);
  lcd.print(V_LCD_Line1C);

  FastLED.show();
  FastLED.delay(1000 / UPDATES_PER_SECOND);

  if (P_Status_S > 0)
  {
    P_Status_I = 0;
  }
  else if (P_Status_W > 0)
  {
    P_Status_I = 1;
  }

}
