/*
 * Very simple menu on an OLED display (with 8 lines of text).
 * Displays menu items from the array menu. Max. number of items is 7.
 * 
 * This sketch uses the library "U8g2", "Bounce2" and uses 3 buttons (up/down/select).
 * 
 */

#include <U8g2lib.h>

#define P_ENC_A 25
#define P_ENC_B 26
#define P_ENC_SW 27

U8X8_SSD1306_128X64_NONAME_HW_I2C display(U8X8_PIN_NONE);

#define MENU_SIZE 10
#define MENU_ROWS 3

char *menu[MENU_SIZE] = {
  "Den je moc",
  "Za dvermi",
  "Mesto",
  "Soused",
  "Karlin",
  "Vres",
  "Klidne se me",
  "Jeste me drz",
  "Jeste kousek",
  "Svatojanska"
};

int cursor = 0;
bool selected = false;

struct Encoder {
  bool a;
  bool b;
  int delta;
};

Encoder enc = {false, false, 0};

void IRAM_ATTR enc_isr_a() {
  bool b = digitalRead(P_ENC_B) == HIGH;

  if (b != enc.b) {
    enc.b = b;

    if (enc.a) {
      enc.delta += b ? -1 : 1;
    }
  }
}

void IRAM_ATTR enc_isr_b() {
  bool a = digitalRead(P_ENC_A) == HIGH;

  if (a != enc.a) {
    enc.a = a;
  }
}

void setup() {
  pinMode(P_ENC_A, INPUT);
  pinMode(P_ENC_B, INPUT);
  pinMode(P_ENC_SW, INPUT_PULLUP);

  enc.a = digitalRead(P_ENC_A) == HIGH;
  enc.b = digitalRead(P_ENC_B) == HIGH;

  attachInterrupt(digitalPinToInterrupt(P_ENC_A), enc_isr_a, CHANGE);
  attachInterrupt(digitalPinToInterrupt(P_ENC_B), enc_isr_b, CHANGE);

  display.begin();
  display.setPowerSave(0);

  renderMenu();
}

void loop() {
  if (enc.delta != 0) {
    cursor = max(0, min(MENU_SIZE - 1, cursor + enc.delta));
    enc.delta = 0;
    selected = false;
    renderMenu();
  } else if (!selected && digitalRead(P_ENC_SW) == LOW) {
    selected = true;
    renderCurrent();
  }

  delay(50);
}

void renderMenu() {
  int offset = max(0, min(MENU_SIZE - MENU_ROWS, cursor - 1));

  display.clearDisplay();
  display.setFont(u8x8_font_7x14B_1x2_f);

  char* line = (char*) malloc(17);

  for (int i = 0; i < MENU_ROWS; ++i) {
    sprintf(line, "%02d %-13.13s", i + offset + 1, menu[i + offset]);
    display.setInverseFont(i + offset == cursor);
    display.drawString(0, 3 * i, line);
  }

  free(line);
}

void renderCurrent() {
  char* line = (char*) malloc(17);
  char* sp;

  display.clearDisplay();
  display.setInverseFont(0);
  
  sprintf(line, "%02d", cursor + 1);
  display.setFont(u8x8_font_7x14B_1x2_f);
  display.drawString(0, 0, line);

  display.setFont(u8x8_font_courB18_2x3_f);

  if (strlen(menu[cursor]) <= 8) {
    sprintf(line, "%-8.8s", menu[cursor]);
    display.drawString(0, 2, line);
  } else {
    sp = strstr(menu[cursor], " ");

    if (sp == NULL) {
      sp = menu[cursor] + 8;
    } else {
      ++sp;
    }

    sprintf(line, "%-*.*s", sp - menu[cursor], sp - menu[cursor], menu[cursor]);
    display.drawString(0, 2, line);
    sprintf(line, "%-8.8s", sp);
    display.drawString(0, 5, line);
  }

  free(line);
}
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
ssd1306:DATA
ssd1306:CLK
ssd1306:DC
ssd1306:RST
ssd1306:CS
ssd1306:3V3
ssd1306:VIN
ssd1306:GND
enc:CLK
enc:DT
enc:SW
enc:VCC
enc:GND