// Learn about the ESP32 WiFi simulation in
// https://docs.wokwi.com/guides/esp32-wifi

#include <WiFi.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

unsigned long UpdateTime;

LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 16, 2);

// LCD1602 to Arduino Uno connection example

unsigned long ST,ET;

//Menu variables
String MainMenuItemPrompt[10];  //this is what is scrolled through when in menu
String SubMenuItemPrompt[10];  //this is what is diplayed on Line 1 on LCD when menu item selected 
int SubMenuPossibleResponses[10];  //this is the number of items in the list of possible responses
String SubMenuResponseAlias[10][10];  //this is the value that is shown on line 2 as possible responses are displayed
int SubMenuResponseValue[10][10];   //this stores the value corresponding to the array index selected as an alias
boolean InMenu = false;
boolean InSubMenu = false;
int MainMenuIndex=0;  //stored the current index in main menu
int SubMenuResponseIndex = 0;
int MenuItems = 8;   //index 0 = 1
String LCDLine1;
String LCDLine2;
String TeamA = "TeamA";
String TeamB = "TeamB";
int TeamAColor = 1;
int TeamBColor = 2;

//change these pin definitions for your schematic
int LeftUpPin = 14;
int LeftDownPin = 12;
int RightUpPin = 26;
int RightDownPin = 25;
int EnterPin = 13;
//int MenuPin = 6;    //Future

//Switch State Variable
int SwitchState = 0;
//0 = Nothing Pressed
//1 = Enter Pressed
//2 = Enter Held
//3 = Left Up Pressed
//4 = Left Up Held
//5 = Left Down Pressed
//6 = Left Down Held
//7 = Right Up Pressed
//8 = Right Up Held
//9 = Right Down Pressed
//10 = Right Down Held
//11 = Menu Pressed (Future)
//12 = Menu Held (Future)

int RightScore, LeftScore;
int Game=1;
int Brightness=1;   //valid values are 1 -10
boolean FlipSides=false;
int OldLeftScore;
int OldRightScore;


void LoadMenuItems(){

  //modify this routine for your menu
  MenuItems = 9;  //this should be 1 more than the max array numer as array starts at 0

  MainMenuItemPrompt[0]=F("Exit Menu");
  MainMenuItemPrompt[1]=F("Switch Sides");
  MainMenuItemPrompt[2]=F("Start Next Game");
  MainMenuItemPrompt[3]=F("Reset Scores");
  MainMenuItemPrompt[4]=F("Set Game #");
  MainMenuItemPrompt[5]=F("Reset All");
  MainMenuItemPrompt[6]=F("Set TeamA Color");
  MainMenuItemPrompt[7]=F("Set TeamB Color");
  MainMenuItemPrompt[8]=F("Set Brightness");

  SubMenuItemPrompt[0]=F("");
  SubMenuItemPrompt[1]=F("");
  SubMenuItemPrompt[2]=F("");
  SubMenuItemPrompt[3]=F("");
  SubMenuItemPrompt[4]=F("Set Game #:");
  SubMenuItemPrompt[5]=F("");
  SubMenuItemPrompt[6]=F("Team A Color:");
  SubMenuItemPrompt[7]=F("Team B Color:");
  SubMenuItemPrompt[8]=F("Set Brightness:");

//this stores the number of acceptable responses stored in array, non-zero indicates data input
//the submenu response array stores acceptable answers
  SubMenuPossibleResponses[0] = 0;
  SubMenuPossibleResponses[1] = 0;
  SubMenuPossibleResponses[2] = 0;
  SubMenuPossibleResponses[3] = 0;
  SubMenuPossibleResponses[4] = 9;
  SubMenuPossibleResponses[5] = 0;
  SubMenuPossibleResponses[6] = 10;
  SubMenuPossibleResponses[7] = 10;
  SubMenuPossibleResponses[8] = 10;

  //set up submenu response arrays only for menu items that require data input
  //data will be input based on the array index
  SubMenuResponseAlias[4][0] = "1";
  SubMenuResponseAlias[4][1] = "2";
  SubMenuResponseAlias[4][2] = "3";
  SubMenuResponseAlias[4][3] = "4";
  SubMenuResponseAlias[4][4] = "5";
  SubMenuResponseAlias[4][5] = "6";
  SubMenuResponseAlias[4][6] = "7";
  SubMenuResponseAlias[4][7] = "8";
  SubMenuResponseAlias[4][8] = "9";

  SubMenuResponseAlias[6][0] = "Red";
  SubMenuResponseAlias[6][1] = "Green";
  SubMenuResponseAlias[6][2] = "Blue";
  SubMenuResponseAlias[6][3] = "Magenta";
  SubMenuResponseAlias[6][4] = "Purple";
  SubMenuResponseAlias[6][5] = "Light Blue";
  SubMenuResponseAlias[6][6] = "Yellow";
  SubMenuResponseAlias[6][7] = "Lime Green";
  SubMenuResponseAlias[6][8] = "Orange";
  SubMenuResponseAlias[6][9] = "White";

  SubMenuResponseAlias[7][0] = "Red";
  SubMenuResponseAlias[7][1] = "Green";
  SubMenuResponseAlias[7][2] = "Blue";
  SubMenuResponseAlias[7][3] = "Magenta";
  SubMenuResponseAlias[7][4] = "Purple";
  SubMenuResponseAlias[7][5] = "Light Blue";
  SubMenuResponseAlias[7][6] = "Yellow";
  SubMenuResponseAlias[7][7] = "Lime Green";
  SubMenuResponseAlias[7][8] = "Orange";
  SubMenuResponseAlias[7][9] = "White";

  SubMenuResponseAlias[8][0] = "Minimum";
  SubMenuResponseAlias[8][1] = "20%";
  SubMenuResponseAlias[8][2] = "30%";
  SubMenuResponseAlias[8][3] = "40%";
  SubMenuResponseAlias[8][4] = "50%";
  SubMenuResponseAlias[8][5] = "60%";
  SubMenuResponseAlias[8][6] = "70%";
  SubMenuResponseAlias[8][7] = "80%";
  SubMenuResponseAlias[8][8] = "90%";
  SubMenuResponseAlias[8][9] = "Maximum";

  SubMenuResponseValue[4][0] = 1;
  SubMenuResponseValue[4][1] = 2;
  SubMenuResponseValue[4][2] = 3;
  SubMenuResponseValue[4][3] = 4;
  SubMenuResponseValue[4][4] = 5;
  SubMenuResponseValue[4][5] = 6;
  SubMenuResponseValue[4][6] = 7;
  SubMenuResponseValue[4][7] = 8;
  SubMenuResponseValue[4][8] = 9;

  SubMenuResponseValue[6][0] = 1;
  SubMenuResponseValue[6][1] = 2;
  SubMenuResponseValue[6][2] = 3;
  SubMenuResponseValue[6][3] = 4;
  SubMenuResponseValue[6][4] = 5;
  SubMenuResponseValue[6][5] = 6;
  SubMenuResponseValue[6][6] = 7;
  SubMenuResponseValue[6][7] = 8;
  SubMenuResponseValue[6][8] = 9;
  SubMenuResponseValue[6][9] = 10;

  SubMenuResponseValue[7][0] = 1;
  SubMenuResponseValue[7][1] = 2;
  SubMenuResponseValue[7][2] = 3;
  SubMenuResponseValue[7][3] = 4;
  SubMenuResponseValue[7][4] = 5;
  SubMenuResponseValue[7][5] = 6;
  SubMenuResponseValue[7][6] = 7;
  SubMenuResponseValue[7][7] = 8;
  SubMenuResponseValue[7][8] = 9;
  SubMenuResponseValue[7][9] = 10;

  SubMenuResponseValue[8][0] = 1;
  SubMenuResponseValue[8][1] = 2;
  SubMenuResponseValue[8][2] = 3;
  SubMenuResponseValue[8][3] = 4;
  SubMenuResponseValue[8][4] = 5;
  SubMenuResponseValue[8][5] = 6;
  SubMenuResponseValue[8][6] = 7;
  SubMenuResponseValue[8][7] = 8;
  SubMenuResponseValue[8][8] = 9;
}


void setup() {
  lcd.init();
  lcd.backlight();
  //lcd.begin(16, 2);
  Serial.begin(115200);

  pinMode(LeftUpPin, INPUT_PULLUP);
  pinMode(LeftDownPin, INPUT_PULLUP);
  pinMode(RightUpPin, INPUT_PULLUP);
  pinMode(RightDownPin, INPUT_PULLUP);
  pinMode(EnterPin, INPUT_PULLUP);

  lcd.print("ScoreFi V2.0");
  lcd.setCursor(0,1);
  lcd.print("by Darin");
  LoadMenuItems();
  delay(2000);
  UpdateLCD();

}

void loop() {
  if (millis()>UpdateTime){
    UpdateTime=millis()+50;

    CheckSwitches();

    if (InMenu == true && SwitchState > 0) {    //menu item selected
      ProcessMenuClick();
    }
    else if (InMenu == false && SwitchState > 0) {      //
      ProcessSwitches();
    }

  }


}

void UpdateLCD(){
  lcd.clear();
  if (FlipSides == false){
    lcd.print(TeamA);
    lcd.print("  [");
    lcd.print(Game);
    lcd.print("] ");
    lcd.print(TeamB);
    lcd.setCursor(2,1);
    lcd.print(RightScore);
    lcd.setCursor(13,1);
    lcd.print(LeftScore);
  }

  else {
    lcd.print(TeamB);
    lcd.print("  [");
    lcd.print(Game);
    lcd.print("] ");
    lcd.print(TeamA);
    lcd.setCursor(2,1);
    lcd.print(RightScore);
    lcd.setCursor(13,1);
    lcd.print(LeftScore);
  }

}

void ProcessMenuClick(){
  switch (SwitchState) {

    case 0:    // Exit, no button press
      break;

    case 1:    //Enter Pressed while in menu
      Serial.println("Enter Press...In Menu");
      switch (MainMenuIndex) {
        case 0:     //exit menu requested, just get out
          InMenu=false;
          MainMenuIndex = 0;   //reset menu index
          UpdateLCD();
          break;

        case 1:    //switch sides request
          InMenu=false;
          FlipSides = !FlipSides;
          OldLeftScore = LeftScore;
          OldRightScore = RightScore;
          RightScore = OldLeftScore;
          LeftScore = OldRightScore;
          MainMenuIndex = 0;   //reset menu index
          UpdateLCD();
          break;

        case 2:    //Start Next game/set request
          InMenu=false;
          Game++;    //increment the game number
          if (Game > 9){
            Game = 0;
          }
          LeftScore = 0;
          RightScore = 0;
          MainMenuIndex = 0;   //reset menu index
          UpdateLCD();
          break;

        case 3:   //reset scores
          InMenu=false;
          LeftScore = 0;
          RightScore = 0;
          MainMenuIndex = 0;   //reset menu index
          UpdateLCD();
          break;
        
        case 4:   //Set Game Number
          if (InSubMenu == true){   //if we are in a submenu, set the current value in array
            Game = SubMenuResponseValue[MainMenuIndex][SubMenuResponseIndex];
            Serial.print("Game: ");
            Serial.println(Game);
            UpdateLCD();
            MainMenuIndex = 0;   //reset menu index
            InSubMenu = false;
          }
          else {
            SubMenuResponseIndex = Game - 1;
            lcd.clear();
            lcd.print(SubMenuItemPrompt[MainMenuIndex]);
            lcd.setCursor(0,1);
            lcd.print(SubMenuResponseAlias[MainMenuIndex][SubMenuResponseIndex]);  
            InSubMenu = true;
          }
          break;

        case 5:  //Reset All
          InMenu=false;
          LeftScore = 0;
          RightScore = 0;
          Game = 1;
          FlipSides = false;
          MainMenuIndex = 0;   //reset menu index
          UpdateLCD();
          break;
        
        case 6:   //Change TeamA Color
          if (InSubMenu == true){   //if we are in a submenu, set the current value in array
            TeamAColor = SubMenuResponseValue[MainMenuIndex][SubMenuResponseIndex];
            Serial.print("Team A Color: ");
            Serial.println(TeamAColor);
            UpdateLCD();
            MainMenuIndex = 0;   //reset menu index
            InSubMenu = false;
          }
          else {
            SubMenuResponseIndex = TeamAColor - 1;
            lcd.clear();
            lcd.print(SubMenuItemPrompt[MainMenuIndex]);
            lcd.setCursor(0,1);
            lcd.print(SubMenuResponseAlias[MainMenuIndex][SubMenuResponseIndex]);  
            InSubMenu = true;
          }
          break;
          
        case 7:   //Change TeamB Color
          if (InSubMenu == true){   //if we are in a submenu, set the current value in array
            TeamBColor = SubMenuResponseValue[MainMenuIndex][SubMenuResponseIndex];
            Serial.print("Team B Color: ");
            Serial.println(TeamBColor);
            UpdateLCD();
            MainMenuIndex = 0;   //reset menu index
            InSubMenu = false;
          }
          else {
            SubMenuResponseIndex = TeamBColor - 1;
            lcd.clear();
            lcd.print(SubMenuItemPrompt[MainMenuIndex]);
            lcd.setCursor(0,1);
            lcd.print(SubMenuResponseAlias[MainMenuIndex][SubMenuResponseIndex]);  
            InSubMenu = true;
          }
          break;

        case 8:   //Change Brightness
          if (InSubMenu == true){   //if we are in a submenu, set the current value in array
            Brightness = SubMenuResponseValue[MainMenuIndex][SubMenuResponseIndex];
            Serial.print("Brightness: ");
            Serial.println(Brightness);            
            UpdateLCD();
            MainMenuIndex = 0;   //reset menu index
            InSubMenu = false;
          }
          else {
            SubMenuResponseIndex = Brightness - 1;
            lcd.clear();
            lcd.print(SubMenuItemPrompt[MainMenuIndex]);
            lcd.setCursor(0,1);
            lcd.print(SubMenuResponseAlias[MainMenuIndex][SubMenuResponseIndex]);  
            InSubMenu = true;
          }
          break;

     
      }

      
      break;   //for case 1 enter pressed
    
    case 2:    //enter held (Exit Menu)
      InMenu=false;
      UpdateLCD();
      MainMenuIndex = 0;   //reset menu index
      break;

    case 3:    //Left Up Pressed
      if (InSubMenu == true){   //if we are in a submenu, show next value in array
        SubMenuResponseIndex++;  //increment the index
        if (SubMenuResponseIndex > SubMenuPossibleResponses[MainMenuIndex]-1){   //make sure within bounds
          SubMenuResponseIndex = SubMenuPossibleResponses[MainMenuIndex]-1;   //
        }
        lcd.clear();
        lcd.print(SubMenuItemPrompt[MainMenuIndex]);
        lcd.setCursor(0,1);
        lcd.print(SubMenuResponseAlias[MainMenuIndex][SubMenuResponseIndex]);  
        InSubMenu = true;
      }
      else {  //we are not in submenu, so step through main menu items
        if (MainMenuIndex - 1 >= 0) {
          MainMenuIndex--;
        }
        ShowMenu();
      }
      
      break;   //for case 3 Left Up pressed
    
    case 5:    //Left Down Pressed
      if (InSubMenu == true){   //if we are in a submenu, show next value in array
        SubMenuResponseIndex--;  //increment the index
        if (SubMenuResponseIndex < 0){   //make sure within bounds
          SubMenuResponseIndex = 0;   //
        }
        lcd.clear();
        lcd.print(SubMenuItemPrompt[MainMenuIndex]);
        lcd.setCursor(0,1);
        lcd.print(SubMenuResponseAlias[MainMenuIndex][SubMenuResponseIndex]);  
        InSubMenu = true;
      }
      else {  //we are not in submenu, so step through main menu items
        if (MainMenuIndex + 1 <= MenuItems -1){
          MainMenuIndex++;
        }
        ShowMenu();
      }
      break;   //for case 5 Left Down pressed

    case 7:    //Right Up Pressed
      if (InSubMenu == true){   //if we are in a submenu, show next value in array
        SubMenuResponseIndex++;  //increment the index
        if (SubMenuResponseIndex > SubMenuPossibleResponses[MainMenuIndex]-1){   //make sure within bounds
          SubMenuResponseIndex = SubMenuPossibleResponses[MainMenuIndex]-1;   //
        }
        lcd.clear();
        lcd.print(SubMenuItemPrompt[MainMenuIndex]);
        lcd.setCursor(0,1);
        lcd.print(SubMenuResponseAlias[MainMenuIndex][SubMenuResponseIndex]);  
        InSubMenu = true;
      }
      else {  //we are not in submenu, so step through main menu items
        if (MainMenuIndex - 1 >= 0) {
          MainMenuIndex--;
        }
        ShowMenu();
      }
      
      break;   //for case 7 Right Up pressed
    
    case 9:    //Right Down Pressed
      if (InSubMenu == true){   //if we are in a submenu, show next value in array
        SubMenuResponseIndex--;  //increment the index
        if (SubMenuResponseIndex < 0){   //make sure within bounds
          SubMenuResponseIndex = 0;   //
        }
        lcd.clear();
        lcd.print(SubMenuItemPrompt[MainMenuIndex]);
        lcd.setCursor(0,1);
        lcd.print(SubMenuResponseAlias[MainMenuIndex][SubMenuResponseIndex]);  
        InSubMenu = true;
      }
      else {  //we are not in submenu, so step through main menu items
        if (MainMenuIndex + 1 <= MenuItems -1){
          MainMenuIndex++;
        }
        ShowMenu();
      }
      break;   //for case 9 Right Down pressed

  }
}

void ShowMenu() {
  InMenu = true;
  lcd.clear();

  LCDLine1 = MainMenuItemPrompt[MainMenuIndex];
  LCDLine2="";
  
  if (MainMenuIndex < (MenuItems - 1)) {
    LCDLine2 = MainMenuItemPrompt[MainMenuIndex + 1];
  }
  
  lcd.print(">");
  lcd.print(LCDLine1);
  lcd.setCursor(1,1);
  lcd.print(LCDLine2);

}


void ProcessSwitches(){

  switch (SwitchState) {

    case 0:    // Exit, no button press
      break;

    case 1:    //Enter Pressed Enter Menu
      Serial.println("Enter Press...Enter Menu");
      ShowMenu();
      InMenu=true;
      break;

    case 2:    //Enter Held
      Serial.println("Enter Held");
      break;

    case 3:    //Left Up Pressed
      RightScore++;
      UpdateLCD();
      Serial.println("Left Up Press");
      break;

    case 4:    //Left Up Held
      Serial.println("Left Up Held");
      break;

    case 5:    //Left Down Pressed
      RightScore--;
      UpdateLCD();
      Serial.println("Left Down Press");
      break;

    case 6:    //Left Down Held
      Serial.println("Left Down Held");
      break; 

    case 7:    //Right Up Pressed
      LeftScore++;
      UpdateLCD();
      Serial.println("Right Up Press");
      break;

    case 8:    //Right Up Held
      Serial.println("Right Up Held");
      break;

    case 9:    //Right Down Pressed
      LeftScore--;
      UpdateLCD();
      Serial.println("Right Down Press");
      break;

    case 10:    //Right Down Held
      Serial.println("Right Down Held");
      break;       

  }
  SwitchState = 0;   //reset
  
  delay(500);  //to eliminate bounce back to press

}

void CheckSwitches(){
  //0 = Nothing Pressed
  //1 = Enter Pressed
  //2 = Enter Held
  //3 = Left Up Pressed
  //4 = Left Up Held
  //5 = Left Down Pressed
  //6 = Left Down Held
  //7 = Right Up Pressed
  //8 = Right Up Held
  //9 = Right Down Pressed
  //10 = Right Down Held
  //11 = Menu Pressed (Future)
  //12 = Menu Held (Future)

  SwitchState = 0;   //reset


  //check Enter Switch first
  if (digitalRead(EnterPin) == LOW){
    ST = millis();
    while (digitalRead(EnterPin) == LOW){  //debounce
      delay(1);
      ET = millis()-ST;
    }

    //if we got here we have a debounced button press
    if (ET > 50 && ET <750){    //short press
      SwitchState = 1;
      return;
    }
    else if (ET > 750 ){   //long press
      SwitchState = 2;
      return;
    }
  }

  //check Left Up
  if (digitalRead(LeftUpPin) == LOW){
    ST = millis();
    while (digitalRead(LeftUpPin) == LOW){  //debounce
      delay(1);
      ET = millis()-ST;
    }

    //if we got here we have a debounced button press
    if (ET > 50 && ET <750){    //short press
      SwitchState = 3;
      return;
    }
    else if (ET > 750 ){   //long press
      SwitchState = 4;
      return;
    }
  }

  //check Left Down
  if (digitalRead(LeftDownPin) == LOW){
    ST = millis();
    while (digitalRead(LeftDownPin) == LOW){  //debounce
      delay(1);
      ET = millis()-ST;
    }

    //if we got here we have a debounced button press
    if (ET > 50 && ET <750){    //short press
      SwitchState = 5;
      return;
    }
    else if (ET > 750 ){   //long press
      SwitchState = 6;
      return;
    }
  }

//check Right Up
  if (digitalRead(RightUpPin) == LOW){
    ST = millis();
    while (digitalRead(RightUpPin) == LOW){  //debounce
      delay(1);
      ET = millis()-ST;
    }

    //if we got here we have a debounced button press
    if (ET > 50 && ET <750){    //short press
      SwitchState = 7;
      return;
    }
    else if (ET > 750 ){   //long press
      SwitchState = 8;
      delay(500);  //to eliminate bounce back to press
      return;
    }
  }
  
//check Right Down
  if (digitalRead(RightDownPin) == LOW){
    ST = millis();
    while (digitalRead(RightDownPin) == LOW){  //debounce
      delay(1);
      ET = millis()-ST;
    }

    //if we got here we have a debounced button press
    if (ET > 50 && ET <750){    //short press
      SwitchState = 9;
      return;
    }
    else if (ET > 750 ){   //long press
      SwitchState = 10;
      return;
    }
  }

}  //end of check switches