#include <digitalWriteFast.h>
#include <Button_SL.hpp>

//
// Konstanten
//
constexpr uint8_t MAX_DIGITS {4};
constexpr uint8_t MAX_SEGMENTS {8};

constexpr uint8_t decPlacePin[MAX_DIGITS] {A0, A1, A2, A3};
constexpr uint8_t digitPin[MAX_SEGMENTS] {4, 5, 6, 7, 8, 9, 10, 11};
constexpr uint8_t pinBtn {12};

constexpr uint8_t segmentBits[10] = {
  //  afbgcDde
    0b11101011,   // 0
    0b00101000,   // 1
    0b10110011,   // 2
    0b10111010,   // 3
    0b01111000,   // 4
    0b11011010,   // 5
    0b11011011,   // 6
    0b10101000,   // 7
    0b11111011,   // 8
    0b11111010,   // 9
};

//
// Globale Variablen/Objkte
//
Btn::ButtonSL btn {pinBtn};

//
// Funktionen
//
void digitsOff() {
  // Clear Digits
  for (auto dPP : decPlacePin) { digitalWriteFast(dPP, HIGH); }
}

void digit(uint8_t nbr, uint8_t dpPinIdx) {
  for (uint8_t i = 0; i < MAX_SEGMENTS; ++i) { digitalWriteFast(digitPin[i], ((segmentBits[nbr] >> i) & 0x01)); }
  digitalWriteFast(decPlacePin[dpPinIdx], LOW);
}

void setDot(uint8_t pos) {
  if (pos > 0 && pos < MAX_DIGITS) {
    for (uint8_t i = 0; i < MAX_SEGMENTS; ++i) { digitalWriteFast(digitPin[i], ((0b00000100 >> i) & 0x01)); }
    digitalWriteFast(decPlacePin[pos], LOW);
  }
}

void numberToDisplay(uint8_t dgt[], uint8_t dot) {
  static uint8_t activeDigit {0};
  digitsOff();
  switch (activeDigit) {
    case 0: digit(dgt[0], 0); break;
    case 1: digit(dgt[1], 1); break;
    case 2: digit(dgt[2], 2); break;
    case 3: digit(dgt[3], 3); break;
    case 4: setDot(dot); break;
  }
  if (++activeDigit == (MAX_DIGITS + 1)) { activeDigit = 0; }
}

void breakNumberDown(uint8_t dgt[], uint16_t nbr) {
  dgt[3] = nbr / 1000;
  nbr %= 1000;
  dgt[2] = nbr / 100;
  nbr %= 100;
  dgt[1] = nbr / 10;
  nbr %= 10;
  dgt[0] = nbr;
}

//
// Hauptprogramm
//
void setup() {
  for (auto dP : digitPin) { pinMode(dP, OUTPUT); }
  for (auto dPP : decPlacePin) { pinMode(dPP, OUTPUT); }
  btn.begin();
  randomSeed(638462874);
}

void loop() {
  static uint8_t digits[MAX_DIGITS];
  static uint16_t dotPos;
  uint16_t number;

  if (btn.tick() == Btn::ButtonState::shortPressed) {
    number = random(1, 10000);
    dotPos = random(0, 4);
    breakNumberDown(digits, number);
  }
  numberToDisplay(digits, dotPos);
}