#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#include <NewPing.h> // Library for Ultrasonic Sensor

LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 16, 2);

const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns

char hexaKeys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};

byte rowPins[ROWS] = { 23, 5, 13, 12};  //ROW
byte colPins[COLS] = { 14, 27, 16, 17};    //COL

Keypad keypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); 
int red = 19;
int green = 18;

// Define your password
const int password[] = {1, 2, 3, 4}; // Change the password according to your need
const int emergencyPIN[] = {1, 1, 1, 1}; // Emergency PIN

// Define ultrasonic sensor pins
#define TRIGGER_PIN 25
#define ECHO_PIN 26
#define MAX_DISTANCE 200 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.

NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.

// Define PIR Motion Sensor pin
#define PIR_PIN 34 // Example pin, change according to your setup

boolean sensorEnabled = true; // Flag to control whether to take ultrasonic sensor readings
boolean motionEnabled = true; // Flag to control whether to take PIR motion sensor readings
boolean correctPINEntered = false; // Flag to indicate whether correct PIN is entered
byte failedAttempts = 0; // Counter for failed PIN attempts
boolean alarmActive = false; // Flag to indicate if alarm is active

void setup() {
  Serial.begin(115200);
  initializeLCD(); // Call the function to initialize the LCD
  pinMode(red, OUTPUT);
  pinMode(green, OUTPUT);
  pinMode(PIR_PIN, INPUT);

}

void initializeLCD() {
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0); 
  lcd.print("Enter PIN:");
  digitalWrite(green, HIGH);
}

void loop() {
  static int enteredPassword[4]; // Temporary storage for entered password
  static int enteredEmergencyPIN[4]; // Temporary storage for entered emergency PIN
  static byte index = 0; // Index to keep track of current position in entered password
  static unsigned long intruderTime = 0; // Time when an intruder is detected
  
  char key = keypad.getKey();
  if (!correctPINEntered) {
    if (key != NO_KEY) {
      if (key == '#') { // Check if user pressed '#' to confirm password entry
        bool isCorrect = true;
        for (byte i = 0; i < 4; i++) {
          if (enteredPassword[i] != password[i]) {
            isCorrect = false;
            break;
          }
        }
        if (isCorrect) {
          digitalWrite(green, LOW);
          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("Alarm Disarmed");
          lcd.setCursor(0, 1);
          lcd.print("Welcome Home");
          delay(5000);
          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("Press (A)");
          lcd.setCursor(0, 1);
          lcd.print("TO TURN ON ALARM");
          
          
          correctPINEntered = true; // Set flag indicating correct PIN is entered
          alarmActive = false; // Disarm alarm
          sensorEnabled = false; // Disable ultrasonic sensor readings
          motionEnabled = false; // Disable PIR motion sensor readings
        } else {
          failedAttempts++;
          lcd.clear();
          lcd.print("Access Denied!");
          lcd.setCursor(0, 1);
          lcd.print("Attempts Left: ");
          lcd.print(3 - failedAttempts);
          delay(2000);
          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("Enter PIN:");
          index = 0; // Reset index for next password entry
          if (failedAttempts >= 3) {
            alarmActive = true; // Activate alarm after 3 failed attempts
          }
        }
      } else if (index < 4) { // Check if there is space in the password array
        enteredPassword[index++] = key - '0'; // Store the entered key in the password array and increment index
        lcd.setCursor(10 + index, 0); // Position cursor after "Enter PIN:" text
        lcd.print('*'); // Print '' instead of the actual key
      }
    }
  } else { // Correct PIN entered, waiting for 'A' key to turn on the alarm
    if (key == 'A' && !alarmActive) { // Check if alarm is off and 'A' key is pressed
      lcd.clear();
      lcd.print("Alarm On");
      alarmActive = false;
      sensorEnabled = true; // Enable ultrasonic sensor readings
      motionEnabled = true; // Enable PIR motion sensor readingS
      digitalWrite(green, HIGH);
      delay(500);
      digitalWrite(red, LOW);
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Enter PIN:");
      correctPINEntered = false; // Reset flag to require PIN entry again
      index = 0; // Reset password index
    }
  }
  // Read PIR Motion Sensor
  if (motionEnabled && !alarmActive) {
    int motionDetected = digitalRead(PIR_PIN);
    if (motionDetected == HIGH) {
      alarmActive = true;
    }
  }
  // Check distance if the sensor is enabled and alarm is not active
  if (sensorEnabled && !alarmActive) {
    unsigned int distance = sonar.ping_cm();
    if (distance != 0) { // Check if distance reading is valid
      Serial.print("Distance: ");
      Serial.print(distance);
      Serial.println(" cm");

      // If the distance is less than 10 cm, start counting time
      if (distance < 10) {
        if (millis() - intruderTime >= 10000) {
          // If the user is closer than 10 cm for 10 seconds, lock the system and activate the intruder alert
          // Implement your locking and alerting mechanism here
          alarmActive = true;
        }
      } else {
        intruderTime = millis(); // Reset the intruder detection timer
      }
    }
  }
  
  // Read PIR Motion Sensor
  
  // If alarm is active
  if (alarmActive) {
     lcd.clear();
     lcd.print("Intruder Alert!");
     lcd.setCursor(0, 1);
     lcd.print("Locking System...");
     digitalWrite(red, LOW);
     delay(200);
     digitalWrite(red, HIGH);
     delay(200);
     digitalWrite(green, LOW);
     
    
    if (key == 'B' && alarmActive) {
      // Display "Emergency PIN"
      lcd.clear();
      lcd.print("Emergency PIN");
      delay(700);
      lcd.setCursor(0, 1);
      lcd.print("Enter PIN:");

      // Reset index for emergency PIN entry
      index = 0;
      
      // Wait for the user to enter the emergency PIN
      while (index < 4) {
        char key = keypad.getKey();
        if (key != NO_KEY && key >= '0' && key <= '9') {
          enteredEmergencyPIN[index] = key - '0'; // Store the entered key in the emergency PIN array
          lcd.setCursor(10 + index, 1); // Position cursor after "Enter PIN:" text
          lcd.print('*'); // Print '' instead of the actual key
          index++;
        }
        delay(100); // Delay to avoid rapid keypad reading
      }
      
      // Check if the entered emergency PIN is correct
      bool isCorrect = true;
      for (byte i = 0; i < 4; i++) {
        if (enteredEmergencyPIN[i] != emergencyPIN[i]) {
          isCorrect = false;
          break;
        }
      }
      
      if (isCorrect) {
        // If emergency PIN is correct, redirect to correctPinEntered
        correctPINEntered = true;
        alarmActive = false; // Disarm alarm
        sensorEnabled = false; // Disable ultrasonic sensor readings
        motionEnabled = false; // Disable PIR motion sensor readings
        lcd.clear();
        lcd.print("Alarm Disarmed");
        delay(2000);
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("Press (A)");
        lcd.setCursor(0, 1);
        lcd.print("TO TURN ON ALARM");
        digitalWrite(green, HIGH);
        delay(200);
        digitalWrite(red, LOW);
        //digitalWrite(green, LOW);
        
      } else {
        // If emergency PIN is incorrect, display error message
        lcd.clear();
        lcd.print("Incorrect PIN");
        delay(2000);
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("Enter PIN:");
      }
      index = 0; // Reset the index for future entries
    }
  }
  delay(100); // Small delay for stability 
}