#include "SevSegShift.h"
#include "Bounce2.h"


SevSeg sevseg;


const int data_pin = 7;    // 74HC165
const int clock_pin = 8;   // 74HC165
const int latch_pin = 9;   // 74HC165

const int numBits = 8;     // Set to 8 * number of shift registers

// Button pins
const byte BUTTON_YELLOW = 5;
const byte BUTTON_RED = 6;
const byte BUTTON_GREEN = 7;

// Display pins
const int LATCH_PIN = A1;  // 74HC595
const int DATA_PIN = A0;   // 74HC595 
const int CLOCK_PIN = A2;  // 74HC595 

// Define segment patterns for 7-segment display (assuming COMMON_ANODE)
const byte SEGMENT_PATTERNS[] = {
  B00111111,  // Digit 0: 0
  B00000110,  // Digit 1: 1
  B01011011,  // Digit 2: 2
  B01001111,  // Digit 3: 3
  B01100110,  // Digit 4: 4
  B01101101,  // Digit 5: 5
  B01111101,  // Digit 6: 6
  B00000111,  // Digit 7: 7
  B01111111,  // Digit 8: 8
  B01101111   // Digit 9: 9
};

// Button debounce interval (in milliseconds)
const unsigned long debounceInterval = 50;

// Update interval for display (in milliseconds)
const unsigned long updateInterval = 100;

// Button struct to store button information
struct Button {
  int pin;
  int state;
  int lastState;
  Bounce bounce;
  int displayIndex;
};

// Display struct to store display information
struct Display {
  int value;
  byte segmentPattern;
  int brightness;
};

Button buttons[] = {
  {BUTTON_YELLOW, LOW, LOW, Bounce(), 5},
  {BUTTON_RED, LOW, LOW, Bounce(), 6},
  {BUTTON_GREEN, LOW, LOW, Bounce(), 7}
};

Display displays[] = {
  {0, SEGMENT_PATTERNS[0], 90}
};

unsigned long previousDebounceTime = 0;
unsigned long previousUpdateTime = 0;

void setup() {
  byte numDigits = sizeof(SEGMENT_PATTERNS) / sizeof(SEGMENT_PATTERNS[0]);
  byte digitPins[] = {2};  
  byte segmentPins[] = {6, 5, 2, 3, 4, 7, 8, 9};  
  bool resistorsOnSegments = true;
  byte hardwareConfig = COMMON_ANODE;
  sevseg.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments);
  sevseg.setBrightness(90);

  for (Button &button : buttons) {
    pinMode(button.pin, INPUT_PULLUP);
    button.bounce.attach(button.pin);
    button.bounce.interval(debounceInterval);
  }

  pinMode(LATCH_PIN, OUTPUT);
  pinMode(CLOCK_PIN, OUTPUT);
  pinMode(DATA_PIN, OUTPUT);

  Serial.begin(9600);
}

void loop() {
  unsigned long currentMillis = millis();

  // Update buttons and handle debouncing
  for (Button &button : buttons) {
    button.bounce.update();
    int newState = button.bounce.read();
    if (newState != button.state) {
      button.state = newState;
      if (button.state == HIGH) {
        handleButtonPress(button);
      }
    }
  }

  // Update the display
  if (currentMillis - previousUpdateTime >= updateInterval) {
    updateDisplay();
    previousUpdateTime = currentMillis;
  }

  // Update the SevSeg display
  sevseg.refreshDisplay();
}

void handleButtonPress(Button &button) {
  switch (button.pin) {
    case BUTTON_YELLOW:
      // Yellow button pressed, increment the displayed number by 1
      displays[button.displayIndex].value++;
      if (displays[button.displayIndex].value >= 10) {
        displays[button.displayIndex].value = 0;
      }
      break;
    case BUTTON_RED:
      // Red button pressed, decrement the displayed number by 1
      displays[button.displayIndex].value--;
      if (displays[button.displayIndex].value < 0) {
        displays[button.displayIndex].value = 9;
      }
      break;
    case BUTTON_GREEN:
      // Green button pressed, reset the counter to 0
      displays[button.displayIndex].value = 0;
      break;
    default:
      break;
  }
}

void updateDisplay() {
  // Update the display with the counter value using shift register
  byte displayValue = displays[0].value;
  shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, SEGMENT_PATTERNS[displayValue]);
  digitalWrite(LATCH_PIN, HIGH);
  digitalWrite(LATCH_PIN, LOW);
  
  displays[0].segmentPattern = SEGMENT_PATTERNS[displayValue];
}
74HC595
74HC165