int RedLED = 8;
int BlueLED = 9;
int dotPin = 11;
int dashPin = 10;
int buzzPin = 7;

int ditLength;
int dahLength;
int spaceLength;
int toneVal = 1;

String input_string = "";
String morseInput = "";
String message = "";

int letterGap = 500;
int wordGap = 1000;
long lastInputTime = 0;

void setSpeed(char);
void translateLetter(char);
void buzzerSound(int);
char translateCode(String);


void setup() {
  Serial.begin(9600);
  pinMode(dotPin, INPUT_PULLUP);
  pinMode(dashPin, INPUT_PULLUP);
  pinMode(RedLED, OUTPUT);
  pinMode(BlueLED, OUTPUT);
  pinMode(buzzPin, OUTPUT);
}

void loop() {
  while (true) {
    Serial.println("Choose a mode: ");
    char mode_choice = getMenuChoice();
    Serial.println(mode_choice);

    if (mode_choice == 'A') {
      while (true) {
        MorseCodeGeneration();
        if (Serial.available() > 0 && Serial.read() == 'Q') {
          // Press 'Q' to exit the loop
          break;
        }
      }
    } 
    else if (mode_choice == 'B') {
      while (true) {
        MorseCodeTranslation();
        if (Serial.available() > 0 && Serial.read() == 'Q') {
          // Press 'Q' to exit the loop
          break;
        }
      }
    }
  }
}

char getMenuChoice() {
  Serial.println("A. Morse Code Generation  B. Morse Code Translation");
  while (Serial.available() == 0) {
  }
  char choice = Serial.read();
  return choice;
}

void MorseCodeGeneration() {
  setSpeed('C');

  Serial.println("Enter a Word or Phrase: ");
  while (Serial.available() == 0) {
  }

  input_string = Serial.readString();
  int str_len = input_string.length() + 1;

  char buf[30];
  input_string.toCharArray(buf, str_len);
  Serial.println(buf);

  for (int x = 0; x < str_len - 1; x++) {
    char letter = tolower(buf[x]);
    Serial.println(letter);
    translateLetter(letter);

    delay(800);
  }
}

void MorseCodeTranslation() {
  ditLength=40;
  dahLength=120;
  int dotButtonState, dashButtonState;
  long currentTime = millis();

  dotButtonState = digitalRead(dotPin);
  dashButtonState = digitalRead(dashPin);

  if (dotButtonState == LOW || dashButtonState == LOW) {
    if (currentTime - lastInputTime > wordGap) {
      message += " ";
    }
    lastInputTime = currentTime;

    if (dotButtonState == LOW) {
      digitalWrite(RedLED, HIGH);
      delay(ditLength);
      digitalWrite(RedLED, LOW);

      buzzerSound(ditLength);
      while (digitalRead(dotPin) == LOW) {
      }
      morseInput += ".";
    }

    if (dashButtonState == LOW) {
      digitalWrite(BlueLED, HIGH);
      delay(dahLength);
      digitalWrite(BlueLED, LOW);

      buzzerSound(dahLength);
      while (digitalRead(dashPin) == LOW) {
      }
      morseInput += "-";
    }
  }

  if (currentTime - lastInputTime > letterGap && morseInput != "") {
    char letter = translateCode(morseInput);
    message += letter;
    morseInput = "";
  }

  if (message != "") {
    Serial.print(message);
    message = "";
  }
}

void setSpeed(char c){
  switch(c){
    case 'A':
      ditLength=60;
      break;
    case 'B':
      ditLength=34;
      break;
    case 'C':
      ditLength=24;
      break;
  }
  dahLength=ditLength*3;
  spaceLength=ditLength*7;
}

void translateLetter(char l){
  switch(l){
        case 'a':
          ditSound(1);  //The dit sound last for a set number of milliseconds,
          dahSound(1);  //the dah sound lasts for 3 times as long as a dit
          break;        //LED blinks are of same duration and simultaneous as the dit and dah sounds
        case 'b':
          dahSound(1);
          ditSound(3);
          break;
        case 'c':
          dahSound(1);
          ditSound(1);
          dahSound(1);
          ditSound(1);
          break;
        case 'd':
          dahSound(1);
          ditSound(2);
          break;
        case 'e':
          ditSound(1);
          break;
        case 'f':
          ditSound(2);
          dahSound(1);
          ditSound(1);
          break;
        case 'g':
          dahSound(2);
          ditSound(1);
          break;
        case 'h':
          ditSound(4);
          break;
        case 'i':
          ditSound(2);
          break;
        case 'j':
          ditSound(1);
          dahSound(3);
          break;
        case 'k':
          dahSound(1);
          ditSound(1);
          dahSound(1);
          break;
        case 'l':
          ditSound(1);
          dahSound(1);
          ditSound(2);
          break;
        case 'm':
          dahSound(2);
          break;
        case 'n':
          dahSound(1);
          ditSound(1);
          break;
        case 'o':
          dahSound(3);
          break;
        case 'p':
          ditSound(1);
          dahSound(2);
          ditSound(1);
          break;
        case 'q':
          dahSound(2);
          ditSound(1);
          dahSound(1);
          break;
        case 'r':
          ditSound(1);
          dahSound(1);
          ditSound(1);
          break;
        case 's':
          ditSound(3);
          break;
        case 't':
          dahSound(1);
          break;
        case 'u':
          ditSound(2);
          dahSound(1);
          break;
        case 'v':
          ditSound(3);
          dahSound(1);
          break;
        case 'w':
          ditSound(1);
          dahSound(2);
          break;
        case 'x':
          dahSound(1);
          ditSound(2);
          dahSound(1);
          break;
        case 'y':
          dahSound(1);
          ditSound(1);
          dahSound(2);
          break;
        case 'z':
          dahSound(2);
          ditSound(2);
          break;
        case '1':
          ditSound(1);
          dahSound(4);
          break;
        case '2':
          ditSound(2);
          dahSound(3);
          break;
        case '3':
          ditSound(3);
          dahSound(2);
          break;
        case '4':
          ditSound(4);
          dahSound(1);
          break;
        case '5':
          ditSound(5);
          break;
        case '6':
          dahSound(1);
          ditSound(4);
          break;
        case '7':
          dahSound(2);
          ditSound(3);
          break;
        case '8':
          dahSound(3);
          ditSound(2);
          break;
        case '9':
          dahSound(4);
          ditSound(1);
          break;
        case '0':
          dahSound(5);
          break;
        case ' ':
          delay(spaceLength);
          break;
        default:
          Serial.println("Invalid Letter");
          break;
      }
}

void ditSound(int times){
  for(int k=0; k<times; k++){
    digitalWrite(RedLED,HIGH);
    delay(ditLength);
    for(int x=0; x<ditLength; x++){
      digitalWrite(buzzPin,HIGH);
      delay(toneVal);
      digitalWrite(buzzPin,LOW);
      delay(toneVal);
      }
    digitalWrite(RedLED,LOW);
  delay(dahLength);
  }
}

//a dah sound should be 3 times longer than the duration of a dit
void dahSound(int times){
  for(int k=0; k<times; k++){
    digitalWrite(BlueLED,HIGH);
    delay(dahLength);
    for(int x=0; x<dahLength; x++){
      digitalWrite(buzzPin,HIGH);
      delay(toneVal);
      digitalWrite(buzzPin,LOW);
      delay(toneVal);
      }
    digitalWrite(BlueLED,LOW);
  delay(dahLength);
  }
}

char translateCode(String code) {

  const char* morseCode[] = {
    ".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--",
    "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--..",
    "-----", ".----", "..---", "...--", "....-", ".....", "-....", "--...", "---..", "----.",
    ".-.-.-"};


  const char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.";

  for (int i = 0; i < 37; i++) { 
    if (code == morseCode[i]) {
      return alphabet[i];
    }
  }
}

void buzzerSound(int buzzT){
  for (int x=0; x<buzzT; x++){
    digitalWrite(buzzPin,HIGH);
    delay(toneVal);
    digitalWrite(buzzPin,LOW);
    delay(toneVal);
  }
}
