//-----------------------------------------//
//
//-----------------------------------------//
unsigned long previousTimeColonBlink = 0;
unsigned long ColonBlinkDelay = 500;

unsigned long previousTimeLED2Blink = 0;
unsigned long LED2BlinkDelay = 1000;
byte LED2State = LOW;

bool boom2 = true;
//-----------------------------------------//

#include <Keypad.h>
#include <LiquidCrystal_I2C.h>
#include <TM1637.h>
TM1637 TM1;


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

LiquidCrystal_I2C   lcd(0x27, 16, 2);

//-----------------------------------------//
//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] = {9, 8, 7, 6};   //connect to the row pinouts of the keypad
byte pin_column[COLUMN_NUM] = {5, 4, 3}; //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;
int numControler = 0;
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;

bool colon = false;
//-----------------------------------------//
//random defuse number
//-----------------------------------------//
String inputNumber;
int pressCount = 1;
long inputInt;
long randNumber;
bool run = true;
int digit;

int cursor = 10;
//-----------------------------------------//

//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.backlight(); 
  lcd.init();
  lcd.clear();

  // LCD 2
  TM1.begin(11, 8, 4);
  TM1.displayClear();
  TM1.setBrightness(7);

  //random generator logic
  inputString.reserve(16);
  randomSeed(analogRead(0));
  /*randNumber = random(1000, 9999);
  Serial.println(randNumber);*/

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

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

  //passwordLogic();
}

void loop()
{
  digitalWrite(buzz, HIGH);
  digitalWrite(armed, HIGH);
  digitalWrite(disArmed, HIGH); 
  delay(250);
  digitalWrite(buzz, LOW);
  delay(250);
}

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;
      numControler += 1;
      lcd.print(key); 
      Serial.print("numciontoler:");
      Serial.println(numControler);             // append new character to input string
    } 
    else if (key == '#') 
    {
      if (inputString.length() > 0) {
        prepTime = inputString.toInt(); // YOU GOT AN INTEGER NUMBER
        inputString = "";
        numControler = 0;               // 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);*/
    }
    if (numControler == 3) 
    {
      Serial.println("reset");
      inputString = "";
      numControler = 0;
      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); 
    }
  }
}

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;
      numControler += 1;
      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 = "";
        numControler = 0;               // clear input
        Serial.print("Defuse Time: ");
        Serial.println(defTime);
        defuseDigit();
      }
    } 
    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);*/
    }
    if (numControler == 3) 
    {
      Serial.println("reset");
      inputString = "";
      numControler = 0;
      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); 
    }
  }
}

void defuseDigit()
{
  Serial.println("Enter Defuse Digits");

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

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

    if (key >= '1' && key <= '9') 
    {     // only act on numeric keys
      inputString += key;
      numControler += 1;
      lcd.print(key);              // append new character to input string
    }
    else if (key == '#') 
    {
      if (inputString.length() > 0) 
      {
        digit = inputString.toInt();
        if (digit > 3 && digit < 17)
        {
          Serial.println("gut");
          timerStart();
        } 
        Serial.println("not gut");
        inputString = "";
        numControler = 0;
        digit = 0;
        lcd.clear();
        lcd.setCursor(0, 0);                                   //   Four is added to pressCount to center the input on the LCD
        lcd.print("Def Digits 4-16");
        lcd.setCursor(0, 1); 
      }
    } 
    else if (key == '*') 
    {
      inputString = "";
      numControler = 0;
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.setCursor(0, 1);                 // clear input
    }
    /*Serial.println(inputString);
    Serial.println(inputInt);*/
    }
    if (numControler == 3) 
    {
      Serial.println("reset");
      inputString = "";
      numControler = 0;
      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); 
      numControler = 0;
    }
  }
}


void timerStart()
{
  if (digit == 4)
  {
    randNumber = random(1000, 9999);
  }
  else if (digit == 6)
  {
    randNumber = random(1000, 999999);
  }
  else if (digit == 8)
  {
    randNumber = random(1000, 99999999);
  }
  else if (digit == 10)
  {
    randNumber = random(1000, 9999999999);
  }
  else if (digit == 12)
  {
    randNumber = random(1000, 999999999999);
  }
  else if (digit == 14)
  {
    randNumber = random(1000, 99999999999999);
  }
  else if (digit == 16)
  {
    randNumber = random(1000, 9999999999999999);
  }
 


  Serial.println("START");
  Serial.print("preparation time: ");
  Serial.println(prepTime);
  Serial.print("defuse time: ");
  Serial.println(defTime);
  Serial.print("defuse code: ");
  Serial.println(randNumber);

  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()
{
  static unsigned long nextSwitchTime = millis()+1;


  lcd.clear();
  delay(250);
  PREP = true;
  while (PREP)
  {
    TM1.displayTime(Min, sec, colon);

    unsigned long timeNow = millis();
    if (timeNow - previousTimeColonBlink > ColonBlinkDelay)
    {
      previousTimeColonBlink += ColonBlinkDelay;
      //colon
      colon = !colon;
    }

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

      sec = sec - 1;
      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++)
        {
          TM1.displayPChar("----");
          colon = false;
          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();
  while (boom2 = true)
  {

  unsigned long timeNow = millis();

  if (timeNow - previousTimeLED2Blink > LED2BlinkDelay)
  {
    previousTimeLED2Blink += LED2BlinkDelay;
    digitalWrite(armed, HIGH);
    TM1.displayPChar("----");
  }
  }
  //Serial.println("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(cursor, 1);
  lcd.print(randNumber);
  //lcd.setCursor(1, 1);

  static unsigned long nextSwitchTime = millis()+1;

  while (run = true)
  {
  unsigned long timeNow = millis();
  if (timeNow - previousTimeColonBlink > ColonBlinkDelay)
  {
    previousTimeColonBlink += ColonBlinkDelay;
    //colon
    colon = !colon;
  }

  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;
        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);
      }
      }
    Serial.println(inputString);
    Serial.println(inputInt);
    }
  
    TM1.displayTime(Min, sec, colon);
  }
}
4-Digit Display