/*

  Freigabe (Release) =
  Zimmernummer (room number) = er kaj hocche room number pathano






*/
#include "Variables.h"
#include "Timer.h"
#include <SPI.h>
#include "MFRC522.h"
#include <LiquidCrystal_I2C.h>
#include "pcf8574.h"
#include "PubSubClient.h"
#include <WiFi.h>

int lcdColumns          = 20;
int lcdRows             = 4;
int RST_PIN             = 3;            // Configurable, see typical pin layout above
int SS_PIN              = 8;            // Configurable, see typical pin layout above

LiquidCrystal_I2C   lcd(0x27, lcdColumns, lcdRows);
WiFiClient          espClient;
PubSubClient        client(espClient);
PCF8574             exBrd(0x20);
MFRC522             mfrc522(SS_PIN, RST_PIN);
Timer               timer1000, timer5000, timer10000;

char roomNumber[4];
MFRC522::MIFARE_Key key;
MFRC522::StatusCode status;

byte myKey[]    = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
byte block      = 12;
byte len        = 18;
byte buffer[18];

void RFIDInit() {
  mfrc522.PCD_Init();
  for (byte i = 0; i < 6; i++) key.keyByte[i] = myKey[i];
}

void RFIDreadAndSend() {
  Backlight = millis() + 60000;
  mqttRoom = roomNumber;
}

int RFIDRead() {
  while (mfrc522.PICC_IsNewCardPresent()) {
    Serial.println("A new card is present!");
    if (mfrc522.PICC_ReadCardSerial()) {
      Serial.println("Card UID read successfully:");
      //authentificate RFID Card
      status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 12, &key, &(mfrc522.uid));
      if (status == MFRC522:: STATUS_OK) {
        status = mfrc522.MIFARE_Read(block, buffer, &len);
        if (status == MFRC522::STATUS_OK) {
          // construct the Room Number out of the Array, without the first 0
          //3 digits +1 for null
          sprintf(roomNumber, "%c%c%c%c", buffer[1], buffer[2], buffer[3], '\0');
          Serial.println(roomNumber);
          RFIDreadAndSend();
          return 1; // Read sucessfully
        }
      }
      else {
        return -1; //Auth Failed
      }
    }
    return 0; // Read failed
  }
  return -2; // No new card
}

void displayInit() {
  lcd.init();
  lcd.backlight();                  // activat Backlight
  Backlight = millis() + 60000;     // add 60 seconds
  backlightIsOn = true;             // set status for Backlight
  displayDE();
  // Startup Waittime
  delay(500);
}

void displayDE()  {
  if (timer1000.checkNreset()) {
    lcd.clear();
    // lcd.autoscroll();
    lcd.setCursor(0, 0);  lcd.print("Karte auf Sensor    ");
    lcd.setCursor(0, 1);  lcd.print("Nummer 1 auflegen   ");
    lcd.setCursor(0, 3);  lcd.print("          English ->");
  }
}


void displayEN()  {
  if (timer1000.checkNreset()) {
    lcd.clear();
    lcd.setCursor(0, 0);  lcd.print("Place your RoomCard ");
    lcd.setCursor(0, 1);  lcd.print("on Sensor Number 1  ");
    lcd.setCursor(0, 3);  lcd.print("          Deutsch ->");
  }
}

void menuLevel1() {
  if (language == 0) {
    displayDE();
  }
  else {
    displayEN();
  }
}

void menuLevel2() {
  if (timer1000.checkNreset()) {
    lcd.clear();
    if (language == 0) {
      lcd.setCursor(0, 0);  lcd.print("Um zu Laden die     ");
      lcd.setCursor(0, 1);  lcd.print("Karte auf Sensor 2  ");
      lcd.setCursor(0, 2);  lcd.print("Preis / KwH EUR ");    lcd.print(wallboxPreis / 100.0);
      lcd.setCursor(0, 3);  lcd.print("        Abbrechen ->");
    }
    else {
      lcd.setCursor(0, 0);  lcd.print("To start charging   ");
      lcd.setCursor(0, 1);  lcd.print("put Card on Sensor 2");
      lcd.setCursor(0, 2);  lcd.print("Price / KwH EUR ");    lcd.print(wallboxPreis / 100.0);
      lcd.setCursor(0, 3);  lcd.print("            Abort ->");
    }
  }
}

void charging() {
  if (timer1000.checkNreset()) {
    lcd.clear();
    if (language == 0) {
      // getFreigabeMQTT();
      lcd.setCursor(0, 0);  lcd.print("Ladevorgang laueft: ");
      lcd.setCursor(0, 1);  lcd.print("                    ");
      lcd.setCursor(0, 2);  lcd.print("Leistung: "); lcd.print(kw); lcd.print(" KW");
      lcd.setCursor(0, 3);  lcd.print("Gesamt: "); lcd.print(kwh); lcd.print(" KwH");
    }
    else {
      // getFreigabeMQTT();
      lcd.setCursor(0, 0);  lcd.print("Charging started:   ");
      lcd.setCursor(0, 1);  lcd.print("                    ");
      lcd.setCursor(0, 2);  lcd.print("Leistung: "); lcd.print(kw); lcd.print(" KW");
      lcd.setCursor(0, 3);  lcd.print("Gesamt: "); lcd.print(kwh); lcd.print(" KwH");
    }
  }
}

void readingFailed() {
  if (timer1000.checkNreset()) {
    lcd.clear();
    lcd.setCursor(0, 0);    lcd.print("Reading failed");
    lcd.setCursor(0, 1);    lcd.print(mfrc522.GetStatusCodeName(status));
    lcd.setCursor(0, 3);    lcd.print("Please ask Reception");
    Serial.print("Reading failed: ");
    Serial.println(mfrc522.GetStatusCodeName(status));
  }
}

void authFailed() {
  if (timer1000.checkNreset()) {
    lcd.clear();
    lcd.setCursor(0, 0);  lcd.print("      FEHLER");
    lcd.setCursor(0, 1);  lcd.print(mfrc522.GetStatusCodeName(status));
    lcd.setCursor(0, 3);  lcd.print("Please ask Reception");
    Serial.print("Authentication failed: "); Serial.println(mfrc522.GetStatusCodeName(status));
  }
}

void exBrdInit() {
  pinMode(exBrd, 0, INPUT_PULLUP);    //  D0 for lock authorization
  pinMode(exBrd, 1, INPUT_PULLUP);    //  D1 for button
  pinMode(exBrd, 2, INPUT_PULLUP);    //  Test Button 3
  pinMode(exBrd, 3, INPUT_PULLUP);    //  Test Button 4
}

bool readLockAuth() {
  return digitalRead(exBrd, 0);
}

bool readButton() {
  return digitalRead(exBrd, 1);
}

void wificonnect() {
  WiFi.persistent(false);
  WiFi.begin(wifi_ssid, wifi_password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    lcd.clear(); lcd.setCursor(0, 0);  lcd.print("Connecting to WIFI");
    Serial.println("Connecting to WIFI..");
  }
  lcd.clear(); lcd.setCursor(0, 0);  lcd.print("Succesful connection");
  Serial.println("Succesfully connected!");
}

void sendToMQTT() {
  wallboxFreigabe = 1;
  char wallboxFreigabe2[2];
  sprintf(wallboxFreigabe2, "%d", wallboxFreigabe);
  mqttwallboxfreigabe = wallboxFreigabe2;
  // mqttwallboxfreigabe = itoa(wallboxFreigabe, wallboxFreigabe2, 10);
  client.publish("Arduino/Wallbox1/Zimmernummer", mqttRoom);
  client.publish("Arduino/Wallbox1/Freigabe", mqttwallboxfreigabe);
}

void MQTTCallback(char* topic, byte* payload, unsigned int length) {
  String Command = "";
  for (int i = 0; i < length; i++) {
    Command = Command + (char)payload[i];
  }
  int Wert = Command.toInt();
  if (strcmp(topic, "Arduino/Wallbox1/Freigabe") == 0)  {
    Serial.println("Freigabe: ");
    Serial.println(Wert);
    wallboxFreigabe = Wert;
  }
  if (strcmp(topic, "Arduino/Wallbox1/KW") == 0)  {
    Serial.println("KW: ");
    Serial.println(Wert);
    kw = Wert;
  }
  if (strcmp(topic, "Arduino/Wallbox1/KWH") == 0)  {
    Serial.println("KWH: ");
    Serial.println(Wert);
    kwh = Wert;
  }

  if (strcmp(topic, "Arduino/Wallbox1/VehicleConnection") == 0)  {
    Serial.println("Vehicle Status: ");
    Serial.println(Wert);
    vehicleIsConnected = Wert;
  }

  if (strcmp(topic, "Arduino/Wallbox/Preis") == 0)  {
    Serial.println("Preis: ");
    Serial.println(Wert);
    wallboxPreis = Wert;
  }
}

void mqttReconnect() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect(clientId, mqtt_user, mqtt_password)) {
      lcd.clear(); lcd.setCursor(0, 0);  lcd.print("Succesful connection");
      Serial.println("MQTT Connected!");
      client.subscribe("Arduino/Wallbox1/Freigabe");
      client.subscribe("Arduino/Wallbox1/KW");
      client.subscribe("Arduino/Wallbox1/KWH");
      client.subscribe("Arduino/Wallbox/Preis");
      client.subscribe("Arduino/Wallbox1/VehicleConnection");
    }
    else {
      lcd.clear(); lcd.setCursor(0, 0);  lcd.print("Connecting to MQTT");
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println("try again in 5 seconds");
      // Wait 3 seconds before retrying
      delay(3000);
    }
  }
}

void mqttInit() {
  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(MQTTCallback);
  mqttReconnect();
}

void setup() {
  Serial.begin(115200);
  SPI.begin();
  timer1000.begin(DisplayRefresh, true);
  timer5000.begin(ConnectionRefresh, true);
  timer10000.begin(ConnectCar, true);

  pinMode(5, INPUT_PULLUP);
  pinMode(19, INPUT_PULLUP);
  pinMode(18, INPUT_PULLUP);
  pinMode(12, INPUT_PULLUP);


  displayInit();
  wificonnect();
  mqttInit();
  RFIDInit();
  exBrdInit();
}

void loop() {
  if (WiFi.status() != WL_CONNECTED) {
    wificonnect();
    mqttReconnect();
  }

  client.loop();
  if (millis() > Backlight) {
    lcd.noBacklight();
    backlightIsOn = false;
  }

  // If button is pressed
  if (digitalRead(12) == LOW) {
    //check If Backlight is on
    if (backlightIsOn && timer1000.checkNreset()) {
      //language change
      if (language == 0) {
        language = 1;
        displayEN();
      }
      else {
        displayDE();
        language = 0;
      }
    }
    else {
      //turn on Backlight
      lcd.backlight();
      Backlight = millis() + 60000;
      backlightIsOn = true;
    }
  }
  //When just started the charging
  if (wallboxFreigabe == 0) {
    if (ladungBeendet == 0) {
      if (digitalRead(5) == LOW) {
        // display menu level 2
        menuLevel2();
        //RFID scan
        //RFIDRead() == 1
        if (digitalRead(18) == LOW) {
          RFIDreadAndSend();
          sendToMQTT();
          ladungBeendet = 1;
          startTime = millis();
          Serial.print("ladungBeendet: ");
          Serial.print(ladungBeendet);
          Serial.println();
        }
        else if (digitalRead(19) == LOW) {
          authFailed();
        }
        else if (RFIDRead() == 0) {
          readingFailed();
        }
      }
      else {
        menuLevel1();
      }
    }
    else {
      Serial.println("Charge Finish");
      lcd.clear();
      lcd.setCursor(0, 0);  lcd.print("Charge Finish!");
      ladungBeendet = 0;
    }
  }
  else {
    if (ladungBeendet == 1) {
      if (vehicleIsConnected == 1) {
        charging();
      }
      else if (vehicleIsConnected == 0) {
        if (millis() - showTime >= 1000 && millis() - startTime <= 60000) {
          lcd.clear();
          lcd.setCursor(0, 0);  lcd.print("Connect your car");
          lcd.setCursor(0, 1);  lcd.print("to the station");
          showTime = millis();
        }
        else if (millis() - startTime >= 60000) {
          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("Failed to Connect Car");
          delay(3000);
        }
      }
    }
    else {
      wallboxFreigabe = 0;
      char wallboxFreigabe2[2];
      sprintf(wallboxFreigabe2, "%d", wallboxFreigabe);
      mqttwallboxfreigabe = wallboxFreigabe2;
      client.publish("Arduino/Wallbox1/Freigabe", mqttwallboxfreigabe);
    }
  }
}
Charge
Language
RFID Card
Switch 1