#include <IRremote.h>
#include <LiquidCrystal_I2C.h>
#include "max7219func.h"
#include <SPI.h>
#include <TimeLib.h>


#define PIN_RECEIVER 12   // Signal Pin of IR receiver
#define MAX_MESG   20

IRrecv receiver(PIN_RECEIVER);
LiquidCrystal_I2C lcd(0x27, 16, 2);

unsigned char szMesg[MAX_MESG + 1] = "";
void getTime(unsigned char *psz)
{
   sprintf((char*)psz, "%s%01d%s%02d%s\x9a%02d\x9a", hours < 10 ? "  " : "", hours, seconds % 2 ? (numFont == Font5x8 ? "\x9c" : " ") : (numFont == Font5x8 ? "\x9b" : ":"), minutes, numFont == Font4x8 ? " " : "  ", seconds);
}

void checkIR() {
  if (receiver.decode()) {
    translateIR();
    receiver.resume();  // Receive the next value
  }
}

void setup()
{
  Wire.begin();
  mx.begin();
  mx.setFont(numeric7Seg);
  mx.setShiftDataInCallback(&dataInCB);
  lcd.init();
  lcd.print("<press a button>");
  Serial.begin(115200);
  receiver.enableIRIn();  // Start the receiver
  while (!Serial)  // Wait for the serial connection to be establised.
    delay(50);
  Serial.println();
  Serial.print(F("IRrecvDemo is now running and waiting for IR message on Pin "));
  Serial.println(PIN_RECEIVER);
}

decode_results results;

unsigned char helyseg[] = "Várpalota:";
unsigned char temp[] = "-21.6\x90\x43";
unsigned char hum[] = "Pára:";
unsigned char humDigs[] = "25%";
char anims[] = {'P','L','U'};
enum states { Idle, InitCycle, TimeStart, ShowTime, ShowTempLoc, ShowTempDigits, ShowHumidityText, ShowHumidityDigits };
enum animTypes { Print, LR, UD } animType;

void loop() {
  static enum states state = InitCycle;
  static enum states prevState, nextState;
  static uint32_t showTimeFor = 2000, showTempFor = 2000, idleTime = 15;
  static uint32_t  lastDSUpdate = 0; // Memory (ms)
  static uint8_t lastSec = 5;
  bool animEnd;
  static byte randAnim[5];
  byte tempPos;
  
  //----------------------------------------------------------------
  
  switch (state) {
    case Idle:
      yield();                                       //In case of ESP
      if (elapsed(idleTime)) {
        state = nextState;
        idleTime = 15;
      }
      else {
        if (receiver.decode()) {
          translateIR();
          receiver.resume();  // Receive the next value
        }
      }
      break;
    case InitCycle:
      for(int i = 0; i < 5; i++){ randAnim[i] = random(3); Serial.print(anims[randAnim[i]]); }
       Serial.println();
      // randAnim[0] = 2;
      // randAnim[1] = 2;
      // randAnim[2] = 1;
      // randAnim[3] = 0;
      // randAnim[4] = 1;
      //for(int i = 0; i < 5; i++)Serial.print(anims[randAnim[i]]);
      DS1307getTime();
      setTime(hours, minutes, seconds, mday, monthL, yearL);
      getTime(szMesg);
    case TimeStart:
      switch (randAnim[0]) {
        case Print: animEnd = printText(szMesg, numFont != Font5x8 ?1:4); break;
        case LR: animEnd = TSLR(szMesg, numFont != Font5x8 ? 30 : 45, 0, LEFT); break;
        case UD: animEnd = numFont != Font5x8 ? TSUD(szMesg, UP, 1, 32, 2) : TSUD(szMesg, UP, 3, 29, 3);
      }
      if (!animEnd) {
        state = Idle; idleTime = 150;
        nextState = TimeStart;
      }
      else state = ShowTime;
      break;

    case ShowTime:
      hours = hour(), minutes = minute(), seconds = second();
      if (lastSec != seconds) {
        lastSec = seconds;
        getTime(szMesg);
        if (numFont == Font5x8) {
          printText(szMesg, 3);
          seconds <= 30 ? mx.setPoint(7, seconds == 0 ? 30 : 31 - seconds, true) : mx.setPoint(7, seconds == 31 ? 1 : seconds - 30, true);
          if (seconds > 55) mx.setColumn(30, 4 << seconds % 5);
          if (seconds > 25 && seconds < 31) mx.setColumn(1, 4 << (seconds < 30 ? seconds % 5 : 5));
        } else {
          printText(szMesg, 1);
        }
        if (elapsed(showTimeFor, 1)) {
          state = ShowTempLoc;
        }
      } else {
        state = Idle; idleTime = 50;
        nextState = ShowTime;
      }
      break;
    case ShowTempLoc:
      switch (randAnim[1]) {
        case Print: animEnd = printText(helyseg, 0, 32, false, true); break;
        case LR: animEnd = TSLR(helyseg, -16, 7); break;
        case UD: animEnd = TSUD(helyseg, DOWN, 0, 32, 3, true);
      }
      if (!animEnd) {
        state = Idle;
        nextState = ShowTempLoc;
      }
     else {
        nextState = ShowTempDigits;
        state = Idle;
        idleTime = 1000;
      }
      break;
    case ShowTempDigits:
      tempPos = numFont == Font5x8?temp[0]==0x2d?0:3:temp[0]==0x2d?2:5;
      switch (randAnim[2]) { 
        case Print: animEnd = printText(temp, tempPos); break;
        case LR: animEnd = TSLR(temp, numFont == Font4x8?2:5, 10); break;
        case UD: animEnd = TSUD(temp, DOWN, tempPos, 32, 3);
      }
      if (!animEnd) {
        state = Idle;
        nextState = ShowTempDigits;
      }
      else {
        nextState = ShowHumidityText;
        state = Idle;
        idleTime = showTempFor;
      }
      break;
    case ShowHumidityText:  
      switch (randAnim[3]) {
        case Print: animEnd = printText(hum, 4); break;
        case LR: animEnd = TSLR(hum, 5, 15); break;
        case UD: animEnd = TSUD(hum, true, 4, 32, 2);
      }
      if (!animEnd) {
        state = Idle;
        nextState = ShowHumidityText;
      } else {
        nextState = ShowHumidityDigits;
        state = Idle;
        idleTime = 800;
      }
      break;
    case ShowHumidityDigits:
      switch (randAnim[4]) {
        case Print: animEnd = printText(humDigs, 10); break;
        case LR: animEnd = TSLR(humDigs, 9, 5); break;
        case UD: animEnd = TSUD(humDigs, false, 10, 32, 2);
      }
      if (!animEnd) {
        state = Idle;
        nextState = ShowHumidityDigits;
      }  else {
        nextState = InitCycle;
        state = Idle;
        idleTime = 2000;
      }
      break;
  }
}

void lcdPrint(const char* text)
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("button pressed:");
  lcd.setCursor(0, 1);
  lcd.print(text);
  lcd.print(" code: ");
  lcd.print(receiver.decodedIRData.command);
}

void translateIR()
{
  // Takes command based on IR code received
  switch (receiver.decodedIRData.command) {
    case 162:
      char time[2];
      //lcdPrint("POWER");
      DS1307getTime();
      lcdPrint(itoa(seconds, time, 10));
      break;
    case 226:
      lcdPrint("MENU");
      break;
    case 34:
      lcdPrint("TEST");
      break;
    case 2:
      lcdPrint("PLUS");
      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");
      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:
      lcd.clear();
      lcd.print(receiver.decodedIRData.command);
      lcd.print(" other button");
  }
}
GND5VSDASCLSQWRTCDS1307+