#include <LiquidCrystal_I2C.h>
#define I2C_ADDR 0x27
#define LCD_COLUMNS 16
#define LCD_ROWS 2
#include <Wire.h>

LiquidCrystal_I2C lcd(I2C_ADDR, LCD_COLUMNS, LCD_ROWS);


const int greenPins[] = {4, 10, 2, 13};
const int yellowPins[] = {A3, 9, 5, 12};
const int redPins[] = {6, 8, 7, A2};
const int irSensorPins[] = {A1, 3, 11, A0};
const int whitePins[] = {0, 1};

unsigned long timers[] = {0, 0, 0, 0, 0, 0, 0, 0};
unsigned long irCheckInterval = 1000;  // Adjust the interval as needed
unsigned long lastIRCheckTime = 0;

void setup() {
  lcd.clear();
  lcd.begin(LCD_COLUMNS, LCD_ROWS);
  lcd.setBacklight(LOW);
  lcd.setCursor(0, 0);
  lcd.print("Density Based");
  lcd.setCursor(0, 1);
  lcd.print("Traffic Signal");
  for (int i = 0; i < 4; ++i) {
    pinMode(greenPins[i], OUTPUT);
    pinMode(yellowPins[i], OUTPUT);
    pinMode(redPins[i], OUTPUT);
    pinMode(irSensorPins[i], INPUT);
  }
  digitalWrite(yellowPins[0], HIGH);
  delay(4000); // 4 seconds yellow
}

  



void displayHigh(int lane) {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("L"+String(lane)+":High Density ");
  for (int i = 15; i > 0; --i) {
    lcd.setCursor(0, 1);
    lcd.print(i);
    lcd.print(" second for Red");
    delay(1000);
  }
}

void displayNormal(int lane) {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("L"+String(lane)+":Normal Density ");
  for (int i = 8; i > 0; --i) {
    lcd.setCursor(0, 1);
    lcd.print(i);
    lcd.print(" second for Red");
    delay(1000);
  }
}

void displayNextGreenCountdown(int lane) {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Next Green Light");
  lcd.setCursor(0, 1);
  lcd.print("in Lane " + String(lane) + " in ");
  for (int i = 5; i > 0; --i) {
    lcd.setCursor(0, 1);
    lcd.print("in Lane " + String(lane) + " in ");
    lcd.print(i);
    delay(1000);
  }
}
void setLights(int setIndex,int nextSetIndex,int Green1) {
  bool isSensorBlocked = (digitalRead(irSensorPins[setIndex]) == LOW);

  digitalWrite(yellowPins[setIndex], LOW);
  digitalWrite(redPins[setIndex], LOW);

  if (isSensorBlocked) {
    if (millis() - timers[setIndex] < 15000) {
      digitalWrite(greenPins[setIndex], HIGH);
      displayHigh(setIndex + 1);
    } else {
      timers[setIndex] = millis();
    }
    digitalWrite(greenPins[setIndex], LOW);
  } else {
    if (millis() - timers[setIndex] < 8000) {
      digitalWrite(greenPins[setIndex], HIGH);
      displayNormal(setIndex + 1);
    } else {
      timers[setIndex] = millis();
    }
    digitalWrite(greenPins[setIndex], LOW);
    
    
  }
  digitalWrite(redPins[nextSetIndex], LOW);
  digitalWrite(redPins[setIndex], LOW);
  digitalWrite(redPins[Green1],LOW);
    
  if (millis() - timers[setIndex + 4] < 4000) {
    digitalWrite(yellowPins[setIndex], HIGH);
    digitalWrite(yellowPins[nextSetIndex], HIGH);
    digitalWrite(yellowPins[Green1], HIGH);
    displayNextGreenCountdown(nextSetIndex+1);
  } else {
    timers[setIndex + 4] = millis();
  }

  digitalWrite(yellowPins[setIndex], LOW);
  digitalWrite(yellowPins[Green1], LOW);
  digitalWrite(redPins[setIndex], HIGH);
}





void loop() {

  digitalWrite(greenPins[0], LOW);
  digitalWrite(yellowPins[0], LOW);
  digitalWrite(redPins[0], HIGH);

  digitalWrite(greenPins[1], LOW);
  digitalWrite(yellowPins[1], LOW);
  digitalWrite(redPins[1], HIGH);

  digitalWrite(greenPins[2], LOW);
  digitalWrite(yellowPins[2], LOW);
  digitalWrite(redPins[2], HIGH);

  digitalWrite(greenPins[3], LOW);
  digitalWrite(yellowPins[3], LOW);
  digitalWrite(redPins[3], HIGH);
  
  
  
  for (int i = 0; i < 4; i++) {
    setLights(i, (i+1),(i-3));
  }
}