// https://programmersqtcpp.blogspot.com/2022/01/arduinolcd-testo-scorrevoleadvanced.html
#include <IRremote.h>
#include <LiquidCrystal.h>

#include "RTClib.h"

RTC_DS1307 rtc;
DateTime dateTime;

#define PIN_RECEIVER 2   // Signal Pin of IR receiver
IRrecv receiver(PIN_RECEIVER);

LiquidCrystal lcd(12, 11, 10, 9, 8, 7);

uint32_t oldTime = 0;

char *p_daysOfTheWeek[7] = {"Lun", "Mar", "Mer"
                            , "Gio", "Ven", "Sab", "Dom"
                           };
char *p_month[12] = {"Gen", "Feb", "Mar", "Apr", "Mag"
                     , "Giu", "Lug", "Ago", "Set", "Ott"
                     , "Nov", "Dic"
                    };

String strTime;           //  buffer
String strDate;           //  buffer
String strScrollText;       //  buffer
String strDayOfTheMonth;  //  buffer

String hourBuff;
String minuteBuff;
String secondBuff;
uint8_t speedScroll = 50;  // un carattere ogni 50ms

// ROW_LEN può avere un valore minoere di 16
// ad esempio se provate con 10 scoprirete che 
// si impegnano solo 10 colonne del display
#define ROW_LEN 16

// scorre da destra verso sinistra
void scrollText(char *s, char *sd) {

  uint8_t sIdx = 0;
  static uint8_t S_sdIdx = ROW_LEN;
  static uint8_t S_sIdx = 0;

  if (S_sdIdx > 0) {
    S_sdIdx--;
  } else {
    sIdx = S_sIdx;
  }
  uint8_t sdIdx = S_sdIdx;
  int len_s = strlen(s);  // 23

  memset(sd, ' ', ROW_LEN);
  sd[ROW_LEN] = '\0';

  while (sdIdx < ROW_LEN) {
    sd[sdIdx] = s[sIdx];
    sdIdx++;
    sIdx++;
    sIdx = sIdx % len_s;
  }
  if (S_sdIdx == 0) {
    S_sIdx++;
    S_sIdx = S_sIdx % len_s;
  }

} // end void scrollText(char *s, char *sd)


void setup()
{
  Serial.begin(115200);
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    Serial.flush();
    abort();
  }
  lcd.begin(16, 2);
  
  receiver.enableIRIn(); // Start the receiver

  oldTime = millis();
  strDayOfTheMonth.reserve(2);
  strTime.reserve(10);
  strDate.reserve(20);
  strScrollText.reserve(64);
  hourBuff.reserve(2);
  minuteBuff.reserve(2);
  secondBuff.reserve(2);

} // end void setup()


char *timeToStr() {
  uint8_t h = dateTime.hour();
  uint8_t m = dateTime.minute();
  uint8_t s = dateTime.second();
  if (h < 10) {
    hourBuff = "0" + String(h);
  } else {
    hourBuff = String(h);
  }
  if (m < 10) {
    minuteBuff = "0" + String(m);
  } else {
    minuteBuff = String(m);
  }
  if (s < 10) {
    secondBuff = "0" + String(s);
  } else {
    secondBuff = String(s);
  }
  strTime = " " + hourBuff + ":" + minuteBuff + ":" + secondBuff;

  return strTime.c_str();
} // end char *timeToStr()


char *dateToStr() {
  uint8_t dayOfTheMonth = dateTime.day();
  uint8_t dayOfTheWeek = dateTime.dayOfTheWeek();
  uint8_t month = dateTime.month();

  uint16_t year = dateTime.year();
  // visualizza 08 anziché 8, al fine di mantenere la stringa di
  // lunghezza costante. Tuttavia non è necessario, poiché
  // sia la lunghezza cbe il contenuto possono essere
  // modificati a run-time senza effetti negativi (sembra).
  if (dayOfTheMonth < 10) {
    strDayOfTheMonth = "0" + String(dayOfTheMonth);
  } else {
    strDayOfTheMonth = String(dayOfTheMonth);
  }

  strDate = " " + String( p_daysOfTheWeek[ dayOfTheWeek - 1 ] ) + " " + strDayOfTheMonth
            + " " + String( p_month[ month - 1 ] ) + " " + String(year);
  return strDate.c_str();
} // end char *dateToStr()

char scrollBuffer[ ROW_LEN + 1 ] = {0}; // buffer per il testo scorrevole

void loop()
{
  dateTime = rtc.now();
  // La rapidità di scorrimento può essere controllata
  // tramite i tasti + e - del telecomando.

  if (millis() - oldTime >= speedScroll) {

    dateToStr();
    timeToStr();

    oldTime = millis();
    // combina data e ora in unica variabile
    strScrollText = " MauroTec Software" + strDate + strTime + " Wokwi Simulator";

    scrollText(strScrollText.c_str(), scrollBuffer);

    lcd.setCursor(0, 1);
    lcd.print(scrollBuffer);

  }

  // Checks received an IR signal
  if (receiver.decode()) {
    translateIR();
    receiver.resume();  // Receive the next value
  }

} // end void loop()

void clsRow0() {
  lcd.setCursor(0, 0);
  lcd.print("                ");  // 16 spazi
}

void lcdPrint(char* text)
{
  clsRow0();
  lcd.setCursor(0, 0);

  lcd.print(text);
  lcd.print(" (");
  lcd.print(receiver.decodedIRData.command);
  lcd.print(")");
}

void translateIR()
{
  // Takes command based on IR code received
  switch (receiver.decodedIRData.command) {
    case 162:
      lcdPrint("POWER");
      break;
    case 226:
      lcdPrint("MENU");
      break;
    case 34:
      lcdPrint("TEST");

      break;
    case 2:
      lcdPrint("PLUS");
      if (speedScroll > 10)
        speedScroll -= 2;

      lcd.setCursor(14, 0);
      lcd.print(speedScroll);
      //Serial.println(speedScroll);
      break;
    case 194:
      lcdPrint("BACK");
      break;
    case 224:
      lcdPrint("PREV.");
      break;
    case 168:
      lcdPrint("PLAY");
      
      break;
    case 144:
      lcdPrint("NEXT");
      break;
    case 104:
      lcdPrint("num: 0");
      break;
    case 152:
      lcdPrint("MINUS");
      if (speedScroll < 100)
        speedScroll += 2;

      lcd.setCursor(14, 0);
      lcd.print(speedScroll);
      //Serial.println(speedScroll);
      break;
    case 176:
      lcdPrint("key: C");
      break;
    case 48:
      lcdPrint("num: 1");
      break;
    case 24:
      lcdPrint("num: 2");
      break;
    case 122:
      lcdPrint("num: 3");
      break;
    case 16:
      lcdPrint("num: 4");
      break;
    case 56:
      lcdPrint("num: 5");
      break;
    case 90:
      lcdPrint("num: 6");
      break;
    case 66:
      lcdPrint("num: 7");
      break;
    case 74:
      lcdPrint("num: 8");
      break;
    case 82:
      lcdPrint("num: 9");
      break;
    default:
      clsRow0();
      lcd.setCursor(0, 0);
      lcd.print(receiver.decodedIRData.command);
      lcd.print(" other button");
  }
}
GND5VSDASCLSQWRTCDS1307+