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

#define RELE 12
#define START 9
#define RESET 8
#define SEG_UP 5
#define SEG_DOWN 4
#define MIN_UP 7
#define MIN_DOWN 6

#define INTERVAL_MILLIS 5

#define E_INICIAL 0
#define E_CONFIG_TIME 1
#define E_CUENTA_ATRAS 2
#define E_RELE_ACTIVADO 3

#define REBOUNCE_TIME 250

LiquidCrystal_I2C lcd(0x38,16,2);

uint8_t state = E_INICIAL;

Bounce buttonStart = Bounce(START, INTERVAL_MILLIS);
Bounce buttonReset = Bounce(RESET, INTERVAL_MILLIS);
Bounce buttonSegUp = Bounce(SEG_UP, INTERVAL_MILLIS);
Bounce buttonSegDown = Bounce(SEG_DOWN, INTERVAL_MILLIS);
Bounce buttonMinUp = Bounce(MIN_UP, INTERVAL_MILLIS);
Bounce buttonMinDown = Bounce(MIN_DOWN, INTERVAL_MILLIS);

struct tiempo{
  uint8_t horas;
  uint8_t minutos;
  uint8_t segundos;
  uint8_t decimas;
}cuenta = {0,0,0,0};

long milisegundos;

////////////////////////////////////////////
//*************SETUP*********************//
void setup(){
  pinMode(RELE, OUTPUT);
  digitalWrite(RELE, LOW);
  
  for(int i=4; i<10; i++){
    pinMode(i, INPUT_PULLUP);
  }

  lcd.init();
}
//*************SETUP***********************//
////////////////////////////////////////////
//**************LOOP*********************//
void loop(){
  switch(state){
    case E_INICIAL:{
      imprimirTiempo();
      state = E_CONFIG_TIME;
    }break;
    case E_CONFIG_TIME:{
      configTiempo();
      if(ev_reset()){
        resetTiempo();
        state = E_INICIAL;
      }
      if(ev_start()){
        activarRele();
        state = E_CUENTA_ATRAS;
      }
    }break;
    case E_CUENTA_ATRAS:{
      if(!ev_fin_cuenta_atras() && !ev_reset()){
        cuentaAtras();
      }else{
        desactivarRele();
        resetTiempo();
        state = E_INICIAL;
      }
    }break;
  }
}
//**************LOOP***********************//
////////////////////////////////////////////
boolean ev_start(){
  
  if(buttonStart.update() && buttonStart.read() == LOW){
    return true;
  }
  return false;
}
boolean ev_reset(){

  if(buttonReset.update() && buttonReset.read() == LOW){
    return true;
  }
  return false;
}
void imprimirTiempo(){
  lcd.setCursor(3,0);
  if(cuenta.horas < 10){
    lcd.print("0");
  }
  lcd.print(":");
  if(cuenta.minutos < 10){
    lcd.print("0");
  }
  lcd.print(cuenta.minutos);
  lcd.print(":");
  if(cuenta.segundos < 10){
    lcd.print("0");
  }
  lcd.print(cuenta.segundos);
  lcd.print(":");
  lcd.print(cuenta.decimas);
}
void configTiempo(){
  if(buttonMinUp.update() && buttonMinUp.read() == LOW){
    buttonMinUp.rebounce(REBOUNCE_TIME);
    if(cuenta.minutos < 59){
      cuenta.minutos++;
    }else{
      cuenta.minutos = 0;
    }
  }
  if(buttonMinDown.update() && buttonMinDown.read() == LOW){
    buttonMinDown.rebounce(REBOUNCE_TIME);
    if(cuenta.minutos > 0){
      cuenta.minutos--;
    }
  }
  if(buttonSegUp.update() && buttonSegUp.read() == LOW){
    buttonSegUp.rebounce(REBOUNCE_TIME);
    if(cuenta.segundos < 59){
      cuenta.segundos++;
    }else{
      cuenta.segundos = 0;
    }
  }
  if(buttonSegDown.update() && buttonSegDown.read() == LOW){
    buttonSegDown.rebounce(REBOUNCE_TIME);
    if(cuenta.segundos > 0){
      cuenta.segundos--;
    }
  }
  imprimirTiempo();
}
void resetTiempo(){
  cuenta.horas = 0;
  cuenta.minutos = 0;
  cuenta.segundos = 0;
  cuenta.decimas = 0;
}
boolean ev_fin_cuenta_atras(){

  if(cuenta.minutos == 0 && cuenta.segundos == 0 && cuenta.decimas == 0){
    return true;
  }

  return false;
}
void cuentaAtras(){
  int decimasTotales = (((cuenta.minutos*60)+cuenta.segundos)*10)+cuenta.decimas;
  milisegundos = millis();

  if(milisegundos % 100 == 0){
    decimasTotales--;
    cuenta.decimas = decimasTotales % 10;
    cuenta.segundos = ((decimasTotales - cuenta.decimas)/10) % 60;
    cuenta.minutos = ((decimasTotales - cuenta.decimas)/10)/60;
  
    imprimirTiempo();
  }
}
void activarRele(){
  digitalWrite(RELE, HIGH);
}
void desactivarRele(){
  digitalWrite(RELE, LOW);
}
