// Include the required Arduino libraries:
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <RTClib.h>
#include <SPI.h>
// Define the number of devices we have in the chain and the hardware interface
// NOTE: These pin numbers will probably not work with your hardware and may
// need to be adapted
//Per applicazione reale
//#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
//Per simulazione
#define HARDWARE_TYPE MD_MAX72XX::PAROLA_HW
#define MAX_DEVICES 4
#define PAUSE_TIME    10
#define SCROLL_SPEED  10
#define CLK_PIN 13//10  //Giallo
#define CS_PIN  8//9   //Verde
#define DATA_PIN 11//8  //Blu
// Button definitiom
const int functionButton = 3;
const int increaseButton = 4;
const int decreaseButton = 5;
// Ingresso sensore luminosità
const int ldr = 7;
// Stato del pulsante function
int functionButtonState = 0;
int increaseButtonState = 0;
int decreaseButtonState = 0;
// Ultimo stato del pulsante function
int last_functionButtonState = 0;
int last_increaseButtonState = 0;
int last_decreaseButtonState = 0;
// Create RTC_DS3231 instance
RTC_DS3231 rtc;
// Create Parola instance
//MD_Parola myDisplay = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);
MD_Parola myDisplay = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
// Date & time variable
DateTime dateTime;
// Variables to store date characters to be printed
char strDate[15] = "    ";
String dateLine = String();
// Variables to store time characters to be printed
char strTime[7] = "    ";
String timeLine = String();
// create array of a week days
char daysOfTheWeek[7][12] = {"Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab"};
// State variable
static uint8_t state = 1;
void setup() {
  // put your setup code here, to run once:
    // initialize serial communication
    // Per simulazione
    Serial.begin(57600);
    // Per applicazione reale
    //Serial.begin(9600);
  // start I2C communication
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    Serial.flush();
    while (1) delay(10);
  }
  // set initial Date-Time
  if (rtc.lostPower()) {
    Serial.println("RTC lost power, let's set the time!");
    // When time needs to be set on a new device, or after a power loss, the
    // following line sets the RTC to the date & time this sketch was compiled
    //rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    //rtc.adjust(DateTime(2023, 1, 21, 17, 20, 0));
    getTime();
    rtc.adjust(strTime);
    // rtc.adjust(DateTime("2023-01-21T11:30:00"));
  }
  else Serial.println("Rtc is running....");
  // Intialize the object:
  myDisplay.begin();
  // Set the intensity (brightness) of the display (0-15):
  myDisplay.setIntensity(0);
  // Clear the display:
  myDisplay.displayClear();
  pinMode(functionButton, INPUT);
  pinMode(increaseButton, INPUT);
  pinMode(decreaseButton, INPUT);
}
void getDate()
{
  // read value from RTC module
  dateTime = rtc.now();
  dateLine.concat(daysOfTheWeek[dateTime.dayOfTheWeek()]);
  dateLine.concat(" ");
  dateLine.concat(dateTime.day());
  dateLine.concat("/");
  dateLine.concat(dateTime.month());
  dateLine.concat("/");
  dateLine.concat(dateTime.year());
  dateLine.toCharArray(strDate, 15);
  dateLine = "";
}
void setState()
{
  functionButtonState = digitalRead(functionButton);
  if (functionButtonState != last_functionButtonState)
  {
    if (functionButtonState == HIGH)
    {
      if (state == 3) {
        state = 1;
      } else {
        state = state + 1;
      }
    }
    else
    {}
    // Delay per evitare il bouncing
    delay(300);
  }
  last_functionButtonState = functionButtonState;
}
void incHour()
{
  increaseButtonState = digitalRead(increaseButton);
  if (increaseButtonState != last_increaseButtonState)
  {
    if (increaseButtonState == HIGH)
    {
      DateTime currentDateTime = rtc.now();
      uint8_t hour = currentDateTime.hour();
      if (hour == 23)
      {
        hour = 0;
      } else
      {
        hour = hour + 1;
      }
      rtc.adjust(DateTime(currentDateTime.year(), currentDateTime.month(), currentDateTime.day(), hour, currentDateTime.minute(), currentDateTime.second()));
    }
    else
    {}
    // Delay per evitare il bouncing
    delay(300);
  }
  last_increaseButtonState = increaseButtonState;
}
void decHour()
{
  decreaseButtonState = digitalRead(decreaseButton);
  if (decreaseButtonState != last_decreaseButtonState)
  {
    if (decreaseButtonState == HIGH)
    {
      DateTime currentDateTime = rtc.now();
      uint8_t hour = currentDateTime.hour();
      if (hour == 0)
      {
        hour = 23;
      } else {
        hour = hour - 1;
      }      
      rtc.adjust(DateTime(currentDateTime.year(), currentDateTime.month(), currentDateTime.day(), hour, currentDateTime.minute(), currentDateTime.second()));
    }
    else {
    }
    // Delay per evitare il bouncing
    delay(300);
  }
  last_decreaseButtonState = decreaseButtonState;
}
void incMinute()
{
  increaseButtonState = digitalRead(increaseButton);
  if (increaseButtonState != last_increaseButtonState)
  {
    if (increaseButtonState == HIGH)
    {
      DateTime currentDateTime = rtc.now();
      uint8_t minute = currentDateTime.minute();
      if (minute == 59)
      {
        minute = 0;
      } else {
        minute = minute + 1;
      }
      rtc.adjust(DateTime(currentDateTime.year(), currentDateTime.month(), currentDateTime.day(), currentDateTime.hour(), minute, currentDateTime.second()));
    }
    else {
    }
    // Delay per evitare il bouncing
    delay(300);
  }
  last_increaseButtonState = increaseButtonState;
}
void decMinute()
{
  decreaseButtonState = digitalRead(decreaseButton);
  if (decreaseButtonState != last_decreaseButtonState)
  {
    if (decreaseButtonState == HIGH)
    {
      DateTime currentDateTime = rtc.now();
      uint8_t minute = currentDateTime.minute();
      if (minute == 0) {
        minute = 59;
      } else {
        minute = minute - 1;
      }
      rtc.adjust(DateTime(currentDateTime.year(), currentDateTime.month(), currentDateTime.day(), currentDateTime.hour(), minute, currentDateTime.second()));
    }
    else {
    }
    // Delay per evitare il bouncing
    delay(300);
  }
  last_decreaseButtonState = decreaseButtonState;
}
void getTime()
{
  // read value from RTC module
  dateTime = rtc.now();
  if (dateTime.hour() < 10)
  {
    timeLine.concat("0");
    timeLine.concat(dateTime.hour());
  }
  else
  {
    timeLine.concat(dateTime.hour());
  }  
  timeLine.concat(":");
  if (dateTime.minute() < 10)
  {
    timeLine.concat("0");
    timeLine.concat(dateTime.minute());
  }
  else
  {
    timeLine.concat(dateTime.minute());
  }
  timeLine.concat(dateTime.minute());
  timeLine.toCharArray(strTime, 6);
  timeLine = "";
}
void getHour()
{
  // read value from RTC module
  dateTime = rtc.now();
  timeLine.concat("h ");
  timeLine.concat(dateTime.hour());
  timeLine.toCharArray(strTime, 6); 
  timeLine = "";
}
void getMinute()
{
  // read value from RTC module
  dateTime = rtc.now();
  timeLine.concat("m ");
  timeLine.concat(dateTime.minute());
  timeLine.toCharArray(strTime, 6);
  timeLine = "";
}
void loop() {
  setState();
  int analogValue = analogRead(ldr);
  //Serial.println(analogValue);
  analogValue = (analogValue, 8, 1016, 15, 0);
  myDisplay.setIntensity(analogValue);
  
  switch (state)
  {
    case 1:
      if (myDisplay.displayAnimate())
      {
        //Stato normale, viene mostrata l'ora
        getTime();
        myDisplay.displayText(strTime, PA_CENTER, SCROLL_SPEED, PAUSE_TIME, PA_PRINT);     
      }    
      break;
    case 2:
      if (myDisplay.displayAnimate())
      {
        //Stato di impostazione dell'ora
        getHour();
        myDisplay.displayText(strTime, PA_CENTER, SCROLL_SPEED, PAUSE_TIME, PA_PRINT);
        incHour();
        decHour();
      }
      break;
    case 3:
      if (myDisplay.displayAnimate())
      {
        //Stato di impostazione dei minuti
        getMinute();
        myDisplay.displayText(strTime, PA_CENTER, SCROLL_SPEED, PAUSE_TIME, PA_PRINT);
        incMinute();
        decMinute();        
      }
      break;
  }
}