#include "AiEsp32RotaryEncoder.h"
#include <U8g2lib.h>                     

// Pins
#define BUZZER_PIN                  5   // buzzer
#define ROTARY_ENCODER_A_PIN        32  // rotary encoder 1
#define ROTARY_ENCODER_B_PIN        33 // rotary encoder 2
#define ROTARY_ENCODER_BUTTON_PIN   14 // rotary encoder switch

#define ROTARY_ENCODER_STEPS        4

#define VERSION       "v1.0"

// Default voltage control values
#define VOLT_MIN      410       // min selectable voltage
#define VOLT_MAX      594       // max selectable voltage
#define VOLT_DEFAULT  545       // default start voltage
#define VOLT_STEP     1         // rotary encoder voltage change steps

// Default voltage control values
#define CURR_MIN      50        // min selectable current
#define CURR_MAX      635       // max selectable current
#define CURR_DEFAULT  580       // default start current
#define CURR_STEP     1         // rotary encoder current change steps

// Control values
#define BEEP_ENABLE   true      // enable/disable buzzer
#define ECREVERSE     true      // enable/disable rotary encoder reverse
#define MAINSCREEN    1         // type of main screen (0: big numbers; 1: more infos)

// Default values that can be changed by the user and stored in the EEPROM
uint16_t  DefaultVolt = VOLT_DEFAULT;
uint16_t  DefaultCurr = CURR_DEFAULT;
bool      beepEnable  = BEEP_ENABLE;
bool      ECReverse   = ECREVERSE;

// Menu items
const char *SetupItems[]        = { "Setup Menu", "V/A Settings", "Information", "Return" };
const char *VAItems[]           = { "V/A Settings", "Set Voltage online", "Set Current online", "Default Voltage", "Default Current",  "Return" };
const char *SetVoltItems[]      = { "Voltage online", "V" };
const char *SetCurrItems[]      = { "Current online", "A" };
const char *DefaultVoltItems[]  = { "Default Voltage", "V" };
const char *DefaultCurrItems[]  = { "Default Current", "A" };

// Variables for control
uint16_t SetVoltage = VOLT_DEFAULT;
uint16_t SetCurrent = CURR_DEFAULT;
uint16_t Step;


AiEsp32RotaryEncoder rotaryEncoder = AiEsp32RotaryEncoder(ROTARY_ENCODER_A_PIN, ROTARY_ENCODER_B_PIN, ROTARY_ENCODER_BUTTON_PIN, -1, ROTARY_ENCODER_STEPS);

  U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

void IRAM_ATTR readEncoderISR()
{
    rotaryEncoder.readEncoder_ISR();
}

void setup()
{
    Serial.begin(115200);

    pinMode(BUZZER_PIN,   OUTPUT);
    digitalWrite(BUZZER_PIN, LOW);        // must be LOW when buzzer not in use

    rotaryEncoder.begin();
    rotaryEncoder.setup(readEncoderISR);
    rotaryEncoder.setAcceleration(0);

    rotaryEncoder.correctionOffset = 2; //try with zero or ROTARY_ENCODER_STEPS/2
    rotaryEncoder.isButtonPulldown = false;
	rotaryEncoder.areEncoderPinsPulldownforEsp32 = true;

    setForOption(0);

    u8g2.begin();
}

// creates a short beep on the buzzer
void beep(){
  if (beepEnable) {
    for (uint8_t i=0; i<255; i++) {
      digitalWrite(BUZZER_PIN, HIGH);
      delayMicroseconds(125);
      digitalWrite(BUZZER_PIN, LOW);
      delayMicroseconds(125);
    }
  }
}

String options[] = {"Select fast food", "How many (1...10)", "Do you want fast delicery for 2$?"};
String foods[] = {"Hot dog", "Pizza", "Hamburger", "Cheeseburger"};
String selectedFood = "";

String delivery[] = {"Normal", "Fast for extra 2$"};
String selectedDelivery = "";

int selectedQuantity = 1;

int currentOption = 0;

void setForOption(int newOption)
{
    currentOption = newOption;

    switch (newOption)
    {
    case 0:
        rotaryEncoder.setBoundaries(0, 3, true); //food type 0..3
        rotaryEncoder.setEncoderValue(0);
        break;
    case 1:
        rotaryEncoder.setBoundaries(1, 10, false); //how many pieces 1 to 10; do not go from 10 to 1
        rotaryEncoder.setEncoderValue(1);
        break;
    case 2:
        rotaryEncoder.setBoundaries(0, 1, false); //select delivery
        rotaryEncoder.setEncoderValue(0);
        break;

    default:
        break;
    }
    Serial.print(">");
    Serial.println(options[currentOption]);
    showSelection();
}

void rotary_onButtonClick()
{
    static unsigned long lastTimePressed = 0;
    if (millis() - lastTimePressed < 200)
        return;
    if  (millis() - lastTimePressed >= 500){
        SetupScreen();
    }
    lastTimePressed = millis();

    int selecedValue = rotaryEncoder.readEncoder();

    switch (currentOption)
    {
    case 0: //"Select fast food"
        selectedFood = foods[selecedValue];
        setForOption(1);
        break;
    case 1: //"Select quantity"
        selectedQuantity = selecedValue;
        setForOption(2);
        break;
    case 2: //"Select delivery"
        selectedDelivery = delivery[selecedValue];
        showOrder();
        setForOption(0);
        break;

    default:
        break;
    }
}

void showOrder()
{
    Serial.println("++++++++++++++++++++++++ ORDER DETAILS ++++++++++++++++++++++++++++++++++++++++++");
    Serial.print("You ordered ");
    Serial.print(selectedFood);
    Serial.print(", quantity: ");
    Serial.print(selectedQuantity);
    Serial.print(". Delivery: ");
    Serial.println(selectedDelivery);
    Serial.println("---------------------------------------------------------------------------------");
    Serial.println("");

    Serial.print("NEW ORDER ");
}




void showSelection()
{
    int selecedValue = rotaryEncoder.readEncoder();

    switch (currentOption)
    {
    case 0: //"Select fast food"
        Serial.print(">");
        Serial.println(foods[selecedValue]);
        break;
    case 1: //"Select quantity"
        Serial.print("Quantity: ");
        Serial.println(selecedValue);
        break;
    case 2: //"Select delivery"
        Serial.println(delivery[selecedValue]);
        break;
    default:
        break;
    }
}

void loop()
{    
    MainScreen();       // updates the main page on the OLED
    if (rotaryEncoder.encoderChanged())
    {
        //showSelection();
        Serial.println("encoderChanged");    
    }
    if (rotaryEncoder.isEncoderButtonClicked())
    {
        rotary_onButtonClick();
        Serial.println("EncoderButtonClicked");    
    }
}

// draws the main screen
void MainScreen() {
  u8g2.firstPage();
  do {
    // draw voltage/current
    u8g2.setFont(u8g2_font_ncenB08_tr);
    u8g2.setFontPosTop();
    u8g2.drawStr( 10, 0,  "SET:");
    u8g2.setCursor(45,0);
    u8g2.print((float)SetVoltage/10, 1);u8g2.print(F(" V  "));
    u8g2.print((float)SetCurrent/10, 1);u8g2.print(F(" A"));
    
    float U=54.5;
    float A=25.0;
    u8g2.setFont(u8g2_font_fur17_tf);
    u8g2.setFontPosTop();
    u8g2.setCursor(0,22);
    u8g2.print(U, 1);u8g2.print(F("V "));u8g2.print(A, 1);u8g2.print(F("A"));

  } while(u8g2.nextPage());
}

// setup screen
void SetupScreen() {

  beep();
  uint16_t SaveSetVoltage = SetVoltage;
  uint8_t selection = 0;
  bool repeat = true;
  
  while (repeat) {
    selection = MenuScreen(SetupItems, sizeof(SetupItems), selection);
    switch (selection) {
      case 0:   VAScreen(); break;
      case 1:   InfoScreen(); break;
      default:  repeat = false; break;
    }
  }  
  // updateEEPROM();
  // handleMoved = true;
  // SetVoltage = SaveSetVoltage;
  // setRotary(VOLT_MIN, VOLT_MAX, VOLT_STEP, SetVoltage);
}

// menu screen
uint8_t MenuScreen(const char *Items[], uint8_t numberOfItems, uint8_t selected) {
  uint8_t lastselected = selected;
  int8_t  arrow = 0;
  if (selected) arrow = 1;
  numberOfItems >>= 1;
  setRotary(0, numberOfItems - 2, 1, selected);
  bool    lastbutton = (!digitalRead(SWITCH_PIN));

  do {
    selected = getRotary();
    arrow = constrain(arrow + selected - lastselected, 0, 2);
    lastselected = selected;
    u8g.firstPage();
      do {
        u8g.setFont(u8g_font_7x14);
        u8g.setFontPosTop();
        u8g.drawStr( 0, 0,  Items[0]);
        u8g.drawStr( 0, 16 * (arrow + 1), ">");
        for (uint8_t i=0; i<3; i++) {
          uint8_t drawnumber = selected + i + 1 - arrow;
          if (drawnumber < numberOfItems)
            u8g.drawStr( 12, 16 * (i + 1), Items[selected + i + 1 - arrow]);
        }
      } while(u8g.nextPage());
    if (lastbutton && digitalRead(SWITCH_PIN)) {delay(10); lastbutton = false;}
  } while (digitalRead(SWITCH_PIN) || lastbutton);

  beep();
  return selected;
}
esp:VIN
esp:GND.2
esp:D13
esp:D12
esp:D14
esp:D27
esp:D26
esp:D25
esp:D33
esp:D32
esp:D35
esp:D34
esp:VN
esp:VP
esp:EN
esp:3V3
esp:GND.1
esp:D15
esp:D2
esp:D4
esp:RX2
esp:TX2
esp:D5
esp:D18
esp:D19
esp:D21
esp:RX0
esp:TX0
esp:D22
esp:D23
oled1:GND
oled1:VCC
oled1:SCL
oled1:SDA
encoder1:CLK
encoder1:DT
encoder1:SW
encoder1:VCC
encoder1:GND