#include <Wire.h>
#include <Adafruit_GFX.h>
#include "FORS_SSD1306_6448.h"

#define ENCODER_CLK 2
#define ENCODER_DT 6
#define ENCODER_SW 7
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET 4

FORS_SSD1306 display(OLED_RESET);

#define MODE_MENU 0
#define MODE_DASHBOARD 1
#define MODE_GRAPH 2

typedef struct {
    String items[3];
} MENU;

MENU menus[] = {{"Setup","Limits","Start/Stop"},
                {"Back","Cooking time","Screen"},
                {"Back","Temperature","Min/Max"}};

int encStep = 0;
int mnuIdx = 0;
byte menuLevel = 0;
byte screenMode = MODE_MENU;
bool running = false;

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

  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }
  display.display();
  delay(500);

  pinMode(ENCODER_CLK, INPUT);
  pinMode(ENCODER_DT, INPUT);
  pinMode(ENCODER_SW, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(ENCODER_CLK), readEncoder, FALLING);

  Serial.println("setup done...");
}

void readEncoder() {
  int dtValue = digitalRead(ENCODER_DT);
  if (dtValue == HIGH)
    encStep = -1;
  else
    encStep = 1;
}

int getEncStep() {
  int result;
  noInterrupts();
  result = encStep;
  interrupts();
  return result;
}

void clearEncStep() {
  noInterrupts();
  encStep = 0;
  interrupts();
}

void loop() {
  mnuIdx += getEncStep();

  MENU currentMenu = menus[menuLevel];

  if (mnuIdx < 0) 
    mnuIdx = 2;
  if (mnuIdx > 2)
    mnuIdx = 0;
  clearEncStep();

  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_INVERSE);

  for(int i=0;i<3;i++) {
    int y = 10+(15*i);
    if (mnuIdx == i) {
      display.fillRect(10,y-2, 108, 12, SSD1306_WHITE);
      
    }
    display.setCursor(30,y);
    display.print(currentMenu.items[i]);
  }
  display.display();

  delay(100);

  if (digitalRead(ENCODER_SW) == LOW) {
    handleClick();  
  }
}

void handleClick() {
  switch (screenMode) {
    case MODE_MENU:
      handleMenu();
      break;
    case MODE_DASHBOARD:
    case MODE_GRAPH:
      screenMode = MODE_MENU;
      menuLevel = 0;
      mnuIdx = 0;
      break;
  }
}

void handleMenu() {
    switch (menuLevel) {
      case 0:  // Main menu
        switch (mnuIdx) {
          case 0:
            menuLevel = 1;
            mnuIdx = 0;
            break;
          case 1:
            menuLevel = 2;
            mnuIdx = 0;
            break;
          case 2:
            doStartStop();
            break;
        }
        break;
      case 1: // Setup menu
        switch (mnuIdx) {
          case 0:
            doBack();
            break;
          case 1:
            doSetCookTime();
            break;
          case 2:
            doSetScreen();
            break;
        }
        break;
      case 2: // Limits menu
        switch (mnuIdx) {
          case 0:
            doBack();
            break;
          case 1:
            doSetTemperature();
            break;
          case 2:
            doSetMinMax();
            break;
        }
        break;
    }
}

void doBack() {
  mnuIdx = menuLevel -1;
  menuLevel = 0;
}

void doSetCookTime() {
  Serial.println("CookTime");
}

void doSetTemperature() {
  Serial.println("Temparature");
}

void doSetScreen() {
  Serial.println("Screen");
}

void doSetMinMax() {
  Serial.println("Min/Max");
}

void doStartStop() {
  running = !running;
  Serial.println(running?"Started":"Stopped");
}