#include <Servo.h>

const byte PEDESTRIAN_GREEN = 2;
const byte PEDESTRIAN_RED = 3;
const byte BUTTON = 5;
const byte BELL = 6;
const byte TRAFFIC_GREEN = 8;
const byte TRAFFIC_YELLOW = 9;
const byte TRAFFIC_RED = 10;
const byte SERVO_PIN = A3;
long cycle = 10000;
long last_cycle = 0;
int debounce_delay = 800;
int pedestrian_req = 0;
int req_state = 0;
bool pedestrianActive = false;
const byte SEG_A = 7;
const byte SEG_B = 4;
const byte SEG_C = 11;
const byte SEG_D = 12;
const byte SEG_E = 13;
const byte SEG_F = A0;
const byte SEG_G = A1;
const byte SEG_DP = A2;
Servo barrier;

const byte NUMBERS[] = {
  0b00111111,  
  0b00000110,  
  0b01011011,  
  0b01001111,  
  0b01100110,  
  0b01101101,  
  0b01111101,  
  0b00000111,  
  0b01111111,  
  0b01101111   
};

void setup() {
  pinMode(PEDESTRIAN_GREEN, OUTPUT);
  digitalWrite(PEDESTRIAN_GREEN, LOW);
  pinMode(PEDESTRIAN_RED, OUTPUT);
  digitalWrite(PEDESTRIAN_RED, HIGH);
  
  pinMode(TRAFFIC_GREEN, OUTPUT);
  digitalWrite(TRAFFIC_GREEN, HIGH);
  pinMode(TRAFFIC_YELLOW, OUTPUT);
  digitalWrite(TRAFFIC_YELLOW, LOW);
  pinMode(TRAFFIC_RED, OUTPUT);
  digitalWrite(TRAFFIC_RED, LOW);
  
  pinMode(BUTTON, INPUT);

  barrier.attach(SERVO_PIN);
  barrier.write(90);

  pinMode(SEG_A, OUTPUT);
  pinMode(SEG_B, OUTPUT);
  pinMode(SEG_C, OUTPUT);
  pinMode(SEG_D, OUTPUT);
  pinMode(SEG_E, OUTPUT);
  pinMode(SEG_F, OUTPUT);
  pinMode(SEG_G, OUTPUT);
  pinMode(SEG_DP, OUTPUT);

  Serial.begin(9600);
}

void loop() {
  long ms = millis();
  byte request = digitalRead(BUTTON);

  if (last_cycle + cycle < ms) {
    stopVehicles();
    pedestriansCycle();
    startVehicles();
    last_cycle = millis();
  } else if (request == 1 && (ms - debounce_delay) > pedestrian_req && !pedestrianActive) {
    stopVehicles();
    pedestriansCycle();
    startVehicles();
    pedestrian_req = ms;
    pedestrianActive = true;
    last_cycle = millis();
  }
  req_state = request;
}

void stopVehicles() {
  delay(1000);
  digitalWrite(TRAFFIC_GREEN, LOW);
  digitalWrite(TRAFFIC_YELLOW, HIGH);
  delay(1000);
  digitalWrite(TRAFFIC_YELLOW, LOW);
  digitalWrite(TRAFFIC_RED, HIGH);
  barrier.write(0);
  delay(1500);
}

void startVehicles() {
  digitalWrite(TRAFFIC_RED, LOW);
  digitalWrite(TRAFFIC_YELLOW, LOW);
  digitalWrite(TRAFFIC_GREEN, HIGH);
  barrier.write(90);
}

void pedestriansCycle() {
  digitalWrite(PEDESTRIAN_RED, LOW);
  digitalWrite(PEDESTRIAN_GREEN, HIGH);

  for (int i = 9; i >= 0; i--) {
    displayNumber(i);
    tone(BELL, 1760, 500);
    delay(1000);
  }

  blinkLights(PEDESTRIAN_GREEN, 5, 400);
  digitalWrite(PEDESTRIAN_GREEN, LOW);
  digitalWrite(PEDESTRIAN_RED, HIGH);
  delay(2000);
  pedestrianActive = false;
}

void blinkLights(byte light, byte times, int duration) {
  for (byte i = 0; i < times; i++) {
    digitalWrite(light, LOW);
    tone(BELL, 1760, 500);
    delay(duration);
    digitalWrite(light, HIGH);
    delay(duration);
    noTone(BELL);
  }
}

void displayNumber(int num) {
  byte segments = NUMBERS[num];
  digitalWrite(SEG_A, !bitRead(segments, 0));
  digitalWrite(SEG_B, !bitRead(segments, 1));
  digitalWrite(SEG_C, !bitRead(segments, 2));
  digitalWrite(SEG_D, !bitRead(segments, 3));
  digitalWrite(SEG_E, !bitRead(segments, 4));
  digitalWrite(SEG_F, !bitRead(segments, 5));
  digitalWrite(SEG_G, !bitRead(segments, 6));
  digitalWrite(SEG_DP, LOW);
}
