/**
   Arduino BOMB!

   Copyright (C) 2022, Francesco Mulassano.
*/

#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#include <Tone.h>

Tone tone1;

int Scount = 30; // count seconds
int Mcount = 0; // count minutes
int Hcount = 0; // count hours
int DefuseTimer = 0; // set timer to 0

char Tentativi  = 0;
int TentativiUsati = 0;
int currLengthTentativi = 0;

long secMillis = 0; // store last time for second add
long interval = 1000; // interval for seconds

//lunghezza password 
const byte passwordLenght = 6;
char password[passwordLenght]; // number of characters in our password
char entered[passwordLenght];
char hours[2];
char minutes[2];
char seconds[2];

int currentLength = 0; //defines which number we are currently writing

int currLengthHours = 0;
int currLengthMinutes = 0;
int currLengthSeconds = 0;

int i = 0; 

int ledPin = 7; //red led
int ledPin2 = 6; //yellow led
int ledPin3 = 8; //green led

int filo_1 = 9;
int filo_2 = 10;
int filo_3 = 11;
int filo_4 = 12;

/* Display */
#define I2C_ADDR    0x27
#define LCD_COLUMNS 20
#define LCD_LINES   2

LiquidCrystal_I2C lcd(I2C_ADDR, LCD_COLUMNS, LCD_LINES);

/* Keypad setup */
const byte KEYPAD_ROWS = 4;
const byte KEYPAD_COLS = 4;
byte rowPins[KEYPAD_ROWS] = {5, 4, 3, 2};
byte colPins[KEYPAD_COLS] = {A3, A2, A1, A0};
char keys[KEYPAD_ROWS][KEYPAD_COLS] = {
  { '1', '2', '3', 'A' },
  { '4', '5', '6', 'B' },
  { '7', '8', '9', 'C' },
  { '*', '0', '#', 'D' }
};

Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, KEYPAD_ROWS, KEYPAD_COLS);

uint64_t value = 0;

void showSpalshScreen() {
  lcd.print("*OPERATION BOMB*");
  lcd.setCursor(0, 1);
  String message = "*PRIMA CENTURIA*";
  for (byte i = 0; i < message.length(); i++) {
    lcd.print(message[i]);
    delay(50);
  }
  delay(3000);
}

void(* resetFunc) (void) = 0; //reset

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

  pinMode(filo_1, INPUT_PULLUP);
  pinMode(filo_2, INPUT_PULLUP);
  pinMode(filo_3, INPUT_PULLUP);
  pinMode(filo_4, INPUT_PULLUP);

  int filo_1_stato = digitalRead(filo_1);
  int filo_2_stato = digitalRead(filo_2);
  int filo_3_stato = digitalRead(filo_3);
  int filo_4_stato = digitalRead(filo_4);

  tone1.begin(13);
  
  lcd.init();
  //retro illuminazione
  lcd.backlight();

  pinMode(ledPin, OUTPUT); // sets the digital pin as output
  pinMode(ledPin2, OUTPUT); // sets the digital pin as output
  pinMode(ledPin3, OUTPUT); // sets the digital pin as output

  showSpalshScreen();

  //Ore
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("IMPOSTA Ore:    ");

  while (currLengthHours < 2){
    lcd.setCursor(currLengthHours + 6, 1);
    lcd.cursor();
    char key = keypad.getKey();
    key == NO_KEY;
    if (key != NO_KEY)
    {
      if ((key != '*')&&(key != '#')&&(key != 'A')&&(key != 'B')&&(key != 'C')&&(key != 'D'))
      { 
      lcd.print(key);
      hours[currLengthHours] = key;
      currLengthHours++;
      tone1.play(NOTE_C6, 200);
      }
    }

    Hcount = atoi(hours);
  }
  delay(800);

  //Minuti
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("IMPOSTA Minuti: ");
  while (currLengthMinutes < 2){
    lcd.setCursor(currLengthMinutes + 6, 1);
    lcd.cursor();
    char key = keypad.getKey();
    key == NO_KEY;
    if (key != NO_KEY)
    {
      if((key != '*')&&(key != '#')&&(key != 'A')&&(key != 'B')&&(key != 'C')&&(key != 'D')){
        if(currLengthMinutes == 0){
          if((key != '6')&&(key != '7')&&(key != '8')&&(key != '9')){ 
            lcd.print(key);
            minutes[currLengthMinutes] = key;
            currLengthMinutes++;
            tone1.play(NOTE_C6, 200);
          }
        }else{
          lcd.print(key);
          minutes[currLengthMinutes] = key;
          currLengthMinutes++;
          tone1.play(NOTE_C6, 200);
        }
      }
    }

    Mcount = atoi(minutes);
  }

  delay(800);

  //Secondi
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("IMPOSTA Secondi:");
  while (currLengthSeconds < 2){
    lcd.setCursor(currLengthSeconds + 6, 1);
    lcd.cursor();
    char key = keypad.getKey();
    key == NO_KEY;
    if (key != NO_KEY)
    {
      if ((key != '*')&&(key != '#')&&(key != 'A')&&(key != 'B')&&(key != 'C')&&(key != 'D')){
        if(currLengthSeconds == 0){
          if((key != '6')&&(key != '7')&&(key != '8')&&(key != '9')){  
            lcd.print(key);
            seconds[currLengthSeconds] = key;
            currLengthSeconds++;
            tone1.play(NOTE_C6, 200);
          }
        }else{
          lcd.print(key);
          seconds[currLengthSeconds] = key;
          currLengthSeconds++;
          tone1.play(NOTE_C6, 200);
        }
      }
    }

    Scount = atoi(seconds);
  }
 
  delay(500);

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("IMPOSTA password");
  while (currentLength < passwordLenght)
  {
    lcd.setCursor(currentLength + 0, 1);
    lcd.cursor();
    char key = keypad.getKey();
    key == NO_KEY;
    if (key != NO_KEY)
    {
      if ((key != '*')&&(key != '#'))
      { 
      lcd.print(key);
      password[currentLength] = key;
      currentLength++;
      tone1.play(NOTE_C6, 200);
      }
    }
  }

  delay(500);
 
  if (currentLength == passwordLenght)
  {
    delay(500);
    lcd.noCursor();
    lcd.clear();
    lcd.home();
    lcd.print("PASSWORD scelta:");
    lcd.setCursor(10,1);
    lcd.print(password[0]);
    lcd.print(password[1]);
    lcd.print(password[2]);
    lcd.print(password[3]);
    lcd.print(password[4]);
    lcd.print(password[5]);

    //tone1.play(NOTE_E6, 200);
    delay(800);
    lcd.clear();
    currentLength = 0;
  }


   //tentativi
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Tentativi: ");

  while (currLengthTentativi < 1){
    lcd.setCursor(currLengthTentativi + 6, 1);
    lcd.cursor();
    char key = keypad.getKey();
    key == NO_KEY;
    if (key != NO_KEY)
    {
      if ((key != '*')&&(key != '#'))
      { 
      lcd.print(key);
      Tentativi = key;
      currLengthTentativi++;
      tone1.play(NOTE_C6, 200);
      }
    }
  }

  delay(200);
  lcd.clear();
}

void loop() {

  if(digitalRead(filo_1) == HIGH){ //Esplode
    explode();
  }

  if(digitalRead(filo_2) == HIGH && digitalRead(filo_3) == LOW){ //Velocizza il timer
    interval = 500;
    lcd.setCursor(0,0);
    lcd.print("Il tempo corre! ");
  }

  if(digitalRead(filo_3) == HIGH && digitalRead(filo_2) == LOW){ //Velocizza il timer
    interval = 500;
    lcd.setCursor(0,0);
    lcd.print("Filo sbagliato! ");
  }

  if(digitalRead(filo_3) == HIGH && digitalRead(filo_2) == HIGH){ //Velocizza il timer
    interval = 400;
    lcd.setCursor(0,0);
    lcd.print("Fai presto      ");
  }

  if(digitalRead(filo_4) == HIGH){ //Disinnesco sicuro
    disinnescata();
  }

  //fili
  timer();
  
  char key2 = keypad.getKey(); // get the key
  //if (key2 == '*'){
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Codice: ");
      
    while (currentLength < passwordLenght){ 
      timer();
      char key2 = keypad.getKey(); 
      if (key2 == '*'){
        currentLength = 0;
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print("Codice: ");
      }else if (key2 != NO_KEY){
        lcd.setCursor(currentLength + 7, 0);
        lcd.cursor();
        
        lcd.print(key2);
        entered[currentLength] = key2;
        currentLength++;
        tone1.play(NOTE_C6, 200);
        delay(100);
        lcd.noCursor();
        lcd.setCursor(currentLength + 6, 0);
        lcd.print("*");
        lcd.setCursor(currentLength + 7, 0);
        lcd.cursor();
      }
    }

    if (currentLength == passwordLenght){
      if (entered[0] == password[0] && entered[1] == password[1] && entered[2] == password[2] && entered[3] == password[3] && entered[4] == password[4] && entered[5] == password[5]){
        disinnescata();
      }else{
        lcd.noCursor();
        lcd.clear();
        lcd.home();
        lcd.print("*Codice errato!*");
        digitalWrite(ledPin, HIGH);
        Tentativi--;
        tone1.play(NOTE_A2, 200);
        delay(500);
        digitalWrite(ledPin, LOW);
        lcd.clear();


        if(Tentativi == '0'){
          explode();
        }else{
          lcd.print("Tentativi");
          lcd.setCursor(0, 1);
          lcd.print("rimanenti");
          lcd.setCursor(11, 1);
          lcd.print(Tentativi);
          delay(1500);
        }    
      }
      lcd.clear();
      currentLength = 0;
      }
  //  }  
  }

void disinnescata(){
  lcd.noCursor();
        lcd.clear();
        lcd.home();
        lcd.print("*** MISSIONE ***");
        lcd.setCursor(0, 1);
        lcd.print("*** CONCLUSA ***");
        currentLength = 0;
        digitalWrite(ledPin3, HIGH);
        delay(2500);
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print("*DEVI RIAVVIARE*");
        lcd.setCursor(0,1);
        lcd.print("*IL DISPOSITIVO*");
        delay(1000000);
}

void explode(){
  lcd.clear();
  if (Hcount > 0)
    {
      Hcount = 0;
    }
  if (Mcount > 0)
    {
      Mcount = 0;
    }
  if (Scount > 0)
    {
      Scount = 0;
    }
}


void timer()
{
  if (Hcount <= 0)
  {
    if ( Mcount < 0 )
    {
      lcd.noCursor();
      lcd.clear();
     // lcd.home();
      lcd.print("* HAI  FALLITO *");
      lcd.setCursor (0,1);
      lcd.print("* LA  MISSIONE *");
      
      unsigned long stop = millis();

      while (millis()-stop < 7000 && Mcount < 0) // 7 secondi
      {
        digitalWrite(ledPin, HIGH); // sets the LED on
        tone1.play(NOTE_A2, 90);
        delay(100); 
        digitalWrite(ledPin, LOW); // sets the LED off
        tone1.play(NOTE_A2, 90);
        delay(100); 
        digitalWrite(ledPin2, HIGH); // sets the LED on
        tone1.play(NOTE_A2, 90);
        delay(100); 
        digitalWrite(ledPin2, LOW); // sets the LED off
        tone1.play(NOTE_A2, 90);
        delay(100); 
        digitalWrite(ledPin3, HIGH); // sets the LED on
        tone1.play(NOTE_A2, 90);
        delay(100); 
        digitalWrite(ledPin3, LOW); // sets the LED off
        tone1.play(NOTE_A2, 90);
        delay(100);
      }
      resetFunc();  
    } 
  }

  lcd.setCursor (0,1); // sets cursor to 2nd line
  lcd.print ("Timer:");

  if (Hcount >= 10)
    {
      lcd.setCursor (7,1);
      lcd.print (Hcount);
    }
  if (Hcount < 10) 
    {
      lcd.setCursor (7,1);
      lcd.write ("0");
      lcd.setCursor (8,1);
      lcd.print (Hcount);
    }

  lcd.print (":");

  if (Mcount >= 10)
    {
      lcd.setCursor (10,1);
      lcd.print (Mcount);
    }
  if (Mcount < 10) 
    {
      lcd.setCursor (10,1);
      lcd.write ("0");
      lcd.setCursor (11,1);
      lcd.print (Mcount);
    }
    
  lcd.print (":");

  if (Scount >= 10) 
    {
      lcd.setCursor (13,1);
      lcd.print (Scount);
    }
  if (Scount < 10) 
    {
      lcd.setCursor (13,1);
      lcd.write ("0");
      lcd.setCursor (14,1);
      lcd.print (Scount);
    }

  if (Hcount <0) 
    {
      Hcount = 0; 
    }

  if (Mcount <0) 
    {
      Hcount --; 
      Mcount = 59; 
    }

  if (Scount <1) // if 60 do this operation
    {
      Mcount --; // add 1 to Mcount
      Scount = 59; // reset Scount
    }

  if (Scount > 0) // do this oper. 59 times
    {
      unsigned long currentMillis = millis();
  
      if(currentMillis - secMillis > interval) 
        {
          secMillis = currentMillis;
          Scount --; // add 1 to Scount
          digitalWrite(ledPin2, HIGH); // sets the LED on
          delay(10); // waits for a second
          digitalWrite(ledPin2, LOW); // sets the LED off
          delay(10); // waits for a second
          //lcd.clear();
        }
    }
}