#include <LiquidCrystal.h>
#include <ArduinoJson.h>
#include <Keypad.h>
 
// Keypad
#define ROW_NUM     4 // four rows
#define COLUMN_NUM  4 // four columns

char keys[ROW_NUM][COLUMN_NUM] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};
byte pin_rows[ROW_NUM]      = {15, 2, 4, 16}; // 2, 0, 4, 16
byte pin_column[COLUMN_NUM] = {17, 5, 18, 19};  

Keypad keypad = Keypad( makeKeymap(keys), pin_rows, pin_column, ROW_NUM, COLUMN_NUM );


// LCD
LiquidCrystal lcd(32, 33, 25, 26, 27, 14);


// Variablen
int status = 0; // 0 = Ready for Game; 1 = Read for plant; 2 = planted; 3 = Defused; 4 = Detonated; 5 = Time ran out
String code = "";
String inputcode = "";

// Time Variables
int gamebegintime;

// config
String team = "red";
int redcount = 0;
int yellowcount = 0;
String data[30][3];


void setup() {
  Serial.begin(115200);

  // LED's
  pinMode(23, OUTPUT); // 22
  pinMode(22, OUTPUT); // 1
  pinMode(1, OUTPUT); // 3
  RGBLed(0, 255, 0);

  // Buzzer
  ledcSetup(0, 2000, 12);
  ledcAttachPin(12, 0); // Pin: 15
  delay(1000);

  // LCD
  lcd.begin(1, 15);
  lcd.setCursor(0, 0);
}

void loop() {
  switch(status){
    case 0:
      Menu();
      break;
    case 1:
      ReadyForPlant();
     break;
    case 2:
      Planted();
      break;
    case 3:
      Defused();
      break;
    case 4:
      Detonated();
      break;
    case 5:
      Timeout();
      break;
  }
}

/*------------- GAMEMODE BOMB DEFUSE -------------*/
// 0
void Menu(){
  //Serial.println((String)data);
  int starttime = millis();
  bool inactive = false;
  int resettime = 10000000;

  if(team=="red"){
    RGBLed(255,0,0);
  }else{
    RGBLed(255,255,0);
  }
  
  lcd.setCursor(0, 0);
  lcd.print("Ready for Game");
  lcd.setCursor(0, 1);
  lcd.print("Press 'D'");


  while(true){
    char key = keypad.getKey();

    if(key && inactive){ // Gets out of screen saver
      starttime = millis();
      break;
    }else if(key == '*'){ // Change Team
      if(team=="red"){
        team = "yellow";
        RGBLed(255,255,0);
      }else{
        team = "red";
        RGBLed(255,0,0);
      }
    }else if(key == 'D'){ // Enter Game
      break;
    }else if(key == '#'){ // Resets Round Data
        redcount = 0;
        yellowcount = 0;
        clearDisplay();
        lcd.setCursor(0, 0);
        lcd.print("Round data");
        lcd.setCursor(0, 1);
        lcd.print("reset");

        ledcWriteTone(0, 2731);
        delay(1000);
        ledcWriteTone(0, 0);
        clearDisplay();

        lcd.setCursor(0, 0);
        lcd.print("Ready for Game");
        lcd.setCursor(0, 1);
        lcd.print("Press 'D'");
    }
    else{

      if(millis()-starttime > 120000 && !inactive){
        RGBLed(0,0,0);
        inactive = true;
        clearDisplay();
        lcd.setCursor(0, 0);
        lcd.print("   Heldenhalle  ");
        lcd.setCursor(0, 1);
        lcd.print("   Lahntal      ");
      }
    }
   
    delay(10);
  }
  if(inactive){
      status = 0;
    }
    else{
      status = 1;
    }
    
    clearDisplay();

}
// 1
void ReadyForPlant(){
  gamebegintime = millis();
  int nowtime = millis();
  ledcWriteTone(0, 2000);
  delay(50);
  ledcWriteTone(0, 0);
  delay(40);
  ledcWriteTone(0, 2500);
  delay(50);
  ledcWriteTone(0, 0);
  delay(40);
  ledcWriteTone(0, 3000);
  delay(50);
  ledcWriteTone(0, 0);

  RGBLed(255,0,0);
  // Creates Code
  code = "";
  inputcode = "";
  for(int i = 0; i <= 5; i++){
    code += random(9);
  }

  while(status == 1){
    nowtime = millis();
    if(nowtime-gamebegintime > 600000)//600000
    {
      status = 5;
    }
    char key = keypad.getKey();
    if(key){
      ledcWriteTone(0, 2231);
      delay(50);
      ledcWriteTone(0, 0);
      switch(key){
      case 'A':
        inputcode = "";
        lcd.setCursor(5, 1);
        lcd.print("          ");
        break;
      case 'D':
        if(inputcode == code){
          status = 2;
        }else{
          inputcode = "";
          lcd.setCursor(5, 1);
          lcd.print("            ");
        }
        break;
      default:
        inputcode += key;
      }
    }
    lcd.setCursor(0, 0);
    lcd.print("Code:"+code);
    lcd.setCursor(0, 1);
    lcd.print("---->"+inputcode);
  }
  clearDisplay();
  inputcode = "";
}

// 2
void Planted(){
  int seconds = 60;
  int starttime = millis();
  int currenttime = millis();
  int lastactive = millis();
  int nextbeep = millis();
  bool state = true;
  while(status == 2){
    // beep
    if(state){
      if(seconds > 30){
        nextbeep = millis() + 1000;
      }else{
        nextbeep = (int) (millis() + 1000 / ((30 - seconds) * (30 - seconds) * 0.01 + 1));
      }
    }
    
    if(millis() >= nextbeep){
      ledcWriteTone(0, 3231);
      RGBLed(255,0,0);
      lastactive = millis();
      state = true;
    }

    if(millis()-lastactive >= 100){
      ledcWriteTone(0, 0);
      RGBLed(0,0,0);
      state = false;
    }
    if(millis()-currenttime >= 1000){
      seconds -= 1;
      currenttime = millis();
    }
    if(currenttime-starttime >= 60000){
      status = 4;
      break;
    }
    

    char key = keypad.getKey();
    if(key){
      ledcWriteTone(0, 2231);
      delay(50);
      ledcWriteTone(0, 0);
      switch(key){
      case 'A':
        inputcode = "";
        lcd.setCursor(5, 1);
        lcd.print("     ");
        break;
      case 'D':
        if(inputcode == code){
          status = 3;
        }else{
          inputcode = "";
          lcd.setCursor(5, 1);
          lcd.print("        ");
        }
        break;
      default:
        inputcode += key;
      }
    }
    lcd.setCursor(0, 0);
    lcd.print("Code:"+code);
    if(seconds < 10){
      lcd.setCursor(14, 0);
      lcd.print(" ");
      lcd.setCursor(15, 0);
      lcd.print(seconds);
    }else{
      lcd.setCursor(14, 0);
      lcd.print(seconds);
    }
    lcd.setCursor(0, 1);
    lcd.print("---->"+inputcode);
  }
  ledcWriteTone(0, 3231);
  clearDisplay();
  inputcode = "";
}

// 3
void Defused(){
  SaveGameData("defused");
  ledcWriteTone(0, 0);
  RGBLed(0,255,255);
  lcd.setCursor(0, 0);
  lcd.print("Bomb defused");
  lcd.setCursor(0, 1);
  lcd.print("Press 'D'");
  while(keypad.getKey() != 'D'){

  }
  status = 0;
  clearDisplay();
}

// 4
void Detonated(){
  SaveGameData("detonated");
  RGBLed(255,255,0);
  lcd.setCursor(0, 0);
  lcd.print("Bomb exploded");
  lcd.setCursor(0, 1);
  lcd.print("Press 'D'");
  delay(3000);
  ledcWriteTone(0, 0);
  while(keypad.getKey() != 'D'){

  }
  status = 0;
  clearDisplay();
}

// 5
void Timeout(){
  SaveGameData("timeout");
  RGBLed(255,255,0);
  lcd.setCursor(0, 0);
  lcd.print("Time ran out");
  lcd.setCursor(0, 1);
  lcd.print("Press 'D'");

  // Beep
  ledcWriteTone(0, 1200);
  delay(500);
  ledcWriteTone(0, 0);
  delay(500);
  ledcWriteTone(0, 1200);
  delay(500);
  ledcWriteTone(0, 0);
  delay(500);
  ledcWriteTone(0, 1200);
  delay(2000);
  ledcWriteTone(0, 0);

  while(keypad.getKey() != 'D'){

  }
  status = 0;
  clearDisplay();
}

/*-------------- GAMEMODE HOLD SITE --------------*/







/*------------------- HELPER -------------------*/
void clearDisplay(){
  lcd.clear();
  lcd.begin(1, 15);
}

void RGBLed(int r, int g, int b){
  digitalWrite(23, r);
  digitalWrite(22, g);
  digitalWrite(1, b);
}

void SaveGameData(String type){

  int curround = (int)(redcount+yellowcount);

  if(type == "defused" || type == "timeout"){
    if(team == "red"){
        data[curround][0] = "yellow";
        yellowcount += 1;
      }else{
        data[curround][0] = "red";
        redcount += 1;
      }
  }else if (type == "detonated"){
     if(team == "yellow"){
        data[curround][0] = "yellow";
        yellowcount += 1;
      }else{
        data[curround][0] = "red";
        redcount += 1;
      }
  }
  
  data[curround][1] = type;

  int minutes_raw = (int) ((millis()-gamebegintime)/1000/60);
  int seconds_raw = ((millis()-gamebegintime)/1000-(60*minutes_raw));

  String minutes = (String)(minutes_raw);
  String seconds = (String)(seconds_raw);

  if(minutes_raw < 10){
    minutes = "0" + (String)(minutes_raw);
  }
  if(seconds_raw < 10){
    seconds = "0" + (String)(seconds_raw);
  }

  data[curround][2] = minutes + ":" + seconds;

  for(int i = 0; i < 30; i++){
    if(data[i][0] != ""){
      Serial.println(data[i][0]);
      Serial.println(data[i][1]);
      Serial.println(data[i][2]);
    }else{
      break;
    }
  }
}