#include <AccelStepper.h>
#include <EEPROM.h>
#include <LiquidCrystal_I2C.h>
const int attesa_piega=4000;
const int maxspeed=1000;
const int  acceleration=500;
const int stepPin = 4;
const int dirPin = 3;
AccelStepper stepper(AccelStepper::DRIVER, stepPin, dirPin);
const float stepPerMM = 50.0;
const int stepIncrement = 25;
const int maxPosizioni = 10;
long posizioni[maxPosizioni];
int posSalvate = 1;
int indiceCorrente = 0;
long posizioneAttuale = 0;
long targetPosition = 0;
const int eepromStart = 0;
unsigned long lastMoveTime = 0;
const unsigned long interval = 150;
unsigned long salvaPressStart = 0;
bool salvaAttivo = false;
LiquidCrystal_I2C lcd(0x27, 20, 4);
class DebouncedButton {
  int pin;
  bool state;
  bool lastStableState;
  unsigned long lastDebounceTime;
  const unsigned long debounceDelay = 50;
public:
  DebouncedButton(int p) : pin(p), state(false), lastStableState(false), lastDebounceTime(0) {}
  void setup() {
    pinMode(pin, INPUT_PULLUP);
    state = !digitalRead(pin);
    lastStableState = state;
    lastDebounceTime = millis();
  }
  void update() {
    bool reading = !digitalRead(pin);
    if (reading != lastStableState) {
      lastDebounceTime = millis();
    }
    if ((millis() - lastDebounceTime) > debounceDelay) {
      if (reading != state) {
        state = reading;
      }
    }
    lastStableState = reading;
  }
  bool isPressed() {
    return state;
  }
};
DebouncedButton buttonOrario(5);
DebouncedButton buttonAntiorario(6);
DebouncedButton buttonSalva(7);
DebouncedButton buttonVaiA(8);
void updateDisplay() {
  float posizioneMM = posizioneAttuale / stepPerMM;
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Posizioni: ");
  lcd.print(posSalvate);
  lcd.setCursor(0, 1);
  lcd.print("Pos: ");
  lcd.print(posizioneMM, 2);
  lcd.print(" mm");
}
void setup() {
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("Sistema pronto");
  delay(1000);
  stepper.setMaxSpeed(maxspeed);
  stepper.setAcceleration(acceleration);
  buttonOrario.setup();
  buttonAntiorario.setup();
  buttonSalva.setup();
  buttonVaiA.setup();
  EEPROM.get(eepromStart, posSalvate);
  if (posSalvate < 1 || posSalvate > maxPosizioni) posSalvate = 1;
  posizioni[0] = 0;
  for (int i = 1; i < posSalvate; i++) {
    EEPROM.get(eepromStart + sizeof(int) + (i - 1) * sizeof(long), posizioni[i]);
  }
  targetPosition = posizioneAttuale;
  updateDisplay();
}
void loop() {
  stepper.run();
  buttonOrario.update();
  buttonAntiorario.update();
  buttonSalva.update();
  buttonVaiA.update();
  static bool salvaPrev = false;
  static bool vaiPrev = false;
  unsigned long currentMillis = millis();
  if (buttonOrario.isPressed() && currentMillis - lastMoveTime >= interval) {
    targetPosition += stepIncrement;
    lastMoveTime = currentMillis;
  }
  if (buttonAntiorario.isPressed() && currentMillis - lastMoveTime >= interval) {
    targetPosition -= stepIncrement;
    lastMoveTime = currentMillis;
  }
  if (!buttonOrario.isPressed() && !buttonAntiorario.isPressed() && targetPosition % stepIncrement != 0) {
    targetPosition = round((float)targetPosition / stepIncrement) * stepIncrement;
  }
  stepper.moveTo(targetPosition);
  posizioneAttuale = targetPosition;
  if (buttonSalva.isPressed()) {
    if (!salvaPrev) {
      salvaPressStart = currentMillis;
      salvaAttivo = false;
    } else if (!salvaAttivo && (currentMillis - salvaPressStart >= 1000)) {
      salvaAttivo = true;
      if (posSalvate < maxPosizioni) {
        posizioni[posSalvate] = posizioneAttuale;
        posSalvate++;
        EEPROM.put(eepromStart, posSalvate);
        for (int i = 1; i < posSalvate; i++) {
          EEPROM.put(eepromStart + sizeof(int) + (i - 1) * sizeof(long), posizioni[i]);
        }
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("Salvato:");
        lcd.setCursor(0, 1);
        lcd.print(posizioneAttuale / stepPerMM, 2);
        lcd.print(" mm");
        delay(500);
        updateDisplay();
      }
    } else {
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Tieni premuto");
      lcd.setCursor(0, 1);
      lcd.print((currentMillis - salvaPressStart) / 1000.0, 1);
      lcd.print(" sec");
    }
  }
  salvaPrev = buttonSalva.isPressed();
  if (buttonVaiA.isPressed() && !vaiPrev && !buttonSalva.isPressed() && posSalvate > 0 && !stepper.isRunning()) {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("ATTESA..");
    lcd.print(attesa_piega);
    lcd.print(" millisec.");
    delay(attesa_piega);
    
    
    
    targetPosition = posizioni[indiceCorrente];
    posizioneAttuale = targetPosition;
    stepper.moveTo(targetPosition);
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Piega N:");
    lcd.print(indiceCorrente + 1);
    lcd.setCursor(0, 1);
    lcd.print("Pos: ");
    lcd.print(posizioneAttuale / stepPerMM, 2);
    lcd.print(" mm");
    indiceCorrente = (indiceCorrente + 1) % posSalvate;
    delay(300);
  }
  vaiPrev = buttonVaiA.isPressed();
}