#include <EEPROM.h>
#include "LedControl.h"
#include <Adafruit_AHTX0.h>

int displaytime = 300;    //The overall speed of the thermostat display
float calibration = 0;     //Withthis variable you can calibrate the temperature sensor by adding or extracting from its value

//Sensors and the hardware
Adafruit_AHTX0 aht;
LedControl DP = LedControl(2, 4, 3, 1);

int button1 = 5, button2 = 6, button3 = 7;
int YellowLed = 9, RedLed = 8;


//Main containers for displaying and showing the display data

int DPCurrent[7];            //Load the default values for the diplayer struct whichwill contain all the displayable data
int Menu[6];
int currentLetter = 0;                  //The crrently displayed letter
int seCurrentLetter = 0;                //the currently displayed letter of the value
int CurrentDisplayed = 0;       //Which container is displayed at the moment

int ActiveBurner = 0;       //1 is wood burner 2 is gas burner

char isstatic = 'n';
int scheduler = 0;
bool menu = false, first = true, manual = false;
float temperaturesum =0;
int menuTimer = 0;

int hiszterezis = 50;      //Itt allithato a termosztat hiszterezise

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  DP.shutdown(0, false);
  DP.setIntensity(0, 0.1);
  DP.clearDisplay(0);
  aht.begin();
  pinMode(button1, INPUT_PULLUP);
  pinMode(button2, INPUT_PULLUP);
  pinMode(button3, INPUT_PULLUP);

  pinMode(RedLed, OUTPUT);
  pinMode(YellowLed, OUTPUT);
  DPCurrent[0] = 9999;          //This is PERMANENT

  Menu[0] = EEPROM.get(0, Menu[0]);
  Menu[1] = EEPROM.get(2, Menu[1]);
  Menu[2] = EEPROM.get(4, Menu[2]);
  Menu[3] = 0;
  Menu[4] = EEPROM.get(6, Menu[4]);
  Menu[5] = EEPROM.get(8, Menu[5]);
}

String GetDPCValue(int elem){    
  String Datawriteout;
  switch (elem) {
    case 0:
      Datawriteout = "hommerseklet...";
      break;
    case 1:
      Datawriteout = "paratartalomm...";
      break;
    case 2:
      Datawriteout = "celhommerseklet...";
      break;
    case 3:
      Datawriteout = "kulonbseg...";
      break;
    case 4:
      Datawriteout = "aktiv kazan...";
      break;
    case 5:
      Datawriteout = "hofok vegyes...";
      break;
    case 6:
      Datawriteout = "hofok puffer...";
  }
    return Datawriteout;
}

String GetMenuValue(int elem){    
  String Datawriteout;
  switch (elem) {
    case 0:
      Datawriteout = "futes ki.be...";
      break;
    case 1:
      Datawriteout = "hofok elsodleges kazanhoz...";
      break;
    case 2:
      Datawriteout = "hofok mmasodlagos kazanhoz...";
      break;
    case 3:
      Datawriteout = "mmanual mmode kivalasztasa...";
      break;
    case 4:
      Datawriteout = "elsodleges kazan kivalasztasa...";
      break;
    case 5:
      Datawriteout = "futesimmod kivalasztasa...";
  }
    return Datawriteout;
}

byte segmentABC(char letter){
  byte BinaryLetter;
  switch(letter){
    case 'a':
      BinaryLetter = B01110111;
    break;
    case 'b':
      BinaryLetter = B0011111;
    break;
    case 'c':
      BinaryLetter = B01001110;
    break;
    case 'd':
      BinaryLetter = B00111101;
    break;
    case 'e':
      BinaryLetter = B01001111;
    break;
    case 'f':
      BinaryLetter = B01000111;
    break;
    case 'g':
      BinaryLetter = B01011110;
    break;
    case 'h':
      BinaryLetter = B00010111;
    break;
    case 'i':
      BinaryLetter = B00110000;
    break;
    case 'j':
      BinaryLetter = B01011000;
    break;
    case 'k':
      BinaryLetter = B00110111;
    break;
    case 'l':
      BinaryLetter = B00001110;
    break;
    case 'm':
      BinaryLetter = B00010101;
    break;
    case 'n':
      BinaryLetter = B00010101;
    break;
    case 'o':
      BinaryLetter = B00011101;
    break;
    case 'p':
      BinaryLetter = B01100111;
    break;
    case 'q':
      BinaryLetter = B01110011;
    break;
    case 'r':
      BinaryLetter = B00000101;
    break;
    case 's':
      BinaryLetter = B01011011;
    break;
    case 't':
      BinaryLetter = B00001111;
    break;
    case 'v':
      BinaryLetter = B00011100;
    break;
    case 'u':
      BinaryLetter = B00011100;
    break;
    case 'y':
      BinaryLetter = B00110011;
    break;
    case 'z':
      BinaryLetter = B01101101;
    break;
    case '.':
      BinaryLetter = B10000000;
    break;
    case '1':
      BinaryLetter = B00110000;
    break;
    case '2':
      BinaryLetter = B01101101;
    break;
    case '3':
      BinaryLetter = B01111001;
    break;
    default: 
    BinaryLetter = B00000000;
  }
  return BinaryLetter;
}

byte segmentNumbers(char letter){
    byte BinaryLetter;
   switch(letter){
    case '0':
      BinaryLetter = B01111110;
    break;
    case '1':
      BinaryLetter = B00110000;
    break;
    case '2':
      BinaryLetter = B01101101;
    break;
    case '3':
      BinaryLetter = B01111001;
    break;
    case '4':
      BinaryLetter = B00110011;
    break;
    case '5':
      BinaryLetter = B01011011;
    break;
    case '6':
      BinaryLetter = B1011111;
    break;
    case '7':
      BinaryLetter = B01110000;
    break;
    case '8':
      BinaryLetter = B01111111;
    break;
    case '9':
      BinaryLetter = B01111011;
    break;
    case '-':
      BinaryLetter = B00000001;
    break;
   }
   return BinaryLetter;
}

void displaytimer(char skip = 'n'){     //skip could have 3 values default is n (not to skip), f is skip forward, b is skip backwards
  if(skip == 'f'){    if(CurrentDisplayed +1 >= sizeof(DPCurrent) / sizeof(DPCurrent[0]) ) CurrentDisplayed = 0;
    else CurrentDisplayed++;
    currentLetter = 0;
    seCurrentLetter = 0;
  }
  if(skip == 'b'){    if(CurrentDisplayed -1 < 0 ) CurrentDisplayed = sizeof(DPCurrent) / sizeof(DPCurrent[0]);
    else CurrentDisplayed--;
    currentLetter = 0;
    seCurrentLetter = 0;
  }
  String CurrentlyDisplayedText = GetDPCValue(CurrentDisplayed);
  if(currentLetter < CurrentlyDisplayedText.length()){
    DP.clearDisplay(0);
    for(int j = 0; j <= currentLetter; j++){
      DP.setRow(0,j,segmentABC(CurrentlyDisplayedText[currentLetter-j]));
    }
    currentLetter++;
  }
  if(CurrentDisplayed == 3) DPCurrent[3] = DPCurrent[0] - DPCurrent[2];
  if(currentLetter >= CurrentlyDisplayedText.length() && seCurrentLetter > -10 && CurrentDisplayed != 4 && CurrentDisplayed < sizeof(DPCurrent) / sizeof(DPCurrent[0])){
    DP.clearDisplay(0);
    DP.clearDisplay(0);
    String a;
    if(DPCurrent[CurrentDisplayed] < 0){
      a = "-";
      for(int i = 0; i < 4-String(DPCurrent[CurrentDisplayed]*-1).length(); i++){
        a += "0";
      }
      a += String(DPCurrent[CurrentDisplayed]*-1);
      DP.setRow(0,6,segmentNumbers(a[0]));
      DP.setRow(0,5,segmentNumbers(a[1]));
      byte modifi = segmentNumbers(a[2]);
      modifi |= (1 << 7);;
      DP.setRow(0,4, modifi);
      DP.setRow(0,3,segmentNumbers(a[3]));
      DP.setRow(0,2,segmentNumbers(a[4]));
    } else{
      a = "";
      for(int i = 0; i < 4-String(DPCurrent[CurrentDisplayed]).length(); i++){
        a += "0";
      }
      a += String(DPCurrent[CurrentDisplayed]);
      DP.setRow(0,5,segmentNumbers(a[0]));
      byte modifi = segmentNumbers(a[1]);
      modifi |= (1 << 7);;
      DP.setRow(0,4, modifi);
      DP.setRow(0,3,segmentNumbers(a[2]));
      DP.setRow(0,2,segmentNumbers(a[3]));
    }
    if(CurrentDisplayed != 1){
      DP.setRow(0,1,B01100011);
      DP.setRow(0,0,segmentABC('c'));
    }else{
      DP.setRow(0,1,segmentABC('r'));
      DP.setRow(0,0,segmentABC('h'));
    }
    seCurrentLetter--;
    }
    bool securrentready = false;
    if(currentLetter >= CurrentlyDisplayedText.length() && CurrentDisplayed == 4){
      DP.clearDisplay(0);
      String securrentText = "";
      switch(DPCurrent[4]){
        case 0:
          securrentText = "nincs aktiv...";
          break;
        case 1:
          securrentText = "vegyes kazan.";
          break;
        case 2:
          securrentText = "gaz kazan.";
      }
      if(seCurrentLetter < CurrentlyDisplayedText.length()){
          for(int j = 0; j <= seCurrentLetter; j++){
          DP.setRow(0,j,segmentABC(securrentText[seCurrentLetter-j]));
          }
          seCurrentLetter++;
          if(seCurrentLetter >= securrentText.length()) securrentready = true;
      }
    }
    
    if((currentLetter >= CurrentlyDisplayedText.length() && (securrentready || seCurrentLetter <= -10)) || CurrentDisplayed >= sizeof(DPCurrent) / sizeof(DPCurrent[0]) ){
      if(skip == 'n'){
      if(CurrentDisplayed +1 > sizeof(DPCurrent) / sizeof(DPCurrent[0]) ) CurrentDisplayed = 0;
      else CurrentDisplayed++;
      }
      currentLetter = 0;
      seCurrentLetter = 0;
      }
}

char BlinkYellow(char isstatic = 'n'){
    digitalWrite(YellowLed, HIGH);
    while(digitalRead(button2) == LOW || digitalRead(button3) == LOW){
        if(digitalRead(button2) == LOW && digitalRead(button3) == LOW){
          digitalWrite(YellowLed, LOW);
          if(isstatic == 'n') isstatic = 'c';
          else isstatic = 'n';
          while(digitalRead(button2) == LOW || digitalRead(button3) == LOW);
          break;
        }
      }
      digitalWrite(YellowLed, LOW);
      return isstatic;
}

void displayTheTextValue(String &Writeout){
  DP.clearDisplay(0);
  if(seCurrentLetter < Writeout.length()){
    for(int j = 0; j <= seCurrentLetter; j++){
      DP.setRow(0,j,segmentABC(Writeout[seCurrentLetter-j]));
    }
    seCurrentLetter++;
  }else{
    seCurrentLetter = 0;
  }
}

void displayTheNumberValue(){
    DP.clearDisplay(0);
    String a;
    if(Menu[CurrentDisplayed] < 0){
      a = "-";
      for(int i = 0; i < 4-String(Menu[CurrentDisplayed]*-1).length(); i++){
        a += "0";
      }
      a += String(Menu[CurrentDisplayed]*-1);
      DP.setRow(0,6,segmentNumbers(a[0]));
      DP.setRow(0,5,segmentNumbers(a[1]));
      byte modifi = segmentNumbers(a[2]);
      modifi |= (1 << 7);;
      DP.setRow(0,4, modifi);
      DP.setRow(0,3,segmentNumbers(a[3]));
      DP.setRow(0,2,segmentNumbers(a[4]));
    } else{
      a = "";
      for(int i = 0; i < 4-String(Menu[CurrentDisplayed]).length(); i++){
        a += "0";
      }
      a += String(Menu[CurrentDisplayed]);
      DP.setRow(0,5,segmentNumbers(a[0]));
      byte modifi = segmentNumbers(a[1]);
      modifi |= (1 << 7);;
      DP.setRow(0,4, modifi);
      DP.setRow(0,3,segmentNumbers(a[2]));
      DP.setRow(0,2,segmentNumbers(a[3]));
    }
    DP.setRow(0,1,B01100011);
    DP.setRow(0,0,segmentABC('c'));
}

void menuController(char skip = 'n', int change = 0){
  while(digitalRead(button1) == LOW);
  if(menuTimer >= 200) CurrentDisplayed = 6;             //Sets the amount of time you can spend inside a menu
  if(first){
      DP.clearDisplay(0);
      DP.setRow(0,6, segmentABC('m'));
      DP.setRow(0,5, segmentABC('m'));
      DP.setRow(0,4, segmentABC('e'));
      DP.setRow(0,3, segmentABC('n'));
      DP.setRow(0,2, segmentABC('u'));
      delay(1500);
      DP.clearDisplay(0);
      CurrentDisplayed = 0;
      currentLetter = 0;
      seCurrentLetter = 0;
      first = false;
  }
  if(skip == 'f'){ 
    CurrentDisplayed++;
    currentLetter = 0;
    seCurrentLetter = 0;
  }
  if(currentLetter < GetMenuValue(CurrentDisplayed).length() && menu != false){
    DP.clearDisplay(0);
    for(int j = 0; j <= currentLetter; j++){
      DP.setRow(0,j,segmentABC(GetMenuValue(CurrentDisplayed)[currentLetter-j]));
    }
    currentLetter++;
  }
  if(currentLetter >= GetMenuValue(CurrentDisplayed).length() && menu != false){
      digitalWrite(YellowLed, HIGH);
      if(change != 0) seCurrentLetter = 0;
      String Writeout;

      if(CurrentDisplayed == 0){       //When the first menu is selected
        if(change > 0) Menu[0] = 1; Menu[0];
        if(change < 0) Menu[0] = 0; Menu[0];
        switch (int(Menu[0])){
          case 1:
            Writeout = "be kapcsolva";
            break;
          case 0:
            Writeout = "ki kapcsolva";
            break;
        }
        displayTheTextValue(Writeout);
      }

      if(CurrentDisplayed == 1){       //When the Second menu is selected
        if(change > 0) { if( (Menu[1] - 50) <= 4500) Menu[1] += 50;}
        if(change < 0) { if( (Menu[1] - 50) >= 500) Menu[1] -= 50; if(Menu[2] > Menu[1]) Menu[2] = Menu[1]-100;}
        displayTheNumberValue();
      }

      if(CurrentDisplayed == 2){       //When the third menu is selected
        if(change > 0) { if((Menu[1]-100) > (Menu[2])) Menu[2] += 50;}
        if(change < 0) { if( (Menu[2] - 50) >= 500) Menu[2] -= 50;}
        displayTheNumberValue();

      }

      if(CurrentDisplayed == 3){       //Manual mode selector (fouth menu)
        if(change > 0 && Menu[3] < 2) { Menu[3] += 1;}
        if(change < 0 && Menu[3] > 0) { Menu[3] -= 1;}
        switch (int(Menu[3])){
          case 0:
            Writeout = "kikapcsolva";
            break;
          case 1:
            Writeout = "vegyes aktiv";
            break;
          case 2:
            Writeout = "gaz aktiv";
            break;
        }
        displayTheTextValue(Writeout);
      }

      if(CurrentDisplayed == 4){       //Primary burner selector (fourth menu)
        if(change > 0) Menu[4] = 1;
        if(change < 0) Menu[4] = 0;
        switch(Menu[4]){
          case 0:
            Writeout = "vegyes kazan";
            break;
          case 1:
            Writeout = "gaz kazan";
            break;
        }
        displayTheTextValue(Writeout);
      }
      
      if(CurrentDisplayed == 5){      //Automation behaviour selector (fith menu)
        if(change > 0 && Menu[5] < 3) { Menu[5] += 1;}
        if(change < 0 && Menu[5] > 0) { Menu[5] -= 1;}
        switch (int(Menu[5])){
          case 0:
            Writeout = "csak elsodleges";
            break;
          case 1:
            Writeout = "auto 1";
            break;
          case 2:
            Writeout = "auto 2";
            break;
          case 3:
            Writeout = "auto 3";
            break;
        }
        displayTheTextValue(Writeout);
      }
    }
    if(CurrentDisplayed == 6){
      saveChanges();
      DP.clearDisplay(0);
      DP.setRow(0,7, segmentABC('m'));
      DP.setRow(0,6, segmentABC('m'));
      DP.setRow(0,5, segmentABC('e'));
      DP.setRow(0,4, segmentABC('n'));
      DP.setRow(0,3, segmentABC('t'));
      DP.setRow(0,2, segmentABC('v'));
      DP.setRow(0,1, segmentABC('e'));
      delay(1500);
      DP.clearDisplay(0);
      menu = false; 
      digitalWrite(YellowLed, LOW); 
      first = true; 
      CurrentDisplayed = 0;
    }
}

void burnerOnoff(){
  DPCurrent[4] = ActiveBurner;
  if(ActiveBurner > 0){
    digitalWrite(RedLed, HIGH);
  }else {
    digitalWrite(RedLed, LOW);
  }
}

void takeAction(){
  if(Menu[0] > 0){
    if(Menu[3] > 0){                      //Takes action if manual mode is ON
      if(DPCurrent[0] >= DPCurrent[2]){
        Menu[3] = 0;
        ActiveBurner = 0;
        DPCurrent[2] = 0;
        manual = false;
      }else {
        ActiveBurner = Menu[3];
      }
    }else if(Menu[5] == 0){
      DPCurrent[2] = Menu[1];         //Sets the target heat on the screen
      if((DPCurrent[0] < Menu[1] - hiszterezis) && DPCurrent[0] < Menu[1]){
        ActiveBurner = Menu[4]+1;
      }else if(DPCurrent[0] > Menu[1]) ActiveBurner = 0;
    }else if(Menu[5] == 1){
      DPCurrent[2] = Menu[1];
      if((DPCurrent[0] < Menu[1] - hiszterezis) && (DPCurrent[0] < Menu[1]) && (DPCurrent[0] > Menu[2])){
        DPCurrent[2] = Menu[1];
        ActiveBurner = Menu[4]+1;
      }else if((DPCurrent[0] < Menu[2] - hiszterezis) && DPCurrent[0] < Menu[2]){
        DPCurrent[2] = Menu[2];
        switch (Menu[4]+1){
          case 1:
            ActiveBurner = 2;
          break;
          case 2:
            ActiveBurner = 1;
          break;
        }
      }
      else if(DPCurrent[0] > Menu[2]){ ActiveBurner = Menu[4]+1;}
      else if(DPCurrent[0] > Menu[1]) {ActiveBurner = 0; }
    }else if(Menu[5] == 2){
      DPCurrent[2] = Menu[1];
      if((DPCurrent[0] < Menu[1] - hiszterezis) && DPCurrent[0] < Menu[1] && DPCurrent[0] > Menu[2]){
        DPCurrent[2] = Menu[1];
        if(ActiveBurner == 0) ActiveBurner = Menu[4]+1;
      }else if((DPCurrent[0] < Menu[2] - hiszterezis) && DPCurrent[0] < Menu[2]){
        DPCurrent[2] = Menu[1];
        switch (Menu[4]+1){
          case 1:
            ActiveBurner = 2;
          break;
          case 2:
            ActiveBurner = 1;
          break;
        }
      }
      else if((DPCurrent[0] > Menu[1])) ActiveBurner = 0;
    }
    else if(Menu[5] == 3){
      DPCurrent[2] = Menu[1];
      if((DPCurrent[0] < Menu[1] - hiszterezis) && DPCurrent[0] < Menu[1] && DPCurrent[0] > Menu[1] - hiszterezis*2){
        DPCurrent[2] = Menu[1];
        ActiveBurner = Menu[4]+1;
      }else if((DPCurrent[0] < Menu[1] - hiszterezis*2) && DPCurrent[0] < Menu[1]){
        DPCurrent[2] = Menu[1];
        switch (Menu[4]+1){
          case 1:
            ActiveBurner = 2;
          break;
          case 2:
            ActiveBurner = 1;
          break;
        }
      }
      else if(DPCurrent[0] > Menu[1]) ActiveBurner = 0;
    }
  }
  else{
    ActiveBurner = 0;
  }
  burnerOnoff();
}

void saveChanges(){
  if(Menu[3] > 0 && manual == false){      //If manual mode is on
    if(DPCurrent[2] != DPCurrent[0]+100){
      DPCurrent[2] = DPCurrent[0]+100;
      manual = true;
    }
  }
  if(Menu[3] == 0){
    manual = false;
  }
 int value; // Temporary variable to store the read value

EEPROM.get(0, value);
if(value != Menu[0]) {
  EEPROM.put(0, Menu[0]);
}

EEPROM.get(2, value);
if(value != Menu[1]) {
  EEPROM.put(2, Menu[1]);
}

EEPROM.get(4, value);
if(value != Menu[2]) {
  EEPROM.put(4, Menu[2]);
}

EEPROM.get(6, value);
if(value != Menu[4]) {
  EEPROM.put(6, Menu[4]);
}

EEPROM.get(8, value);
if(value != Menu[5]) {
  EEPROM.put(8, Menu[5]);
}

};

int messagetimer = 0;
int connectionActivity = 0;
int blinker = 0;

void loop() {
   if(messagetimer == 10 && !Serial.available()){
      String SMessage = "A";
      SMessage += String(ActiveBurner % 10); // Ensure ActiveBurner is a single digit
      SMessage += String(Menu[3] % 10); // Ensure Menu[0] is a single digit
      SMessage += String(Menu[0] % 10);
      Serial.println(SMessage);

    }else if(messagetimer == 14){
      if(Serial.available()){
        String RMessage = Serial.readString();
        Serial.println(RMessage);
        if(RMessage[0] == 'B'){
          connectionActivity = 0;
          digitalWrite(YellowLed, LOW);
          if(RMessage[1] == '0') Menu[3] = 0;
          if(RMessage[1] == '1') Menu[3] = 1;
          if(RMessage[1] == '2') Menu[3] = 2;
          if(RMessage[2] == '0') Menu[0] = 0;
          if(RMessage[2] == '1') Menu[0] = 1;
          String a = RMessage.substring(3, 7);
          DPCurrent[5] = int(a.toInt());
          a = RMessage.substring(7, 11);
          DPCurrent[6] = int(a.toInt());
          saveChanges();
        }else{
            if(connectionActivity < 300) connectionActivity++;
        }
      }
      messagetimer = 0;
      if(connectionActivity < 300) connectionActivity++;
    }
    if(connectionActivity > 5){
      if(blinker >= 1 && blinker < 2){digitalWrite(YellowLed, HIGH);}
      if(blinker >= 1 && blinker > 2){digitalWrite(YellowLed, LOW); blinker = 0;};
      blinker++; 
  }
    if(scheduler <= 50){
      sensors_event_t humidity, temp;
      aht.getEvent(&humidity, &temp);
      temperaturesum += temp.temperature + calibration;
      DPCurrent[1] = int((humidity.relative_humidity)*100);
      scheduler++;
    }else{
      DPCurrent[0] = int((temperaturesum / scheduler)*100);
      temperaturesum =0;
      scheduler = 0;
    }
    if(menu == false){
      messagetimer++;
      takeAction();
      displaytimer(isstatic);
      for(int i = 0; i < displaytime; i++){
            if(digitalRead(button2) == LOW){ isstatic = BlinkYellow(isstatic); if(isstatic == 'n') displaytimer('b'); delay(100); break;}
            if(digitalRead(button3) == LOW){ isstatic = BlinkYellow(isstatic); if(isstatic == 'n') displaytimer('f'); delay(100); delay(1); break;}
            if(digitalRead(button1) == LOW){ menuTimer = 0; menu = true; break; }
          delay(1);
      }
    }
    else{
        menuController();
        for(int i = 0; i < displaytime; i++){
            if(digitalRead(button1) == LOW){ while(digitalRead(button1) == LOW) digitalWrite(YellowLed, LOW); menuTimer = 0; menuController( 'f'); break;}
            if(digitalRead(button2) == LOW){ while(digitalRead(button2) == LOW) digitalWrite(YellowLed, LOW); menuTimer = 0; menuController( 'n', -1); break;}
            if(digitalRead(button3) == LOW){ while(digitalRead(button3) == LOW) digitalWrite(YellowLed, LOW); menuTimer = 0; menuController( 'n', 1); break;}
          delay(1);
      }
      menuTimer += 1;
      
    }
}
