#include <TFT_eSPI.h>      // Hardware-specific library
#include <SPI.h>
#include <JC_Button.h>
#include <ESP32Time.h>


ESP32Time rtc(0);
TFT_eSPI tft = TFT_eSPI(); // Invoke custom library

// button pins
#define UP_PIN     12
#define DOWN_PIN   13
#define ENTER_PIN  14
#define BACK_PIN   27
/*
//for real board
#define UP_PIN     3
#define DOWN_PIN   8
#define ENTER_PIN  17
#define BACK_PIN   18
*/
Button btnUP(UP_PIN), btnDOWN(DOWN_PIN), btnENTER(ENTER_PIN), btnBACK(BACK_PIN);    // define the buttons

//offset of all the graphics if the screen is incorrecly placed in the cluster
int offset_x = 3;
int offset_y = 2;

//global variables
int speedDIR = 0;
int current_screen = 0;   //0==big1sensor(speed), 1==sensor4, 2==sensor7, 3=menu
int selected_item = -1;
int sensor_item = -1;
const int NUM_SCREENS = 3; //4 screens

const char *SENSOR_NAMES[] = {"RPM", "IAT", "TPS", "CLT", "EGT", "MAP", "MAF", "SPD"};   //sensor name array
const char *SENSOR_UNITS[] = {"RPM ", "deg ", "%   ", "deg ", "deg ", "mbar", "g/s ", "km/h"};
int  SENSOR_VALUES[] = {890, 26, 50, 89, 660, 1400, 380, 100};                           //sensor value array
const int SENSOR_NUMBER = 7;                                                             //amount of sensors (number-1)

int SCREEN_BIG = 7;                                       //selection to show big number
int SCREEN_SENSOR4_SELECTION[] = {0,1,2,3};               //array which sensor to show in screen4sensors
int SCREEN_SENSOR7_SELECTION[] = {0,1,2,3,4,5,6};         //array which sensor to show in screen7sensors

const int sens4_xy[4][2] = {{77,81},{150,81},{77,110},{150,110}}; //4 sensor screen item coordinates
const int MENU_ITEMS_NUMBER = 4; //how many items in main menu start from 0, so -1
const char *MENU_NAMES[] = {"DIAG CAN   ", "DIAG K-line", "Brightness ", "Time       ", "FW Update  "};
bool select_state = false;        // if the select button is pressed
bool activated_state = false;     //placeholder for aditional show sensor list or menu items

int brightness = 5;


void setup() {
  Serial.begin(115200);
  rtc.setTime(30, 24, 15, 17, 1, 2021); // Set time to 17th Jan 2021 15:24:30
  btnUP.begin();
  btnDOWN.begin();
  btnENTER.begin();
  btnBACK.begin();
 
  tft.init();
  tft.setRotation(1);
  tft.fillScreen(TFT_BLACK);

  tft.setCursor(10+offset_x, 2+offset_y);
  tft.setTextColor(TFT_RED);
  tft.setTextSize(3);
  tft.drawRect(0+offset_x, 0+offset_y, 160, 25, TFT_RED);
  tft.println("GOLF GTD");
  
  
  tft.drawSmoothRoundRect(7+offset_x, 60+offset_y, 5, 5, 146, 58, TFT_RED, TFT_BLACK); //x,y,r1,r2, w,h, color, bgcolor
  logo(TFT_WHITE, TFT_BLUE);
  delay(1000);
  tft.fillRect(1+offset_x, 1+offset_y, 158, 23, TFT_BLACK);                             //reset top
  drawTopLine();
  clearBot();
    
  }

void loop() {
  
  readSensors();
  drawBot(activated_state);
  drawTopLine();

  btnUP.read();      
  if(btnUP.wasPressed()) {
    if(select_state == true && activated_state == false){                                   //check if selection is activated
      selected_item++;
      if (current_screen == 1){  //screen 1 only has 4 sensors
        if (selected_item > 3) { 
        selected_item = 0;
        }
      }
      else if (current_screen == 2) {//screen 2 only has 7 sensors
        if (selected_item > 6) { 
          selected_item = 0;
          }
        }
      else if (current_screen == 3) {//screen 1 only has MENU_ITEMS_NUMBER
        if (selected_item > MENU_ITEMS_NUMBER) { 
          selected_item = 0;
          }
      }
      Serial.print("up button in select state: ");
      Serial.println(selected_item);
      }
    else if(select_state == false && activated_state == true){
      sensor_item++;
      if(sensor_item > SENSOR_NUMBER){ sensor_item = 0;}
      Serial.print("up button in sensor: "); 
      Serial.println(sensor_item);
      }
    else if (select_state == false && activated_state == false){                                               //else cycle through screens
      current_screen++;
      if (current_screen > NUM_SCREENS) { 
        current_screen = 0;
        }
      clearBot(); 
      Serial.print("->");
      }
    }
  
  btnDOWN.read();
  if(btnDOWN.wasPressed()){
    if(select_state == true && activated_state == false){                                   //check if selection is activated
      selected_item--;
      if(selected_item < 0){
        if(current_screen == 1){selected_item = 3;}                    //4sensor
        if(current_screen == 2){selected_item = 6;}                    //7sensor
        if(current_screen == 3){selected_item = MENU_ITEMS_NUMBER;}    //menu items
        }
      Serial.print("bown button in select state: "); 
      Serial.println(selected_item);
      }
    else if(select_state == false && activated_state == true){
      sensor_item--;
      if(sensor_item < 0){ sensor_item = SENSOR_NUMBER;}
      Serial.print("down button in sensor: "); 
      Serial.println(sensor_item);
      }
    else if(select_state == false && activated_state == false){                                               //else cycle through screens
      current_screen--;
      if (current_screen < 0) { 
        current_screen = NUM_SCREENS;
        }
      clearBot(); 
      Serial.println("<-");
    }
  }

  btnENTER.read();
  if(btnENTER.wasPressed()){
    Serial.print("ent pressed: ");
    if(select_state == false && activated_state == false){
      select_state = true;
      selected_item = 0;
      Serial.println("menu->selection"); 
      }
    else if(select_state == true && activated_state == false){
      sensor_item = 0;
      select_state = false;
      activated_state = true;
      Serial.println("selection->sensor_menu");
      clearBot(); 
      }
    else if(select_state == false && activated_state == true){
      //sensor_item = 0;
      select_state = true;
      activated_state = false;
      Serial.print("return sensor: ");
      Serial.println(sensor_item);
      clearBot();
      assignSensorItem();
      }
    }
  
  btnBACK.read();
  if(btnBACK.wasPressed()) {
    Serial.print("bck pressed: ");
    if(select_state == true && activated_state == false){
      select_state = false;
      selected_item = -1;
      Serial.println("selection->menu");
      } 
    else if(select_state == false && activated_state == true){
      select_state = true;
      activated_state = false;
      sensor_item = -1;
      Serial.println("sensor_menu->selection");
      clearBot(); 
      }
    } 
  }


void clearBot(){
  tft.fillSmoothRoundRect(8+offset_x, 61+offset_y, 145, 57, 5, TFT_BLACK, TFT_BLACK);
  }
void drawTopLine(){
  tft.setTextColor(TFT_WHITE, TFT_BLACK);
  tft.setTextSize(2);
  tft.setTextDatum(ML_DATUM);
  tft.drawFloat(26.3, 1, 4+offset_x,14+offset_y);                           //draw temp value
  tft.drawChar(53+offset_x, 6+offset_y, 0xF7, TFT_WHITE, TFT_BLACK,2);      //draw degree sign
  tft.setTextDatum(MR_DATUM);
  tft.drawString(rtc.getTime("%H:%M"), 157+offset_x,14+offset_y);           //draw time
  }
void logo(uint16_t color1, uint16_t color2) {
  //Circles
  tft.fillSmoothCircle(80+offset_x, 89+offset_y, 26, color2, TFT_BLACK);
  tft.fillSmoothCircle(80+offset_x, 89+offset_y, 22, color1, color2);
  tft.fillSmoothCircle(80+offset_x, 89+offset_y, 18, color2, color1);
  //topV
  tft.fillTriangle(70+offset_x, 72+offset_y, 77+offset_x, 87+offset_y, 82+offset_x, 87+offset_y, color1);  //  first
  tft.fillTriangle(73+offset_x, 69+offset_y, 70+offset_x, 72+offset_y, 82+offset_x, 87+offset_y, color1);  //  this part /*  \   */
  tft.fillTriangle(86+offset_x, 69+offset_y, 77+offset_x, 87+offset_y, 82+offset_x, 87+offset_y, color1);  //  this one /
  tft.fillTriangle(90+offset_x, 72+offset_y, 86+offset_x, 69+offset_y, 82+offset_x, 87+offset_y, color1);  //  last
  //bottomW
  tft.fillTriangle(62+offset_x, 78+offset_y, 66+offset_x, 78+offset_y, 69+offset_x, 104+offset_y, color1);
  tft.fillTriangle(69+offset_x, 104+offset_y, 66+offset_x, 75+offset_y, 76+offset_x, 106+offset_y, color1);
  tft.fillTriangle(70+offset_x, 107+offset_y, 77+offset_x, 90+offset_y, 82+offset_x, 90+offset_y, color1);
  tft.fillTriangle(74+offset_x, 108+offset_y, 70+offset_x, 107+offset_y, 82+offset_x, 90+offset_y, color1);
  tft.fillTriangle(90+offset_x, 107+offset_y, 77+offset_x, 90+offset_y, 82+offset_x, 90+offset_y, color1);
  tft.fillTriangle(90+offset_x, 106+offset_y, 85+offset_x, 107+offset_y, 79+offset_x, 93+offset_y, color1);
  tft.fillTriangle(83+offset_x, 108+offset_y, 94+offset_x, 75+offset_y, 98+offset_x, 81+offset_y, color1);
  tft.fillTriangle(86+offset_x, 106+offset_y, 91+offset_x, 107+offset_y, 97+offset_x, 76+offset_y, color1);
  }

void drawBot(bool activated){
  if (current_screen == 0) { // speed screen
    if(activated){
      drawSensorMenu(sensor_item);
      }
    else {drawScreeen0(SCREEN_BIG);}
    }
  else if (current_screen == 1) { //4Sensors menu
    if(activated){
      drawSensorMenu(sensor_item);
      }
    else {drawScreeen1(selected_item);}
    }
  else if (current_screen == 2) { //7Sensors menu
    if(activated){
    drawSensorMenu(sensor_item);
    }
    else {drawScreeen2(selected_item);}
    }
  else if (current_screen == 3) { // options menu
    if(activated){
      clearBot();
      Serial.print("menu selection: ");
      Serial.println(selected_item);
      drawMenuItems(selected_item);
      select_state = true;
      activated_state = false;
      }
    else {
      drawScreeen3(select_state, selected_item);}
      } 
  }

void readSensors(){
  SENSOR_VALUES[0] = random(850, 870);      //RPM
  SENSOR_VALUES[1] = random(25, 30);        //IAT
  SENSOR_VALUES[2] = random(50, 60);        //TPS
  SENSOR_VALUES[3] = random(85, 87);        //CLT
  SENSOR_VALUES[4] = random(850, 870);      //EGT
  SENSOR_VALUES[5] = random(1300, 1310);    //MAP
  SENSOR_VALUES[6] = random(380, 390);      //MAF
  if (speedDIR == 0){
    SENSOR_VALUES[7]++;
    if (SENSOR_VALUES[7]>=200){
      speedDIR = 1;
      }
    }
    else {
      SENSOR_VALUES[7]--;
      if (SENSOR_VALUES[7]<=0){
        speedDIR = 0;
        }
      }
  //SENSOR_VALUES[7] = random(380, 390);      //SPD
  }


void drawScreeen0(int item){
  tft.setTextColor(TFT_WHITE, TFT_BLACK);
  tft.setCursor(110+offset_x, 100+offset_y);
  tft.setTextSize(1);
  tft.print(SENSOR_UNITS[item]);
  tft.setCursor(35+offset_x, 75+offset_y);
  tft.setTextSize(4);
    if (SENSOR_VALUES[item] < 10) {
    tft.print("  ");     //add 2 spaces
    tft.print(SENSOR_VALUES[item]);
  }
  else if (SENSOR_VALUES[item] < 100){
    tft.print(" ");     //add 1 space
    tft.print(SENSOR_VALUES[item]);
  }
  else {tft.print(SENSOR_VALUES[item]);}
  }

void drawScreeen1(int item){
  tft.drawLine(80+offset_x, 60+offset_y, 80+offset_x, 118+offset_y, TFT_RED);
  tft.drawLine(7+offset_x, 89+offset_y, 153+offset_x, 89+offset_y, TFT_RED);
  tft.setTextColor(TFT_WHITE, TFT_BLACK);
  tft.setTextDatum(MR_DATUM);  //middle right text aligment on point
  for(int i=0; i<4; i++){
    if(i == item){                                     //check for selected item and change color for it
      tft.setTextColor(TFT_RED, TFT_BLACK);
      }
    else{
      tft.setTextColor(TFT_WHITE, TFT_BLACK);
      }
    tft.setTextSize(1);
    tft.drawString(SENSOR_NAMES[SCREEN_SENSOR4_SELECTION[i]], sens4_xy[i][0]+offset_x, sens4_xy[i][1]+offset_y-14);    
    tft.setTextSize(2);
    tft.drawNumber(SENSOR_VALUES[SCREEN_SENSOR4_SELECTION[i]], sens4_xy[i][0]+offset_x, sens4_xy[i][1]+offset_y);
    }
  }
void drawScreeen2(int item){
  tft.setTextSize(1);
  tft.setTextDatum(ML_DATUM);  //middle left text aligment on point
  tft.setTextColor(TFT_WHITE, TFT_BLACK);
    for(int i=0; i<7; i++){
    if(i == item){
      tft.setTextColor(TFT_RED, TFT_BLACK);
    }
    else{
      tft.setTextColor(TFT_WHITE, TFT_BLACK);
    }
    tft.drawString(SENSOR_NAMES[SCREEN_SENSOR7_SELECTION[i]], 14+offset_x, 66+offset_y+(i*8));  //font size is 7pixels so +8
    tft.drawNumber(SENSOR_VALUES[SCREEN_SENSOR7_SELECTION[i]], 65+offset_x, 66+offset_y+(i*8)); //font size is 7pixels so +8
    }
  }



void drawScreeen3(bool activated, int item){
  tft.setTextSize(2);
  tft.setTextDatum(ML_DATUM);  //middle left text aligment on point
  tft.setTextColor(TFT_WHITE, TFT_BLACK);
  int previous = item-1;
  if (previous < 0) {previous = MENU_ITEMS_NUMBER;} //previous item would be below first = make it the last
  int next = item+1;
  if (next > MENU_ITEMS_NUMBER) {next = 0;} // next item would be after last = make it the first
  
  if(activated){
    tft.setTextColor(TFT_WHITE, TFT_BLACK);
    tft.drawString(MENU_NAMES[previous], 14+offset_x, 73+offset_y);
    tft.setTextColor(TFT_RED, TFT_BLACK);
    tft.drawString(MENU_NAMES[item], 14+offset_x, 73+offset_y+18);
    tft.setTextColor(TFT_WHITE, TFT_BLACK);
    tft.drawString(MENU_NAMES[next], 14+offset_x, 73+offset_y+36);
    }
  else{
    tft.setTextColor(TFT_WHITE, TFT_BLACK);
    tft.drawString(MENU_NAMES[MENU_ITEMS_NUMBER], 14+offset_x, 73+offset_y);
    tft.drawString(MENU_NAMES[0], 14+offset_x, 73+offset_y+18);
    tft.drawString(MENU_NAMES[1], 14+offset_x, 73+offset_y+36);
    }
  }
void drawSensorMenu(int item){
  tft.setTextSize(2);
  tft.setTextDatum(ML_DATUM);  //middle left text aligment on point

  int previous = item-1;
  if (previous < 0) {previous = SENSOR_NUMBER;} //previous item would be below first = make it the last
  int next = item+1;
  if (next > SENSOR_NUMBER) {next = 0;} // next item would be after last = make it the first
  
  tft.setTextColor(TFT_WHITE, TFT_BLACK);
  tft.drawString(SENSOR_NAMES[previous], 14+offset_x, 73+offset_y);
  tft.setTextColor(TFT_RED, TFT_BLACK);
  tft.drawString(SENSOR_NAMES[item], 14+offset_x, 73+offset_y+18);
  tft.setTextColor(TFT_WHITE, TFT_BLACK);
  tft.drawString(SENSOR_NAMES[next], 14+offset_x, 73+offset_y+36);
  }

void assignSensorItem(){

  if(current_screen == 0){SCREEN_BIG = sensor_item;}            //main big
  if(current_screen == 1){
    SCREEN_SENSOR4_SELECTION[selected_item] = sensor_item;}     //4sensor
  if(current_screen == 2){
    SCREEN_SENSOR7_SELECTION[selected_item] = sensor_item;}     //7sensor
  }
void drawMenuItems(int item){
  switch (item){
    case 0:
      Serial.println("Diag can");
      break;
    case 1:
      Serial.println("Diag K-line");
      break;
    case 2:
      Serial.println("Brightness");
      while(1){
        tft.setTextDatum(MC_DATUM);
        tft.setTextColor(TFT_WHITE, TFT_BLACK);
        tft.drawString("Brightness", 80+offset_x, 73+offset_y);
        tft.drawNumber(brightness, 80+offset_x, 105+offset_y);
        btnBACK.read();
          if(btnBACK.wasPressed()) {clearBot();break;} 
        btnENTER.read();
          if(btnENTER.wasPressed()){clearBot();break;} 
        btnUP.read();
          if(btnUP.wasPressed()){
            brightness++;
            if(brightness>9){brightness=9;}
            } 
        btnDOWN.read();
          if(btnDOWN.wasPressed()){
            brightness--;
            if(brightness<1){brightness=1;}
            }   
        }
      break;
    case 3:
      Serial.println("Time");
      while(1){
        static bool set_time = false;
        static int time_selection = 0;
        tft.setTextDatum(MC_DATUM);
        tft.setTextColor(TFT_WHITE, TFT_BLACK);
        tft.drawString("Time", 80+offset_x, 73+offset_y);
        
        tft.drawString(rtc.getTime("-"), 74+offset_x, 90+offset_y);   // first  - for date
        tft.drawString(rtc.getTime("-"), 110+offset_x, 90+offset_y);  // second - for date
        tft.drawString(rtc.getTime(":"), 62+offset_x, 110+offset_y);  // first  : for time
        tft.drawString(rtc.getTime(":"), 98+offset_x, 110+offset_y);  // second : for time
        
        if(set_time && time_selection == 0){
          tft.setTextColor(TFT_RED, TFT_BLACK);
          tft.drawString(rtc.getTime("%G"), 44+offset_x, 90+offset_y);  //year
          }
        else {
          tft.setTextColor(TFT_WHITE, TFT_BLACK);
          tft.drawString(rtc.getTime("%G"), 44+offset_x, 90+offset_y);  //year
          }
        if(set_time && time_selection == 1){
          tft.setTextColor(TFT_RED, TFT_BLACK);
          tft.drawString(rtc.getTime("%m"), 92+offset_x, 90+offset_y);  //month
          }
        else {
          tft.setTextColor(TFT_WHITE, TFT_BLACK);
          tft.drawString(rtc.getTime("%m"), 92+offset_x, 90+offset_y);  //month
          }
        if(set_time && time_selection == 2){
          tft.setTextColor(TFT_RED, TFT_BLACK);
          tft.drawString(rtc.getTime("%d"),  128+offset_x, 90+offset_y); //day
          }
        else {
          tft.setTextColor(TFT_WHITE, TFT_BLACK);
          tft.drawString(rtc.getTime("%d"), 128+offset_x, 90+offset_y); //day
          }
        if(set_time && time_selection == 3){
          tft.setTextColor(TFT_RED, TFT_BLACK);
          tft.drawString(rtc.getTime("%H"), 44+offset_x, 110+offset_y);  //hour
          }
        else {
          tft.setTextColor(TFT_WHITE, TFT_BLACK);
          tft.drawString(rtc.getTime("%H"), 44+offset_x, 110+offset_y);  //hour
          }
        if(set_time && time_selection == 4){
          tft.setTextColor(TFT_RED, TFT_BLACK);
          tft.drawString(rtc.getTime("%M"), 80+offset_x, 110+offset_y);  //minutes
          }
        else {
          tft.setTextColor(TFT_WHITE, TFT_BLACK);
          tft.drawString(rtc.getTime("%M"), 80+offset_x, 110+offset_y);  //minutes
          }
        if(set_time && time_selection == 5){
          tft.setTextColor(TFT_RED, TFT_BLACK);
          tft.drawString(rtc.getTime("%S"),  116+offset_x, 110+offset_y); //seconds
          }
        else {
          tft.setTextColor(TFT_WHITE, TFT_BLACK);
          tft.drawString(rtc.getTime("%S"),  116+offset_x, 110+offset_y); //seconds
          }
   
        Serial.print("set_time: ");
        Serial.print(set_time);
        Serial.print(" selection: ");
        Serial.println(time_selection);
        btnBACK.read();
          if(btnBACK.wasPressed()) {
            if(set_time){
              time_selection--;
              if(time_selection<0){
                set_time = false;
                time_selection=0;
                }
              }
            else {clearBot();break;}
            } 
        btnENTER.read();
          if(btnENTER.wasPressed()){
            if(set_time){
              time_selection++;
              }
            else {set_time = true;}
            if(time_selection>5){
              set_time = false;
              time_selection=0;}
            }
        btnUP.read();
          if(btnUP.wasPressed()){
            if(set_time){
              switch(time_selection){
                case 0://year
                  rtc.setTime(rtc.getSecond(), rtc.getMinute(), rtc.getHour(true), rtc.getDay(), rtc.getMonth()+1, rtc.getYear()+1);
                  break;
                case 1://month
                  rtc.setTime(rtc.getSecond(), rtc.getMinute(), rtc.getHour(true), rtc.getDay(), rtc.getMonth()+2, rtc.getYear());
                  break;
                case 2://day
                  rtc.setTime(rtc.getSecond(), rtc.getMinute(), rtc.getHour(true), rtc.getDay()+1, rtc.getMonth()+1, rtc.getYear());
                  break;
                case 3://hour
                  rtc.setTime(rtc.getSecond(), rtc.getMinute(), rtc.getHour(true)+1, rtc.getDay(), rtc.getMonth()+1, rtc.getYear());
                  break;
                case 4://minute
                  rtc.setTime(rtc.getSecond(), rtc.getMinute()+1, rtc.getHour(true), rtc.getDay(), rtc.getMonth()+1, rtc.getYear());
                  break;
                case 5://second
                  rtc.setTime(rtc.getSecond()+1, rtc.getMinute(), rtc.getHour(true), rtc.getDay(), rtc.getMonth()+1, rtc.getYear());
                  break;
                }
              }
            } 
        btnDOWN.read();
          if(btnDOWN.wasPressed()){
            if(set_time){
              switch(time_selection){
                case 0://year
                  rtc.setTime(rtc.getSecond(), rtc.getMinute(), rtc.getHour(true), rtc.getDay(), rtc.getMonth()+1, rtc.getYear()-1);
                  break;
                case 1://month
                  rtc.setTime(rtc.getSecond(), rtc.getMinute(), rtc.getHour(true), rtc.getDay(), rtc.getMonth(), rtc.getYear());
                  break;
                case 2://day
                  rtc.setTime(rtc.getSecond(), rtc.getMinute(), rtc.getHour(true), rtc.getDay()-1, rtc.getMonth()+1, rtc.getYear());
                  break;
                case 3://hour
                  rtc.setTime(rtc.getSecond(), rtc.getMinute(), rtc.getHour(true)-1, rtc.getDay(), rtc.getMonth()+1, rtc.getYear());
                  break;
                case 4://minute
                  rtc.setTime(rtc.getSecond(), rtc.getMinute()-1, rtc.getHour(true), rtc.getDay(), rtc.getMonth()+1, rtc.getYear());
                  break;
                case 5://second
                  rtc.setTime(rtc.getSecond()-1, rtc.getMinute(), rtc.getHour(true), rtc.getDay(), rtc.getMonth()+1, rtc.getYear());
                  break;
                }
              }
            }   
        }
      break;
    case 4:
      Serial.println("FW Update");
      break;           
    }
  }