// Blink a LED for a certain time
// https://forum.arduino.cc/t/timer-and-led-sequence/1097402/10
// Blink class
// Timer class
// 2023-03-04 noiasca
// code in forum

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 20, 4);

// LED1 2
//#define LED2 3
byte status = 0;
int Buzz = 7;
uint32_t previousMillis = 0;

class Timer {
  protected:
    uint32_t previousMillis = 0;
    uint32_t interval = 1000;
  public:
    Timer(uint32_t interval) : interval(interval) {}

    void start(uint32_t currentMillis = millis()) {
      previousMillis = currentMillis;
    }

    bool hasTriggered(uint32_t currentMillis = millis()) {
      if (currentMillis - previousMillis > interval)  {
        previousMillis = currentMillis;
        return true;
      }
      return false;
    }
};

Timer timer(5000);

class Blink {
  protected:
    const uint8_t pin;
    uint32_t previousMillis = 0;
    uint16_t interval = 1000;
    uint8_t state = 0;

  public:
    Blink(uint8_t pin, uint16_t interval = 1000) : pin(pin), interval(interval) {}

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

    void on() {
      state = 2;
    }

    void off() {
      state = 0;
      digitalWrite(pin, LOW);
    }

    void update (uint32_t currentMillis = millis()) {
      switch (state) {
        case 1 :
          if (currentMillis - previousMillis > interval)  {
            previousMillis = currentMillis;
            digitalWrite(pin, LOW);
            state = 2;
          }
        case 2 :
          if (currentMillis - previousMillis > interval)  {
            previousMillis = currentMillis;
            digitalWrite(pin, HIGH);
            state = 1;
          }
      }
    }
};

Blink ledA{2, 500};

class Buzzer {
  protected:
    const uint8_t pin;
    uint32_t previousMillis = 0;
    uint16_t interval = 1000;
    uint8_t state = 0;

  public:
    Buzzer(uint8_t pin, uint16_t interval = 1000) : pin(pin), interval(interval) {}

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

    void on() {
      state = 2;
    }

    void off() {
      state = 0;
      //digitalWrite(pin, LOW);
      noTone(pin);
    }

    void update (uint32_t currentMillis = millis()) {
      switch (state) {
        case 1 :
          if (currentMillis - previousMillis > interval)  {
            previousMillis = currentMillis;
            noTone(pin);
            state = 2;
          }
        case 2 :
          if (currentMillis - previousMillis > interval)  {
            previousMillis = currentMillis;
            tone(pin, 600);
            state = 1;
          }
      }
    }
};
Buzzer buzzer(7, 500);  // pin interval

void start() {
  timer.start();
  ledA.on();
  buzzer.on();
}

void stop() {
  ledA.off();
  buzzer.off();
}

void setup()
{
  Serial.begin(115200);
  Serial.println("Ready");
  lcd.init();
  lcd.backlight();
  ledA.begin();
}

void loop()
{
  switch (status) {

    case 0:  {

        lcd.clear();
        lcd.setCursor(7, 0);
        lcd.print("Seconds");
        previousMillis = millis();
        start();
        status++;
      }
      break;
    case 1:  {
        lcd.setCursor(0, 0);
        lcd.print((millis() - previousMillis) / 1000);
      }
      break;

  }

  ledA.update();
  buzzer.update();
  if (timer.hasTriggered()) stop();
}