// using https://www.arduino.cc/reference/en/libraries/hd44780 for the LCD

#include <Wire.h>
#include <hd44780.h>                       // main hd44780 header
#include <hd44780ioClass/hd44780_I2Cexp.h> // i2c expander i/o class header

//using https://github.com/Dlloydev/Toggle for the button
#include <Toggle.h>

hd44780_I2Cexp lcd;
const int LCD_COLS = 16;
const int LCD_ROWS = 2;

const byte buttonPin = 2;
Toggle button;

unsigned long lastTick;
const unsigned long tickPeriod = 100; // ms

enum {PAUSED, RUNNING, ASKING} state = PAUSED;

class Led {
    const char ** questions;
    const size_t questionCount;
    const byte ledPin;
  public:
    Led (const byte pin, const char ** q, const size_t n) :
      ledPin(pin), questions(q),  questionCount(n) {}

    void begin() {
      pinMode(ledPin, OUTPUT);
    }

    void flip() {
      digitalWrite(ledPin, digitalRead(ledPin) == LOW ? HIGH : LOW);
    }
    void on() {
      digitalWrite(ledPin, HIGH);
    }
    void off() {
      digitalWrite(ledPin, LOW);
    }
    const char* getRandomQuestion() {
      if (questions == nullptr || questionCount == 0) return nullptr;
      return questions[random(questionCount)];
    }
};

// the questions
const char * QLed0[] = {"led0 Q0", "led0 Q1", "led0 Q2", "led0 Q3", "led0 Q4"};
const char * QLed1[] = {"led1 Q0", "led1 Q1", "led1 Q2", "led1 Q3"};
const char * QLed2[] = {"led2 Q0", "led2 Q1", "led2 Q2"};
const char * QLed3[] = {"led3 Q0", "led3 Q1"};
const char * QLed4[] = {"led4 Q0", "led4 Q1", "led4 Q2", "led4 Q3", "led4 Q4"};

Led leds[] = {
  { 9, QLed0, sizeof QLed0 / sizeof * QLed0 },
  {10, QLed1, sizeof QLed1 / sizeof * QLed1 },
  {11, QLed2, sizeof QLed2 / sizeof * QLed2},
  {12, QLed3, sizeof QLed3 / sizeof * QLed3 },
  {13, QLed4, sizeof QLed4 / sizeof * QLed4 },
};
const size_t ledsCount = sizeof leds / sizeof * leds;
size_t currentLed;


void setup() {
  button.begin(buttonPin);
  for (auto&l : leds) l.begin();

  int result = lcd.begin(LCD_COLS, LCD_ROWS);
  if (result) {
    Serial.print("LCD initialization failed: ");
    Serial.println(result);
    hd44780::fatalError(result);
  }

  randomSeed(analogRead(A0)); // randomize

  lcd.clear();
  lcd.print("PRESS TO START");
}

void loop() {
  switch (state) {
    case PAUSED: // a click on the button starts the led danse
      button.poll();
      if (button.onPress()) {
        lcd.clear();
        lcd.print("Game on!");
        lastTick = millis();
        // turn off all leds
        for (auto&l : leds) l.off();
        // turn on first led
        currentLed = 0;
        leds[currentLed].on();
        state = RUNNING;
      }
      break;

    case RUNNING:
      button.poll();
      if (button.onPress()) {
        // we stop the led danse and ask a question from the current Led
        lcd.clear();
        lcd.print(leds[currentLed].getRandomQuestion());
        state = ASKING;
      } else {
        // check if it's time to go to next led, do that
        if (millis() - lastTick >= tickPeriod) {
          leds[currentLed++].off();
          if (currentLed >= ledsCount) currentLed = 0;
          leds[currentLed].on();
          lastTick = millis();
        }
      }
      break;

    case ASKING:
      // a click on the button starts the led danse again
      button.poll();
      if (button.onPress()) {
        // turn off all leds (this is not necessary unless you messed up the leds in other part of the code, whilst asking the question)
        for (auto&l : leds) l.off();
        // turn on the current led
        leds[currentLed].on();
        lcd.clear();
        lcd.print("Try again!");
        state = RUNNING;
      }
      break;
  }

}