#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include <Adafruit_FT6206.h>

// Pin definitions for the TFT display
#define TFT_CS 10
#define TFT_RST 8
#define TFT_DC 9

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);

// Touch screen pins
Adafruit_FT6206 ts = Adafruit_FT6206();

// Buttons
Adafruit_GFX_Button autoModeBtn, manualModeBtn;
Adafruit_GFX_Button prevBtn, nextBtn;
Adafruit_GFX_Button startBtn, mainMenuBtn;
Adafruit_GFX_Button EnBtn, FrBtn;
Adafruit_GFX_Button MTBtn, STBtn;

// Frequencies and timer values
int freq1 = 10;
int freq2 = 10;
int freq3 = 10;
int timerDuration = 30;  // in seconds

// Positions for slider labels
const int labelX = 250;
const int labelY1 = 50;
const int labelY2 = 90;
const int labelY3 = 130;
const int labelY4 = 170;

 int minF = 1;    // Minimum frequency
 int maxF = 100;  // Maximum frequency
const int minT = 1;    // Minimum time
const int maxT = 60;  // Maximum time

int tonePin = 6;
bool startFlag = false;

String screen = "select_lang";
String mode = "select_lang";
String lang = "";
String mt_st = "";

const char* diseasesEN[] = { "Wrist", "Elbout", "Shoulder", "Cervical Vertebra", "Lumbar Vertebra", "Groin", "Hip", "Thigh", "Knee", "Foot/Ankle" };

const char* diseasesFR[] = { "Poignet", "Coude", "Épaule", "Vertèbre cervicale", "Vertèbre lombaire", "Aine", "Hanche", "Cuisse", "Genou", "Pied/Cheville" };

const int frequenciesMT[][3] = {
  { 7, 25, 10 },     // Frequencies for Wrist
  { 7, 25, 10 },     // Frequencies for Elbout
  { 7, 25, 10 },     // Frequencies for Shoulder
  { 7, 25, 10 },  // Frequencies for Cervical Vertebra
  { 7, 25, 10 },  // Frequencies for Lumbar Vertebra
  { 7, 25, 10 },   // Frequencies for Groin
  { 25, 45, 15 },     // Frequencies for Hip
  { 7, 25, 10 },     // Frequencies for Thigh
  { 7, 25, 10 },     // Frequencies for Knee
  { 7, 25, 10 }  // Frequencies for Foot/Ankle
};

const int frequenciesST[][3] = {
  { 1000, 3000, 2000 },     // Frequencies for Wrist
  { 1000, 3000, 2000 },     // Frequencies for Elbout
  { 1000, 3000, 2000 },     // Frequencies for Shoulder
  { 1000, 3000, 2000 },  // Frequencies for Cervical Vertebra
  { 1000, 3000, 2000 },  // Frequencies for Lumbar Vertebra
  { 1000, 3000, 2000 },   // Frequencies for Groin
  { 1000, 3000, 2000 },     // Frequencies for Hip
  { 1000, 3000, 2000 },     // Frequencies for Thigh
  { 1000, 3000, 2000 },     // Frequencies for Knee
  { 1000, 3000, 2000 }  // Frequencies for Foot/Ankle
};

const int timers[] = { 15, 15, 20 , 20, 20, 15, 20, 20, 20, 15};  // Timers in minutes for auto mode

int NumDiseases = 10;

int currentDiseaseIndex = 0;

unsigned long lastDebounceTime = 0;
const unsigned long debounceDelay = 50;  // milliseconds

void setup() {
  Serial.begin(9600);
  tft.begin();
  tft.setRotation(3);
  tft.fillScreen(ILI9341_WHITE);  // Set background to white
  ts.begin();
  displaySelectLang();
}
void loop() {
  if (ts.touched()) {
    TS_Point p = ts.getPoint();
    handleTouch(320 - p.y, p.x);
  }
}
bool debounce() {
  if ((millis() - lastDebounceTime) > debounceDelay) {
    lastDebounceTime = millis();
    return true;
  }
  return false;
}
void displaySelectLang() {
  tft.fillScreen(ILI9341_WHITE);
  tft.setTextColor(ILI9341_BLACK);
  tft.setTextSize(2);
  tft.setCursor(20, 20);
  tft.print("Select Language:");
  tft.setCursor(20, 50);
  tft.print("Choisir la langue:");

  EnBtn.initButton(&tft, 160, 140, 150, 40, ILI9341_BLACK, ILI9341_BLUE, ILI9341_WHITE, "English", 2);
  FrBtn.initButton(&tft, 160, 200, 150, 40, ILI9341_BLACK, ILI9341_BLUE, ILI9341_WHITE, "French", 2);

  EnBtn.drawButton(false);
  FrBtn.drawButton(false);

  Serial.println("Language Selection Displayed");
}
void displaySelectMT_ST() {
  tft.fillScreen(ILI9341_WHITE);

  MTBtn.initButton(&tft, 160, 140, 150, 40, ILI9341_BLACK, ILI9341_BLUE, ILI9341_WHITE, "MT Mode", 2);
  STBtn.initButton(&tft, 160, 200, 150, 40, ILI9341_BLACK, ILI9341_BLUE, ILI9341_WHITE, "ST Mode", 2);

  MTBtn.drawButton(false);
  STBtn.drawButton(false);

  Serial.println("MT_ST Selection Displayed");
}
void displayMainMenu() {
  tft.fillScreen(ILI9341_WHITE);
  tft.setTextColor(ILI9341_BLACK);
  tft.setTextSize(2);
  tft.setCursor(60, 60);
  tft.print(getStr(lang, "Sélectionnez le Mode", "Select Mode"));

  autoModeBtn.initButton(&tft, 160, 140, 150, 40, ILI9341_BLACK, ILI9341_BLUE, ILI9341_WHITE, getStr(lang, "Automatique", "Auto"), 2);
  manualModeBtn.initButton(&tft, 160, 200, 150, 40, ILI9341_BLACK, ILI9341_BLUE, ILI9341_WHITE, getStr(lang, "Manuel", "Manual"), 2);

  autoModeBtn.drawButton(false);
  manualModeBtn.drawButton(false);

  Serial.println("Main Menu Displayed");
}
void displayAutoMode() {
  tft.fillScreen(ILI9341_WHITE);
  tft.setTextColor(ILI9341_BLACK);
  tft.setTextSize(2);
  tft.setCursor(10, 10);
  tft.print(getStr(lang, "Mode Automatique:", "Auto Mode:"));

  prevBtn.initButton(&tft, 37, 223, 70, 30, ILI9341_BLACK, ILI9341_BLUE, ILI9341_WHITE, "<<", 2);
  nextBtn.initButton(&tft, 283, 223, 70, 30, ILI9341_BLACK, ILI9341_BLUE, ILI9341_WHITE, ">>", 2);
  mainMenuBtn.initButton(&tft, 303, 15, 30, 30, ILI9341_BLACK, ILI9341_RED, ILI9341_WHITE, "X", 3);
  startBtn.initButton(&tft, 160, 218, 120, 40, ILI9341_BLACK, ILI9341_GREEN, ILI9341_WHITE, getStr(lang, "Commencer:", "Start"), 2);

  prevBtn.drawButton(false);
  nextBtn.drawButton(false);
  mainMenuBtn.drawButton(false);
  startBtn.drawButton(false);
  SetConfig();
  Serial.println("Auto Mode Displayed");
}
void displayManualMode() {
  tft.fillScreen(ILI9341_WHITE);
  tft.setTextColor(ILI9341_BLACK);
  tft.setTextSize(2);
  tft.setCursor(10, 10);
  tft.print(getStr(lang, "Mode Manuel:", "Manual Mode:"));
  // Draw sliders
  drawSlider(20, 40, 220, 30, freq1, minF, maxF);
  drawSlider(20, 80, 220, 30, freq2, minF, maxF);
  drawSlider(20, 120, 220, 30, freq3, minF, maxF);
  drawSlider(20, 160, 220, 30, timerDuration, minT, maxT);
  mainMenuBtn.initButton(&tft, 303, 15, 30, 30, ILI9341_BLACK, ILI9341_RED, ILI9341_WHITE, "X", 3);
  startBtn.initButton(&tft, 160, 218, 120, 40, ILI9341_BLACK, ILI9341_GREEN, ILI9341_WHITE, getStr(lang, "Commencer:", "Start"), 2);
  mainMenuBtn.drawButton(false);
  startBtn.drawButton(false);
  Serial.println("Manual Mode Displayed");
}
void displayGenerate() {
  tft.fillScreen(ILI9341_WHITE);
  tft.setTextColor(ILI9341_BLACK);
  tft.setTextSize(3);
  tft.setCursor(10, 10);
  tft.print(getStr(lang, "Fonctionnement...", "Working..."));
  mainMenuBtn.initButton(&tft, 303, 15, 30, 30, ILI9341_BLACK, ILI9341_RED, ILI9341_WHITE, "X", 3);
  mainMenuBtn.drawButton(false);
  Serial.println("Generating Displayed");
}
void handleTouch(int x, int y) {
  if (!debounce()) return;
  
  if (screen == "select_lang") {
    if (FrBtn.contains(x, y)) {
      FrBtn.press(true);
    } else if (EnBtn.contains(x, y)) {
      EnBtn.press(true);
    } else {
      FrBtn.press(false);
      EnBtn.press(false);
    }

    if (FrBtn.justPressed()) {
      lang = "fr";
      Serial.println("French Selected");
      screen = "select_mt_st";
      displaySelectMT_ST();
      x = 0; y = 0;
    } else if (EnBtn.justPressed()) {
      lang = "en";
      Serial.println("English Selected");
      screen = "select_mt_st";
      displaySelectMT_ST();
      x = 0; y = 0;
    }
  }
  if (screen == "select_mt_st") {
    if (MTBtn.contains(x, y)) {
      MTBtn.press(true);
    } else if (STBtn.contains(x, y)) {
      STBtn.press(true);
    } else {
      MTBtn.press(false);
      STBtn.press(false);
    }

    if (MTBtn.justPressed()) {
      mt_st = "MT";
      minF = 1;    // Minimum frequency
      maxF = 100;  // Maximum frequency
      freq1 = 10;
      freq2 = 10;
      freq3 = 10;
      Serial.println("MT Selected");
      screen = "mode_select";
      displayMainMenu();
      x = 0; y = 0;
    } else if (STBtn.justPressed()) {
      mt_st = "ST";
      minF = 1000;    // Minimum frequency
      maxF = 3000;  // Maximum frequency
      freq1 = 1000;
      freq2 = 1000;
      freq3 = 1000;
      Serial.println("ST Selected");
      screen = "mode_select";
      displayMainMenu();
      x = 0; y = 0;
    }
  }
  if (screen == "mode_select") {
    if (autoModeBtn.contains(x, y)) {
      autoModeBtn.press(true);
    } else if (manualModeBtn.contains(x, y)) {
      manualModeBtn.press(true);
    } else {
      autoModeBtn.press(false);
      manualModeBtn.press(false);
    }

    if (autoModeBtn.justPressed()) {
      mode = "auto";
      screen = "auto_mode";
      Serial.println("Auto Mode Selected");
      displayAutoMode();
      x = 0; y = 0;
    } else if (manualModeBtn.justPressed()) {
      mode = "manual";
      screen = "manual_mode";
      Serial.println("Manual Mode Selected");
      displayManualMode();
      x = 0; y = 0;
    }
  }
  if (screen == "auto_mode") {
    BackToMainMenu(x, y);

    if (prevBtn.contains(x, y)) {
      prevBtn.press(true);
    } else if (nextBtn.contains(x, y)) {
      nextBtn.press(true);
    } else if (startBtn.contains(x, y)) {
      startBtn.press(true);
    } else {
      prevBtn.press(false);
      nextBtn.press(false);
      startBtn.press(false);
    }

    if (prevBtn.justPressed()) {
      prevBtn.press(false);
      Serial.println("<<");
      if (currentDiseaseIndex > 0){
      currentDiseaseIndex--;
      SetConfig();
      }
      Serial.println(currentDiseaseIndex);
      x = 0; y = 0;
    } else if (nextBtn.justPressed()) {
      nextBtn.press(false);
      Serial.println(">>");
      if (currentDiseaseIndex < NumDiseases - 1){
      currentDiseaseIndex++;
      SetConfig();
      }
      Serial.println(currentDiseaseIndex);
      x = 0; y = 0;
    } else if (startBtn.justPressed()) {
      startBtn.press(false);
      Serial.println("Start Generating...");
      screen = "generating";
      displayGenerate();
      x = 0; y = 0;
    }
  }
  if (screen == "manual_mode") {
    BackToMainMenu(x, y);

    if (startBtn.contains(x, y)) {
      startBtn.press(true);
    } else {
      startBtn.press(false);
    }
    if (startBtn.justPressed()) {
      startBtn.press(false);
      Serial.println("Start Generating...");
      screen = "generating";
      displayGenerate();
      x = 0; y = 0;
    }

    // Handle slider movement
    handleSliderTouch(x, y);
  }
  if (screen == "generating") {
    generateFrequencies();
  }
}
void drawSlider(int x, int y, int w, int h, int value, int minValue, int maxValue) {
  int knobX = map(value, minValue, maxValue, x, x + w);
  tft.fillRect(x, y, w, h, ILI9341_LIGHTGREY);
  drawSliderKnob(knobX, y + h / 2, ILI9341_BLUE);
  updateSliderLabels(freq1, freq2, freq3, timerDuration);
}
void clearSlider(int x, int y, int w, int h) {
  tft.fillRect(x, y, w, h, ILI9341_WHITE);
}
void drawSliderKnob(int x, int y, uint16_t color) {
  tft.fillRect(x - 5, y - 10, 10, 20, color);
}
void handleSliderTouch(int x, int y) {
  // Define the positions and dimensions of the sliders
  const int sliderX = 20;
  const int sliderWidth = 220;

  // Only process if x is within the slider range
  if (x >= sliderX && x <= sliderX + sliderWidth) {
    if (y > 40 && y < 70) {  // First slider (freq1)
      freq1 = map(x, sliderX, sliderX + sliderWidth, minF, maxF);
      clearSlider(sliderX, 40, sliderWidth, 30);
      drawSlider(sliderX, 40, sliderWidth, 30, freq1, minF, maxF);

      Serial.print("Frequency 1: ");
      Serial.println(freq1);
    } else if (y > 80 && y < 110) {  // Second slider (freq2)
      freq2 = map(x, sliderX, sliderX + sliderWidth, minF, maxF);
      clearSlider(sliderX, 80, sliderWidth, 30);
      drawSlider(sliderX, 80, sliderWidth, 30, freq2, minF, maxF);
      
      Serial.print("Frequency 2: ");
      Serial.println(freq2);
    } else if (y > 120 && y < 150) {  // Third slider (freq3)
      freq3 = map(x, sliderX, sliderX + sliderWidth, minF, maxF);
      clearSlider(sliderX, 120, sliderWidth, 30);
      drawSlider(sliderX, 120, sliderWidth, 30, freq3, minF, maxF);

      Serial.print("Frequency 3: ");
      Serial.println(freq3);
    } else if (y > 160 && y < 190) {  // Fourth slider (timerDuration)
      timerDuration = map(x, sliderX, sliderX + sliderWidth, minT, maxT);
      clearSlider(sliderX, 160, sliderWidth, 30);
      drawSlider(sliderX, 160, sliderWidth, 30, timerDuration, minT, maxT);

      Serial.print("Timer Duration: ");
      Serial.println(timerDuration);
    }
  }
}
// Function to update slider labels with units (Hz for frequencies, min for timer)
void updateSliderLabels(int freq1, int freq2, int freq3, int timerDuration) {
  tft.setTextColor(ILI9341_BLACK);
  tft.setTextSize(1);

  // Clear previous labels
  tft.fillRect(labelX, labelY1 - 10, 90, 20, ILI9341_WHITE);
  tft.fillRect(labelX, labelY2 - 10, 90, 20, ILI9341_WHITE);
  tft.fillRect(labelX, labelY3 - 10, 90, 20, ILI9341_WHITE);
  tft.fillRect(labelX, labelY4 - 10, 90, 20, ILI9341_WHITE);

  // Draw updated labels with units
  tft.setCursor(labelX, labelY1);
  tft.print("F1:");
  tft.print(freq1);
  tft.print(" Hz");

  tft.setCursor(labelX, labelY2);
  tft.print("F2:");
  tft.print(freq2);
  tft.print(" Hz");

  tft.setCursor(labelX, labelY3);
  tft.print("F3:");
  tft.print(freq3);
  tft.print(" Hz");

  tft.setCursor(labelX, labelY4);
  tft.print("T:");
  tft.print(timerDuration);
  tft.print(" min");
}
char* getStr(String language, char* FR, char* EN) {
    if (language == "en") {
        return EN;
    } else if (language == "fr") {
        return FR;
    }
}
void(* resetFunc) (void) = 0; // Declare reset function at address 0
void BackToMainMenu(int x, int y) {
  if (mainMenuBtn.contains(x, y)) {
    mainMenuBtn.press(true);
  } else {
    mainMenuBtn.press(false);
  }
  if (mainMenuBtn.justPressed()) {
    resetFunc();
  }
}
void DiseaseLabel(char* ch){
  tft.fillRect(0, 100, 320, 50, ILI9341_WHITE);
  tft.setTextColor(ILI9341_BLACK);
  tft.setTextSize(2);
  tft.setCursor(10, 100);
  tft.print(ch);
}
void SetConfig(){
      DiseaseLabel(getStr(lang,diseasesFR[currentDiseaseIndex],diseasesEN[currentDiseaseIndex]));
      timerDuration = timers[currentDiseaseIndex];
      if(mt_st == "MT"){
      freq1 = frequenciesMT[currentDiseaseIndex][0];
      freq2 = frequenciesMT[currentDiseaseIndex][1];
      freq3 = frequenciesMT[currentDiseaseIndex][2];
      } else if(mt_st == "ST"){
      freq1 = frequenciesST[currentDiseaseIndex][0];
      freq2 = frequenciesST[currentDiseaseIndex][1];
      freq3 = frequenciesST[currentDiseaseIndex][2];
      }
}

void generateFrequencies() {
  unsigned long startTime = millis();
  unsigned long endTime = startTime + timerDuration * 60000;
  unsigned long interval = 12000; // 12 seconds
  unsigned long lastChange = startTime;

  int currentFreq = freq1;

  while (millis() < endTime) {
    if (ts.touched()) {
      TS_Point p = ts.getPoint();
      BackToMainMenu(320 - p.y, p.x);
    }
    updateTimeDisplay(endTime - millis());
    
    if (millis() - lastChange >= interval) {
      if (currentFreq == freq1) {
        currentFreq = freq2;
      } else if (currentFreq == freq2) {
        currentFreq = freq3;
      } else {
        currentFreq = freq1;
      }
      lastChange = millis();
    }

    tone(tonePin, currentFreq);
    delay(100); // Keep the loop responsive
  }
  noTone(tonePin);
  resetFunc();
}
void updateTimeDisplay(unsigned long timeRemaining) {
  int minutes = timeRemaining / 60000;
  int seconds = (timeRemaining % 60000) / 1000;

  tft.fillRect(20, 140, 300, 20, ILI9341_WHITE);  // Clear previous text
  tft.setCursor(20, 140);
  tft.setTextColor(ILI9341_BLACK); // Set text color
  tft.setTextSize(2); // Set text size
  tft.print(getStr(lang, "Temps restant: ", "Remaining time: "));
  tft.print(minutes);
  tft.print(":");
  if (seconds < 10) tft.print("0");
  tft.print(seconds);
}