//-----------------------------------------//
//
//-----------------------------------------//


//-----------------------------------------//

#include <Keypad.h>
#include <LiquidCrystal.h>


//-----------------------------------------//
//pinnout
//-----------------------------------------//
const int buzz = 10;

const int rs = 10, en = 9, d4 = 7, d5 = 6, d6 = 5, d7 = 4;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

//-----------------------------------------//
//settings
//-----------------------------------------//
const int ROW_NUM = 4; //four rows
const int COLUMN_NUM = 3; //three columns

char keys[ROW_NUM][COLUMN_NUM] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};

byte pin_rows[ROW_NUM] = {A0, A1, A2, A3};   //connect to the row pinouts of the keypad
byte pin_column[COLUMN_NUM] = {A4, A5, 2}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), pin_rows, pin_column, ROW_NUM, COLUMN_NUM );
//-----------------------------------------//
//minute setting
//-----------------------------------------//
String inputString;
long prepTime;
long defTime;
char key = keypad.getKey();
//test-only!!!!! normal = 59
int secTime = 1;
int minTime = 5;
//-----------------------------------------//
//timer
//-----------------------------------------//
int Min = 0;
int sec = 0;
unsigned int check_val = 50;
bool PREP = true;
bool RUN = true;
bool min_flag = true;

int prepare;
int minute;
//-----------------------------------------//
//random defuse number
//-----------------------------------------//
String inputNumber;
int pressCount = 1;
long inputInt;
long randNumber;
bool run = true;
//-----------------------------------------//

//armed?
const int armed = 13;
const int disArmed = 12;

bool WIN = false;

void setup() {
  //time settings
  Serial.begin(9600); // maximum number of digit for a number is 10, change if needed
  inputString.reserve(2); // maximum number of digit for a number is 10, change if needed

  //armed?
  pinMode(armed, OUTPUT);
  pinMode(disArmed, OUTPUT);

  // LCD Initialization
  lcd.clear();

  //random generator logic
  inputString.reserve(16); // maximum number of digit for a number is 10, change if needed
  randomSeed(analogRead(0));
  randNumber = random(999, 10000);
  Serial.println(randNumber);

  //timer logic
  pinMode(buzz, OUTPUT); 
  digitalWrite(buzz, LOW);

  //run code
  digitalWrite(disArmed, HIGH);
  prep();

  //passwordLogic();
}

void loop()
{
Serial.println("loop");
}

void prep()
{
  Serial.println("Enter Preparation Time");

  lcd.setCursor(0, 0);                                   //   Four is added to pressCount to center the input on the LCD
  lcd.print("Enter Prep Time");
  lcd.setCursor(0, 1);

  while (prepTime == 0)
  {
    char key = keypad.getKey();
    if (key) 
    {
    Serial.println(key);

    if (key >= '0' && key <= '9') 
    {     // only act on numeric keys
      inputString += key;
      lcd.print(key);              // append new character to input string
    } 
    else if (key == '#') 
    {
      if (inputString.length() > 0) {
        prepTime = inputString.toInt(); // YOU GOT AN INTEGER NUMBER
        inputString = "";               // clear input
        // DO YOUR WORK HERE
      Serial.print("Preparation Time Rntered: ");
      Serial.println(prepTime);
      deftime();
      }
    } 
    else if (key == '*') 
    {
      inputString = "";
      lcd.clear();
      lcd.setCursor(0, 0);                                   //   Four is added to pressCount to center the input on the LCD
      lcd.print("Enter Prep Time");
      lcd.setCursor(0, 1);                 // clear input
    }
    /*Serial.println(inputString);
    Serial.println(inputInt);*/
    }
  }
}

void deftime()
{
  Serial.println("Enter Defuse Time");

  lcd.clear();
  lcd.setCursor(0, 0);                                   //   Four is added to pressCount to center the input on the LCD
  lcd.print("Enter Def time");
  lcd.setCursor(0, 1);

  while (defTime == 0)
  {
    char key = keypad.getKey();
    if (key) 
    {
    Serial.println(key);

    if (key >= '0' && key <= '9') 
    {     // only act on numeric keys
      inputString += key;
      lcd.print(key);              // append new character to input string
    } 
    else if (key == '#') 
    {
      if (inputString.length() > 0) {
        defTime = inputString.toInt(); // YOU GOT AN INTEGER NUMBER
        inputString = "";               // clear input
        // DO YOUR WORK HERE
      Serial.print("Defuse Time: ");
      Serial.println(defTime);
      timerStart();
      }
    } 
    else if (key == '*') 
    {
      inputString = "";
      lcd.clear();
      lcd.setCursor(0, 0);                                   //   Four is added to pressCount to center the input on the LCD
      lcd.print("Enter Def Time:");
      lcd.setCursor(0, 1);                 // clear input
    }
    /*Serial.println(inputString);
    Serial.println(inputInt);*/
    }
  }
}


void timerStart()
{
  Serial.println("timer started");
  Serial.print("preparation time: ");
  Serial.println(prepTime);
  Serial.print("defuse time: ");
  Serial.println(defTime);

  lcd.clear();
  timersRun();
}


//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------


void timersRun()
{

  prepare = prepTime;
  minute = defTime;
  Serial.println(prepare);
  Serial.println(minute);

  Min = prepare;

  
  delay(1500);
  INIT();
  delay(1000);
  prepTimer();
  lcd.clear();
}


int startTimer(unsigned long interval, void (*action)(int));

void prepTimer()
{
    lcd.clear();
    delay(250);
    PREP = true;
    while (PREP)
    {
      sec = sec - 1;
      delay(1000);
      if (sec == -1)
      {
        sec = secTime;
        Min = Min - 1;
      }
      lcd.setCursor(2, 0);
      lcd.print("PREPARATION");
      lcd.setCursor(5, 1);
      //lcd.print(':');
      if (Min <= 9)
      {
        lcd.print('0');
      }
      lcd.print(Min);
      lcd.print(':');
      if (sec <= 9)
      {
        lcd.print('0');
      }
      lcd.print(sec);
      if (Min == 0 && sec == 0)
      {
        lcd.setCursor(4, 0);
        PREP = false;
        for (int i = 0; i < 20; i++)
        {
          digitalWrite(buzz, HIGH);
          delay(1000);
          digitalWrite(buzz, LOW);
          delay(1000);
          Min = minute;
          passwordLogic();
        }
      }
    }
}


void INIT()
{
  Min = Min;
  sec = 0;
  lcd.clear();
  lcd.setCursor(5, 0);
  lcd.print("READY?");
  lcd.setCursor(5, 1);
  if (Min <= 9)
  {
    lcd.print('0');
  }
  lcd.print(Min);
  lcd.print(':');
  if (sec <= 9)
  {
    lcd.print('0');
  }
  lcd.print(sec);
  min_flag = true;
  delay(500);
}

void boom()
{
  lcd.clear();
  lcd.setCursor(1, 0);
  lcd.print("TIME  EXPIRED");
  lcd.setCursor(0, 1);
  //lcd.print("******WIN*******");
  digitalWrite(buzz, HIGH);
  digitalWrite(armed, HIGH);
  delay(10000);
  digitalWrite(buzz, LOW);
  digitalWrite(armed,LOW);
  delay(250);
}

void win()
{
 digitalWrite(armed, LOW);
  lcd.clear();
  lcd.setCursor(2, 0);
  lcd.print("DEFUSED");
  lcd.setCursor(10, 0);
  lcd.print(Min);
  lcd.print(":");
  if (sec < 10)
  {
    lcd.print("0");
    lcd.print(sec);
  }
  else if (sec >= 10)
  {
  lcd.print(sec);
  }
  lcd.setCursor(0, 1);
  //lcd.print("******WIN*******");
  WIN = true;
  while (WIN = true)
  {
  digitalWrite(buzz, HIGH);
  digitalWrite(disArmed, HIGH); 
  delay(250);
  digitalWrite(buzz, LOW);
  digitalWrite(disArmed, LOW);
  delay(250);
  }
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------


  
void passwordLogic()
{
  digitalWrite(disArmed, LOW);
  digitalWrite(armed, HIGH);

  Serial.println("Enter Password");
  
  lcd.clear();
  lcd.setCursor(10, 1);
  lcd.print(randNumber);
  //lcd.setCursor(1, 1);

  static unsigned long nextSwitchTime = millis()+1;

  while (run = true)
  {
  //Serial.println(pressCount);

  if( nextSwitchTime < millis() )
  {
    nextSwitchTime = millis() + 1000L;

    sec = sec - 1;
      //delay(1000);
      if (sec == -1)
      {
        sec = minTime;
        Min = Min - 1;
      }
      lcd.setCursor(1, 0);
      lcd.print("DEFUSE");
      lcd.setCursor(9, 0);
      if (Min <= 9)
      {
        lcd.print('0');
      }
      lcd.print(Min);
      lcd.print(':');
      if (sec <= 9)
      {
        lcd.print('0');
      }
      lcd.print(sec);
      if (Min == 0 && sec == 0)
      {
        lcd.setCursor(4, 0);
        RUN = false;
        for (int i = 0; i < 20; i++)
        {
          boom();
        }
      }

    if (pressCount == 1)
    {
      lcd.setCursor(2, 1);
    }
    else if (pressCount == 2)
    {
      lcd.setCursor(3, 1);
    }
    else if (pressCount == 3)
    {
      lcd.setCursor(4, 1);
    }
    else if (pressCount == 4)
    {
      lcd.setCursor(5, 1);
    }
  }

    char key = keypad.getKey();
    if (key) 
    {
    Serial.println(key);

    if (key >= '0' && key <= '9') 
    {     // only act on numeric keys
      inputNumber += key;
      pressCount++;
      lcd.print(key);              // append new character to input string
    }  

      if (inputNumber.length() == 4)
      {
      inputInt = inputNumber.toInt();
      if (inputInt == randNumber)
      {
         // YOU GOT AN INTEGER NUMBER
        inputNumber = "";               // clear input
        // DO YOUR WORK HERE
      Serial.println("defused");
      run = false;
      RUN = false;
      Serial.println(Min);
      Serial.println(sec);
      win();
      }
      else if (inputInt != randNumber)
      {        
      inputNumber = "";
      pressCount = 1;
      Serial.print("wrong");
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("-----WRONG------");
      delay(3000);
      sec = sec - 3;
      lcd.clear();
      lcd.setCursor(10, 1);
      lcd.print(randNumber);
      lcd.setCursor(0, 1);
      }
      }
    Serial.println(inputString);
    Serial.println(inputInt);
    }
  }
}