#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Servo.h>

// Initialize LCD (I2C address 0x27)
LiquidCrystal_I2C lcd(0x27, 16, 2);

// Initialize Servo
Servo myservo;

// Pin definitions
const int IR1 = 2; // Entry IR sensor
const int IR2 = 3; // Exit IR sensor
const int SERVO_PIN = 4; // Servo motor pin

// Parking system variables
int totalSlots = 4; // Total number of parking slots
int availableSlots = totalSlots;

// Flags to handle sensor triggers
bool flag1 = false;
bool flag2 = false;

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

  // Initialize LCD
  lcd.init();
  lcd.backlight();

  // Configure pins
  pinMode(IR1, INPUT);
  pinMode(IR2, INPUT);

  // Attach servo and set to default closed position
  myservo.attach(SERVO_PIN);
  myservo.write(100); // Gate closed

  // Welcome message on LCD
  lcd.setCursor(0, 0);
  lcd.print("     SMART    ");
  lcd.setCursor(0, 1);
  lcd.print(" PARKING SYSTEM ");
  delay(2000);
  lcd.clear();
}

void loop() {
  // Car entering the parking lot
  if (digitalRead(IR1) == LOW && !flag1) {
    if (availableSlots > 0) {
      flag1 = true;
      if (!flag2) {
        openGate();
        availableSlots--; // Reduce available slots
      }
    } else {
      displayParkingFull();
    }
  }

  // Car exiting the parking lot
  if (digitalRead(IR2) == LOW && !flag2) {
    flag2 = true;
    if (!flag1) {
      openGate();
      if (availableSlots < totalSlots) {
        availableSlots++; // Increase available slots
      }
    }
  }

  // Close gate when both flags are set
  if (flag1 && flag2) {
    delay(1000); // Allow car to pass
    closeGate();
    flag1 = false;
    flag2 = false;
  }

  // Update LCD with available slots
  displaySlots();
}

// Function to open the gate
void openGate() {
  myservo.write(0); // Gate open
  delay(1000); // Allow time for the gate to open
}

// Function to close the gate
void closeGate() {
  myservo.write(100); // Gate closed
  delay(1000); // Allow time for the gate to close
}

// Function to display "Parking Full" on LCD
void displayParkingFull() {
  lcd.setCursor(0, 0);
  lcd.print("    SORRY :(    ");
  lcd.setCursor(0, 1);
  lcd.print("  Parking Full  ");
  delay(3000);
  lcd.clear();
}

// Function to update LCD with available slots
void displaySlots() {
  lcd.setCursor(0, 0);
  lcd.print("    WELCOME!    ");
  lcd.setCursor(0, 1);
  lcd.print("Slot Left: ");
  lcd.print(availableSlots);
  lcd.print(" "); // Clear extra characters
}