// Include the required Arduino libraries:
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
#include <Wire.h>
#include "Button.h"
#include <RTClib.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
#define HARDWARE_TYPE MD_MAX72XX::PAROLA_HW
#define MAX_DEVICES 8
#define PAUSE_TIME    1000
#define SCROLL_SPEED  500
#define CLK_PIN 10
#define CS_PIN  9
#define DATA_PIN 8
#define SPEED_TIME 75 // Speed of the transition
#define PAUSE_TIME  0
#define MAX_MESG   20
// HARDWARE SPI
//MD_Parola P = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
MD_Parola myDisplay = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);
// create RTC_DS1307 instance
RTC_DS1307 rtc;
// These are for the clock
#define DS1307_ADDRESS 0x68
// Define buttons
Button hourButton(A0);
Button minuteButton(A1);
Button alarmButton(A2);
uint8_t clear = 0x00;
uint8_t wday, mday, month, year;
uint8_t hours, minutes, seconds;
char szTime[9];    // mm:ss\0
char szMesg[MAX_MESG + 1] = "";
uint8_t decToBcd(uint8_t value)
{
  return ((value / 10 * 16) + (value % 10));
}
uint8_t bcdToDec(uint8_t value)
{
  return ((value / 16 * 10) + (value % 16));
}
// Get a label from PROGMEM into a char array
char *mon2str(uint8_t mon, char *psz, uint8_t len)
{
  static const __FlashStringHelper* str[] =
  {
    F("Gennaio"), F("Febbraio"), F("Marzo"), F("Aprile"),
    F("Mggio"), F("Giugno"), F("Liglio"), F("Agosto"),
    F("Settembre"), F("Ottobre"), F("Novembre"), F("Dicembre")
  };
  strncpy_P(psz, (const char PROGMEM *)str[mon - 1], len);
  psz[len] = '\0';
  return (psz);
}
char *dow2str(uint8_t code, char *psz, uint8_t len)
{
  static const __FlashStringHelper* str[] =
  {
    F("Domenica"), F("Lunedi"), F("Martedi"),
    F("Mercoledi"), F("Giovedi"), F("Venerdi'"),
    F("Sabato")
  };
  strncpy_P(psz, (const char PROGMEM *)str[code - 1], len);
  psz[len] = '\0';
  return (psz);
}
void beginDS1307()
{
  // Read the values (date and time) of the DS1307 module
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(clear);
  Wire.endTransmission();
  Wire.requestFrom(DS1307_ADDRESS, 0x07);
  seconds = bcdToDec(Wire.read());
  minutes = bcdToDec(Wire.read());
  hours = bcdToDec(Wire.read() & 0xff);
  wday = bcdToDec(Wire.read());
  mday = bcdToDec(Wire.read());
  month = bcdToDec(Wire.read());
  year = bcdToDec(Wire.read());
}
// Code for reading clock time
void getTime(char *psz, bool f = true)
{
  sprintf(psz, "%02d%c%02d", hours, (f ? ':' : ' '), minutes);
}
// Code for reading clock date
void getDate(char *psz)
{
  char  szBuf[10];
  sprintf(psz, "%d %s %04d", mday , mon2str(month, szBuf, sizeof(szBuf) - 1), (year + 2000));
}
void incrementHour() {
  DateTime now = rtc.now();
  DateTime newTime = DateTime(now.year(), now.month(), now.day(), (now.hour() + 1) % 24, now.minute());
  rtc.adjust(newTime);
}
void setup() {
  // start serial comunication
  Serial.begin(115200);
  // Intialize the object:
  myDisplay.begin(2);
  // Set the intensity (brightness) of the display (0-15):
  myDisplay.setIntensity(0);
  myDisplay.setZone(0,  MAX_DEVICES - 8, MAX_DEVICES - 1);
  myDisplay.setZone(1, MAX_DEVICES - 8, MAX_DEVICES - 1);
  myDisplay.displayZoneText(1, szTime, PA_CENTER, SPEED_TIME, PAUSE_TIME, PA_PRINT, PA_NO_EFFECT);
  myDisplay.displayZoneText(0, szMesg, PA_CENTER, SPEED_TIME, 0, PA_PRINT , PA_NO_EFFECT);  
  // Clear the display:
  myDisplay.displayClear();
}
void loop() {
  static uint32_t lastTime = 0; // Memory (ms)
  static uint8_t  display = 0;  // Current display mode
  static bool flasher = false;  // Seconds passing flasher
  beginDS1307();
  myDisplay.displayAnimate();
  if (hourButton.pressed()) {
    incrementHour();
  }  
  /*myDisplay.setTextEffect(0, PA_PRINT, PA_NO_EFFECT);
  myDisplay.setPause(0, 0);
  getTime(szMesg, flasher);
  flasher = !flasher;
  myDisplay.setTextEffect(0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
  //display = 0;
  getDate(szMesg);*/
  if (myDisplay.getZoneStatus(0))
  {  
    switch (display)
    {
    case 0: // Clock
      //Serial.println("Sono al case 0");
      myDisplay.setTextEffect(0, PA_PRINT, PA_NO_EFFECT);
      myDisplay.setPause(0, 0);
      //display++;
      if ((millis() - lastTime) >= 1000)
      {
        lastTime = millis();
        getTime(szMesg, flasher);
        flasher = !flasher;
      }
      if ((seconds == 00) && (seconds <= 30)) {
        display++;
        myDisplay.setTextEffect(0, PA_PRINT, PA_WIPE_CURSOR);
      }
      break;
    case 1: // Day of week
      //Serial.println("Sono al case 1");
      myDisplay.setFont(0, nullptr);
      myDisplay.setTextEffect(0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
      display++;
      dow2str(wday, szMesg, MAX_MESG);
      break;
    default: // Calendar
      //Serial.println("Sono al case default");
      myDisplay.setTextEffect(0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
      display = 0;
      getDate(szMesg);
      break;
    }
    myDisplay.displayReset(0);
  }
}