//https://forum.arduino.cc/t/4leds-4-buttons/1240125/8
//https://europe1.discourse-cdn.com/arduino/original/4X/7/e/0/7e0ee1e51f1df32e30893550c85f0dd33244fb0e.jpeg
// Simulation: https://wokwi.com/projects/405862678942568449

#define ProjectName "4 blink leds and 4 buttons"
#define NotesOnRelease "Arduino MEGA tested"
// make names
enum TimerEvent {NotExpired, Expired};
enum TimerControl {Halt, Run};
enum ButtonControl {Released, Pushed};
// make variables
uint32_t currentMillis = millis();
constexpr uint8_t ButtonPins[] {7, 6, 5, 4}; // will be configured as INPUT_PULL - button --> gnd
constexpr uint8_t LedPins[] {13, 12, 11, 10};
constexpr uint32_t BlinkIntervals[] {100, 200, 300, 400};
const String Blink[] {"blink1", "blink2", "blink3", "blink4"};

// make structures
struct TIMER
{
  uint32_t interval;
  uint32_t now;
  uint8_t expired(uint32_t currentMillis)
  {
    uint8_t timerEvent = currentMillis - now >= interval;
    if (timerEvent == Expired) now = currentMillis;
    return timerEvent;
  }
};
struct BUTTONLED
{
  uint8_t name;
  uint8_t ledPin;
  uint8_t buttonPin;
  uint8_t stateOld;
  uint8_t blinkControl;
  TIMER   blinkMe;
  TIMER   debounce;
  void make(uint8_t name_, uint8_t ledPin_, uint8_t buttonPin_, uint32_t blinkInterval)
  {
    Serial.println(__func__);
    name = name_;
    ledPin = ledPin_;
    buttonPin = buttonPin_;
    blinkControl = Halt;
    blinkMe.interval = blinkInterval;
    debounce.interval = 20;
    pinMode(ledPin, OUTPUT);
    pinMode(buttonPin, INPUT_PULLUP);
    stateOld = digitalRead(buttonPin) ? LOW : HIGH;
  }
  void run()
  {
    if (debounce.expired(currentMillis) == Expired)
    {
      uint8_t stateNew = digitalRead(buttonPin) ? LOW : HIGH;
      if (stateOld != stateNew)
      {
        stateOld = stateNew;
        if (stateNew == Pushed)
        {
          blinkControl = blinkControl ? LOW : HIGH;
          if (blinkControl == Run) Serial.println(Blink[name]);
        }
      }
    }
    if (blinkMe.expired(currentMillis) == Expired)
    {
      digitalWrite(ledPin, blinkControl and (digitalRead(ledPin) ? LOW : HIGH));
    }
  }
} buttonLeds[sizeof(ButtonPins)];
// make application
void setup()
{
  Serial.begin(115200);
  Serial.print("Source: "), Serial.println(__FILE__);
  Serial.print(ProjectName), Serial.print(" - "), Serial.println(NotesOnRelease);
  uint8_t element = 0;
  for (auto &buttonLed : buttonLeds)
  {
    buttonLed.make(element, LedPins[element], ButtonPins[element], BlinkIntervals[element]);
    element++;
  }
  Serial.println(" =-> and off we go\n");
}
void loop()
{
  currentMillis = millis();
  for (auto &buttonLed : buttonLeds) buttonLed.run();
}