#include <IRremote.h>  //versione libreria 3.5.0
#include <JC_Button.h>

#include <LiquidCrystal.h>
#include <Servo.h>

// hardware buttons
#define BTN_POWER     4 

// IR & IR commands
// Signal Pin of IR receiver
#define PIN_RECEIVER  2   
#define IRCMD_POWER   162

// stati 
#define S_POWER_ON    1
#define S_POWER_OFF   2
#define S_ENTER_SLEEP 3
#define S_ENTER_POWER_ON 4
#define S_POWER_INIT  S_POWER_OFF

Button btnPower(BTN_POWER);
IRrecv receiver(PIN_RECEIVER);

// powerState è variabile di stato su switch case
uint8_t powerState = S_POWER_INIT; 
uint8_t oldPowerState = S_POWER_ON; 
uint8_t saveCommand;
uint32_t powerTimer;

LiquidCrystal lcd(12, 11, 10, 9, 8, 7);

void setup() {
    Serial.begin(115200);
  
    receiver.enableIRIn(); // Start the receiver

    lcd.begin(16, 2);
    btnPower.begin();

}

void onLoop() {
    static uint32_t time = millis();
    if (millis() - time >= 500) {
        Serial.print('.');
    } 
}

void loop() {
    btnPower.read();
    uint8_t command = 0;

    if (receiver.decode()) {
        command = receiver.decodedIRData.command;
        receiver.resume();  // Receive the next value
        Serial.println(command);
    } else {

        /*if (btnPower.pressedFor(300) && saveCommand != IRCMD_POWER) {
            command = IRCMD_POWER;
            saveCommand = command;
        } else if (btnPower.isReleased()) {
            saveCommand = 0;
        }*/
        if (btnPower.wasPressed())
            command = IRCMD_POWER;
    }

    switch (powerState) {
        case S_ENTER_POWER_ON:
            if (command == 0 && millis() - powerTimer >= 1000)
                powerState = S_POWER_ON;
            // chiama funzione che accende gli alimentatori
            // attende il riscaldamento con millis
            // ok è pronto e passa a S_POWER_ON
            
        break;

        case S_POWER_ON:
                
        if (command == IRCMD_POWER) {
            Serial.println("go to sleep");
            powerState = S_ENTER_SLEEP;
            // salva il tempo in cui abbandona questo stato
            //powerTimer = millis();

        }
        // chiama funzione onLoop();
        onLoop();
        // la funzione è equivalente al void loop()
        // solo che adesso onLoop() viene chiamata 
        // dallo stato S_POWER_ON e pertanto tutto il 
        // codice contenuto in onLoop() viene eseguito 
        // perché la macchina è in S_POWER_ON.
        break;
        
        case S_ENTER_SLEEP:
            // chiama funzione che spegne gli alimentatori
            // se questi risultano accesi, diversamente non
            // la chiama, ad esempio:
            // if (powerSupply.isOn()) {
            //     powerSupply.off();
            // }
            // entra in modo sonno
            // simula con delay un sonno di 2 secondi
            //Serial.println("sono entrato in sleep");
            //delay(2000);
            // e resta qui fino a quando 
            // arriva una IRQ e si sveglia
            // salva l'istante del risveglio
            //if (btnPower.isPressed()) {
                powerTimer = millis();
                // cambia stato per S_POWER_OFF
                powerState = S_POWER_OFF;
                //Serial.println("esco da sleep e passo a power off");
            //}

        break;
        case S_POWER_OFF:
            
            if (command == IRCMD_POWER ) {
                Serial.println("go to power on");
                powerState = S_ENTER_POWER_ON;
                powerTimer = millis();
            } else if (millis() - powerTimer >= 1000) {
                // dopo un secondo dal risveglio
                // torna a dormire.
                // Oppure se entro 1 secondo 
                // command vale IRCMD_POWER
                powerState = S_ENTER_SLEEP;
            }
             
        break;
   }
}