#include <LiquidCrystal.h>
LiquidCrystal lcd(7, 8, 9, 10, 11, 12); // RS,EN,D4,D5,D6,D7
//uint16_t attesa;
//uint32_t t_attesa;
//uint32_t t_start;
//uint32_t t_stop;
enum stati {ST_ATTENZIONE, ST_ATTESA, ST_START, ST_STOP, ST_PAUSA};
enum stati stato = ST_ATTENZIONE;

struct Pausa {
    uint32_t t_t0;
    uint16_t t_pausa;
    uint8_t  actions;
    uint8_t  statePostActions;
};

struct AppData {
    enum stati stato = ST_ATTENZIONE;
    uint16_t attesa;
    uint32_t t_attesa;
    uint32_t t_start;
    uint32_t t_stop;
    Pausa pausa;
};

AppData appData;

//Pausa pausa;

void setup() {
  pinMode(2, INPUT_PULLUP);
  pinMode(3, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);
  lcd.begin(16, 2);
  lcd.print(" Prova riflessi ");
  delay(2000);
  lcd.clear();

}

void blink() {
  static uint32_t saveMillis = millis();
  if (millis() - saveMillis >= 500) {
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
    saveMillis = millis();
  }
}

void appFunction(AppData &d) {
    switch (d.stato) {

    case ST_ATTENZIONE:
        digitalWrite(3, LOW);
        lcd.setCursor(0, 0);
        lcd.print("  ATTENZIONE... ");
        randomSeed(analogRead(A0) + millis());
        d.attesa = random(2500, 7001); // ATTESA da 2,5 a 7 secondi.
        d.t_attesa = millis();
        // seleziona il prossimo stato
        d.stato = ST_ATTESA;

      break;
    case ST_ATTESA:
      if (millis() - d.t_attesa >= d.attesa) {
          lcd.setCursor(0, 0); 
          lcd.print("**** PREMI! ****");
          lcd.setCursor(0, 1);
          lcd.print("****************");
          digitalWrite(3, HIGH);
          d.t_start = millis();
          // seleziona il prossimo stato
          d.stato = ST_START;

      } else if (!digitalRead(2)) {
          lcd.setCursor(0, 0);
          lcd.print("*** NON FARE ***");
          lcd.setCursor(0, 1);
          lcd.print("*** IL FURBO ***");
          
          d.pausa.t_t0 = millis();
          d.pausa.t_pausa = 2000;
          d.pausa.actions = 1;
          d.pausa.statePostActions = ST_ATTENZIONE;
          // seleziona il prossimo stato
          d.stato = ST_PAUSA;
        
      }

      break;
    case ST_PAUSA:
      if (millis() - d.pausa.t_t0 >= d.pausa.t_pausa) {
          bool buttonState = digitalRead(2);
          // risolve il problema di pulsante mantenuto 
          // premuto per lungo tempo.
          if (buttonState && d.pausa.actions == 1) {
              lcd.setCursor(0, 1);
              lcd.print("                ");
              d.stato = d.pausa.statePostActions;
          } else if (!digitalRead(2))
              d.pausa.t_t0 = millis();
          else {
              d.stato = d.pausa.statePostActions;
          }
      }
      break;
    case ST_START:
      if (!digitalRead(2)) {
          d.t_stop = millis();
          lcd.clear();
          lcd.setCursor(5, 0);
          lcd.print(d.t_stop - d.t_start);
          lcd.print(" ms");
          
          d.pausa.t_t0 = millis();
          d.pausa.t_pausa = 500;
          d.pausa.actions = 0;
          d.pausa.statePostActions = ST_STOP;
          // seleziona il prossimo stato
          d.stato = ST_PAUSA;
      }

      break;
    case ST_STOP:
      lcd.setCursor(0, 1);
      lcd.print("VUOI RIPROVARE?");
      if (!digitalRead(2)) {
          d.pausa.t_t0 = millis();
          d.pausa.t_pausa = 500;
          d.pausa.actions = 1;
          d.pausa.statePostActions = ST_ATTENZIONE;
          // seleziona il prossimo stato
          d.stato = ST_PAUSA;
      }

      break;
  }
}

void loop() {
  blink();
  appFunction(appData);

#if(0)  // disabilita questa porzione di codice 
  switch (stato) {

    case ST_ATTENZIONE:
      digitalWrite(3, LOW);
      lcd.setCursor(0, 0);
      lcd.print("  ATTENZIONE... ");
      randomSeed(analogRead(A0) + millis());
      attesa = random(2500, 7001); // ATTESA da 2,5 a 7 secondi.
      t_attesa = millis();
      stato = ST_ATTESA;

      break;
    case ST_ATTESA:
      if (millis() - t_attesa >= attesa) {
        stato = ST_START;
        lcd.setCursor(0, 0); 
        lcd.print("**** PREMI! ****");
        lcd.setCursor(0, 1);
        lcd.print("****************");
        digitalWrite(3, HIGH);
        t_start = millis();

      } else if (!digitalRead(2)) {
        lcd.setCursor(0, 0);
        lcd.print("*** NON FARE ***");
        lcd.setCursor(0, 1);
        lcd.print("*** IL FURBO ***");
        //delay(2000);
        pausa.t_t0 = millis();
        pausa.t_pausa = 2000;
        pausa.actions = 1;
        pausa.statePostActions = ST_ATTENZIONE;
        stato = ST_PAUSA;
        //stato = ST_ATTENZIONE;
        
        //lcd.setCursor(0, 1);
        //lcd.print("                ");
      }

      break;
    case ST_PAUSA:
      if (millis() - pausa.t_t0 >= pausa.t_pausa) {
        if (pausa.actions == 1) {
          lcd.setCursor(0, 1);
          lcd.print("                ");
        }
        stato = pausa.statePostActions;
      }
      break;
    case ST_START:
      if (!digitalRead(2)) {
        t_stop = millis();
        lcd.clear();
        lcd.setCursor(5, 0);
        lcd.print(t_stop - t_start);
        lcd.print(" ms");
        //delay(2000);
        //stato = ST_STOP;
        pausa.t_t0 = millis();
        pausa.t_pausa = 500;
        pausa.actions = 0;
        pausa.statePostActions = ST_STOP;
        stato = ST_PAUSA;
      }

      break;
    case ST_STOP:
      lcd.setCursor(0, 1);
      lcd.print("VUOI RIPROVARE?");
      if (!digitalRead(2)) {
          pausa.t_t0 = millis();
          pausa.t_pausa = 500;
          pausa.actions = 1;
          pausa.statePostActions = ST_ATTENZIONE;
          stato = ST_PAUSA;
          //stato = ST_ATTENZIONE;
      }

      break;
  }
#endif
}