//////////////////////////////////////////////////////////////////////////////
/// @brief Helper class for debouncing input signals (e.g. push-buttons)
///
//////////////////////////////////////////////////////////////////////////////
using uint = unsigned int;
using ulong = unsigned long;

class Debounce {
public:
  Debounce(unsigned int dbt) : debounceTime {dbt} {}
  bool operator()(const uint8_t, const uint8_t);

private:
  uint debounceTime;
  uint8_t prevPinState;
  ulong timeStamp {0};
};

bool Debounce::operator()(const uint8_t pin, uint8_t activePinState = LOW) {
  bool isDebounceReady = false;
#ifdef __digitalWriteFast_h_
  uint8_t pinState = digitalReadFast(pin);
#else
  uint8_t pinState = digitalRead(pin);
#endif
  if (pinState != prevPinState) {   // Restart the debounce timer with every edge change
    timeStamp = millis();
    prevPinState = pinState;
  } else if (pinState == activePinState && (millis() - timeStamp >= debounceTime)) {
    isDebounceReady = true;   // No more edge changes within the debounce time but the pinState is permanently unequal
                              // to the previous one before the test.
  }
  return isDebounceReady;
}

// ------------------- Helper end ----------------------------------------------------

#define CONTINUOUS

constexpr uint8_t BUTTON_NUM {10};
constexpr uint8_t btn[BUTTON_NUM] {13, 12, 11, 10, 9, 8, 7, 6, 5, 4};

// One debounce object for each button with 15ms debounce time
Debounce debounce[BUTTON_NUM] {{15}, {15}, {15}, {15}, {15}, {15}, {15}, {15}, {15}, {15}};

void printLadder(uint8_t num) {
  for (size_t y = 0; y < num; ++y) {
    for (size_t i = 0; i <= y; ++i) { Serial.print(num); }
    Serial.println();
  }
  Serial.println("-");
  delay(500);
}

void setup() {
  Serial.begin(115200);
  for (auto b : btn) { pinMode(b, INPUT_PULLUP); }
  Serial.println("To start press a button...");
}

void loop() {
  static uint8_t number {0};
  static uint8_t prevNumber {0};
  for (uint8_t i = 0; i < BUTTON_NUM; ++i) {
    if (number == prevNumber && true == debounce[i](btn[i])) {
      number = i + 1;
    } else if (number != prevNumber) {
      prevNumber = number;
      printLadder(number);
#ifdef CONTINUOUS 
      number = prevNumber = 0;
#endif
    }
  }
}