#include "RTClib.h"
#include <LiquidCrystal.h>
#include <Servo.h>
#include <BfButton.h>
#include <Encoder.h>

RTC_DS1307 rtc;
Servo servo;
LiquidCrystal lcd(12, 11, 10, 9, 8, 7);

DateTime now;
DateTime shutTime;
DateTime openTime;

unsigned long currentMillis;
unsigned previousMillis =0;
const int blinkDelayTime = 500;
bool blinked = false;

char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

byte shutTime_Hours;
byte shutTime_Minutes;
byte openTime_Hours;
byte openTime_Minutes;

byte timeNow_Hours;
byte timeNow_Minutes;

bool timeSet = false;

long oldTime = 0;
long newTime = 0;

bool minSelected = true;

int btnPin=4; //GPIO #3-Push button on encoder
int DT=2; //GPIO #4-DT on encoder (Output B)
int CLK=3; //GPIO #5-CLK on encoder (Output A)

Encoder navigator(CLK, DT);

BfButton btn(BfButton::STANDALONE_DIGITAL, btnPin, true, LOW);
BfButton btn2(BfButton::STANDALONE_DIGITAL, 2, true, LOW);



int currentStateCLK;
int lastStateCLK;

const int servoPin = 6;

bool lockActivated;

enum displayState 
{
  CLOCK,
  CHANGE_TIME,
  CHANGE_SHUT,
  CHANGE_OPEN,
};

displayState states = CLOCK;


void ChangeOpenTime()
{
  //When minutes are selected
  if(minSelected)
  {
    newTime = navigator.read(); 
    if(newTime < oldTime)
    {
      oldTime = newTime;
      openTime_Minutes -= 1;
    }
    
    if(newTime > oldTime)
    {
      oldTime = newTime;
      openTime_Minutes += 1;
    }
    
    if(openTime_Minutes >= 60)
    {
    Serial.println("reset to 0");
    openTime_Minutes = 0;
    oldTime = newTime;
    }
    else if(openTime_Minutes < 0)
    {
    Serial.println("reset to 60");
    openTime_Minutes = 59;
    oldTime = newTime;
    }

      

  }

  
  else if(!minSelected)
  {
    //Serial.println(timeNow_Minutes);
    newTime = navigator.read();
    //Serial.println(timeNow_Minutes);
    if(newTime < oldTime)
    {
      oldTime = newTime;
      openTime_Hours -=1;
    }
    if(newTime > oldTime)
    {
      oldTime = newTime;
      openTime_Hours +=1;
    }

    if(openTime_Hours >= 24)
    {
    Serial.println("reset to 0");
    openTime_Hours = 0;
    oldTime = newTime;
    }
    else if(openTime_Hours < 0)
    {
    Serial.println("reset to 23");
    openTime_Hours = 23;
    oldTime = newTime;
    }
  }



  lcd.setCursor(0,0);
  lcd.print("open time");
  lcd.setCursor(0,1);
  
if (currentMillis - previousMillis >= blinkDelayTime){
    // save the last time you blinked the LED
    previousMillis = currentMillis;
    blinked = !blinked;
    Serial.println(blinked);
  }
 

  if(!blinked || minSelected){
  if(openTime_Hours < 10)
  {
    lcd.print("0");
    lcd.setCursor(1,1);
  }
  lcd.print(openTime_Hours);
  }
  else if(blinked)
  {
    lcd.print("  ");
  }

  lcd.print(":");
  lcd.setCursor(3,1);
  
  
  
  if(!blinked || !minSelected){
   if(openTime_Minutes < 10)
  {
    lcd.print("0");
  }
    lcd.print(openTime_Minutes);
  } 
    else if(blinked)
  {
    lcd.print("  ");
  }
  lcd.setCursor(0,1);
}

/*******************/
/*CHANGE close TIME*/
/*******************/

void ChangeCloseTime()
{
if(minSelected)
  {
    newTime = navigator.read();
    //Serial.println(timeNow_Minutes);
    
    if(newTime < oldTime)
    {
      oldTime = newTime;
      shutTime_Minutes -= 1;
    }
    
    if(newTime > oldTime)
    {
      oldTime = newTime;
      shutTime_Minutes += 1;
    }
    
    if(shutTime_Minutes >= 60)
    {
    Serial.println("reset to 0");
    shutTime_Minutes = 0;
    oldTime = newTime;
    }
    else if(shutTime_Minutes < 0)
    {
    Serial.println("reset to 60");
    shutTime_Minutes = 59;
    oldTime = newTime;
    }

      

  }

  
  else if(!minSelected)
  {
    //Serial.println(timeNow_Minutes);
    newTime = navigator.read();
    //Serial.println(timeNow_Minutes);
    if(newTime < oldTime)
    {
      oldTime = newTime;
      shutTime_Hours -=1;
    }
    if(newTime > oldTime)
    {
      oldTime = newTime;
      shutTime_Hours +=1;
    }

    if(shutTime_Hours >= 24)
    {
    Serial.println("reset to 0");
    shutTime_Hours = 0;
    oldTime = newTime;
    }
    else if(shutTime_Hours < 0)
    {
    Serial.println("reset to 23");
    shutTime_Hours = 23;
    oldTime = newTime;
    }
  }

  


  lcd.setCursor(0,0);
lcd.print("close time");
lcd.setCursor(0,1);


if (currentMillis - previousMillis >= blinkDelayTime){
    // save the last time you blinked the LED
    previousMillis = currentMillis;
    blinked = !blinked;
    Serial.println(blinked);
  }
 

  if(!blinked || minSelected){
  if(shutTime_Hours < 10)
  {
    //lcd.setCursor(0,1);
    lcd.print("0");
    lcd.setCursor(1,1);
  }
  lcd.print(shutTime_Hours);
  }
  else if(blinked)
  {
    lcd.print("  ");
  }

   lcd.print(":");
  lcd.setCursor(3,1);
  
  
  if(!blinked || !minSelected){
   if(shutTime_Minutes < 10)
  {
    lcd.print("0");
  }
    lcd.print(shutTime_Minutes);
  } 
    else if(blinked)
  {
    lcd.print("  ");
  }
  lcd.setCursor(0,1);
  
}         


/*************/
/*CHANGE TIME*/
/*************/

void ChangeTime()
{
  if(minSelected)
  {
    newTime = navigator.read();
    //Serial.println(timeNow_Minutes);
    if(newTime < oldTime)
    {
      oldTime = newTime;
      timeNow_Minutes -=1;
    }
    if(newTime > oldTime)
    {
      oldTime = newTime;
      timeNow_Minutes +=1;
    }
    
    if(timeNow_Minutes >= 60)
    {
    Serial.println("reset to 0");
    timeNow_Minutes = 0;
    oldTime = newTime;
    }
    else if(timeNow_Minutes < 0)
    {
    Serial.println("reset to 60");
    timeNow_Minutes = 59;
    oldTime = newTime;
    }
  }

  
  else if(!minSelected)
  {
    newTime = navigator.read();
    if(newTime < oldTime)
    {
      oldTime = newTime;
      timeNow_Hours -=1;
    }
    if(newTime > oldTime)
    {
      oldTime = newTime;
      timeNow_Hours +=1;
    }
    
    if(timeNow_Hours >= 24)
    {
    Serial.println("reset to 0");
    timeNow_Hours = 0;
    }

    else if(timeNow_Hours < 0)
    {
    Serial.println("reset to 23");
    timeNow_Hours = 23;
    }
  }


  lcd.setCursor(0,0);
  lcd.print("Change time");
  lcd.setCursor(0,1);
  
  if (currentMillis - previousMillis >= blinkDelayTime){
    // save the last time you blinked the LED
    previousMillis = currentMillis;
    blinked = !blinked;
    Serial.println(blinked);
  }
 

  if(!blinked || minSelected){
  if(timeNow_Hours < 10)
  {
    lcd.setCursor(0,1);
    lcd.print("0");
    lcd.setCursor(1,1);
  }
  lcd.print(timeNow_Hours);
  }

  else if(blinked)
  {
    lcd.print("  ");
  }

  lcd.print(":");
  lcd.setCursor(3,1);
  
  if(!blinked || !minSelected){
   if(timeNow_Minutes < 10)
  {
    lcd.print("0");
  }
    lcd.print(timeNow_Minutes);
  }
  else if(blinked)
  {
    lcd.print("  ");
  }
  }

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

  btn.onPress(pressHandler)
    .onDoublePress(pressHandler) // default timeout
    .onPressFor(pressHandler, 500); // custom timeout for 1 second

  lcd.begin(16,2);

  lcd.print("ChknDoor(Cheap)");
  lcd.setCursor(0,1);
  lcd.print("By");
  delay(2000);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("robotics");
  lcd.setCursor(0,1);
  lcd.print("W/Mr  2023");
  delay(2000);
  lcd.clear();

  if (! rtc.begin()) {
    lcd.println("something wrong!");
    lcd.setCursor(0,1);
    lcd.print("check RTC");
    Serial.flush();
    abort();
  }
  pinMode(LED_BUILTIN, OUTPUT);
  servo.attach(servoPin);
}

void pressHandler (BfButton *btn2, BfButton::press_pattern_t pattern) {
  switch (pattern) {
    case BfButton::SINGLE_PRESS:
      Serial.println("Single push");
      minSelected = !minSelected;
      
      break;
      
    case BfButton::DOUBLE_PRESS:
      Serial.println("Double push");
      rtc.adjust(DateTime(now.year(), now.month(), now.day(), timeNow_Hours, timeNow_Minutes, 0));
      states = CLOCK;
      lcd.clear();
      break;

    case BfButton::LONG_PRESS:
      Serial.println("Long push");
      
      lcd.clear();

      switch(states)
      {
        case CLOCK:
          lcd.clear();
          states = CHANGE_TIME;
          Serial.println("change time");
          break;
        
        case CHANGE_TIME:
          lcd.clear();
          states = CHANGE_SHUT;
          rtc.adjust(DateTime(now.year(), now.month(), now.day(), timeNow_Hours, timeNow_Minutes, 0));
          Serial.println("change shut");
          break;
        
        case CHANGE_SHUT:
          lcd.clear();
          states = CHANGE_OPEN;
          Serial.println("change open");
          break;
        
        case CHANGE_OPEN:
          lcd.clear();
          states = CLOCK;
          Serial.println("clock");
          break;
      }
  }
}

void updateClock()
{
  lcd.setCursor(0,0);
  now = rtc.now();
  timeNow_Minutes = now.minute();
  timeNow_Hours = now.hour();
  shutTime = DateTime(now.year(), now.month(), now.day(), shutTime_Hours, shutTime_Minutes, 0);
  openTime = DateTime(now.year(), now.month(), now.day(), openTime_Hours, openTime_Minutes, 0);
  lcd.print(now.hour(), DEC);
  lcd.print(':');
  lcd.print(now.minute(), DEC);
  lcd.print(':');
  lcd.print(now.second(), DEC);

  lcd.setCursor(0,1);
  lcd.print(shutTime.hour() % now.hour(), DEC);
  lcd.print(':');
  lcd.print(shutTime.minute() % now.minute(), DEC);
  lcd.print(':');
  lcd.print(now.second(), DEC);

  lcd.print(" ");

  lcd.print(openTime.hour() % now.hour(), DEC);
  lcd.print(':');
  lcd.print(openTime.minute() % now.minute(), DEC);
  lcd.print(':');
  lcd.print(now.second(), DEC); 
  Serial.println(lockActivated);

  if(shutTime.hour() == now.hour() &&
    shutTime.minute() == now.minute() && lockActivated == false)
    {
    lockActivated = true;
    digitalWrite(LED_BUILTIN, HIGH);
    }

  if(openTime.hour() == now.hour() &&
     openTime.minute() == now.minute() && lockActivated == true)
    {
    lockActivated = false;
    digitalWrite(LED_BUILTIN, LOW);
    }

  if (lockActivated)
  servo.write(180);
  else
  servo.write(0);
}

void loop () {
  currentMillis = millis();
  btn.read();

  switch(states)
  {
  case CLOCK:
  updateClock();
  break;

  case CHANGE_TIME:
  ChangeTime();
  break;

  case CHANGE_OPEN:
  ChangeOpenTime();
  break;

  case CHANGE_SHUT:
  ChangeCloseTime();
  break;
  }
}
GND5VSDASCLSQWRTCDS1307+