#include <WebUSB.h>
#include <DFMiniMp3.h>


class Mp3Notify
{
  public:
    static void PrintlnSourceAction(DfMp3_PlaySources source, const char* action)
    {
      if (source & DfMp3_PlaySources_Sd)
      {
        Serial.print("SD Card, ");
      }
      if (source & DfMp3_PlaySources_Usb)
      {
        Serial.print("USB Disk, ");
      }
      if (source & DfMp3_PlaySources_Flash)
      {
        Serial.print("Flash, ");
      }
      Serial.println(action);
    }
    static void OnError(uint16_t errorCode)
    {
      // see DfMp3_Error for code meaning
      Serial.println();
      Serial.print("Com Error ");
      Serial.println(errorCode);
    }
    static void OnPlayFinished(DfMp3_PlaySources source, uint16_t track)
    {
      Serial.print("Play finished for #");
      Serial.println(track);
    }
    static void OnPlaySourceOnline(DfMp3_PlaySources source)
    {
      PrintlnSourceAction(source, "online");
    }
    static void OnPlaySourceInserted(DfMp3_PlaySources source)
    {
      PrintlnSourceAction(source, "inserted");
    }
    static void OnPlaySourceRemoved(DfMp3_PlaySources source)
    {
      PrintlnSourceAction(source, "removed");
    }
};

/**
   Creating an instance of WebUSBSerial will add an additional USB interface to
   the device that is marked as vendor-specific (rather than USB CDC-ACM) and
   is therefore accessible to the browser.

   The URL here provides a hint to the browser about what page the user should
   navigate to to interact with the device.
*/
WebUSB WebUSBSerial(1 /* https:// */, "apollo.antoine-rcbs.ovh/activity_1");
DFMiniMp3<HardwareSerial, Mp3Notify> mp3(Serial1);

#define Serial WebUSBSerial

#define RING_PIN 2

String currentCommand = "";





void setup() {
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(14, OUTPUT);
  pinMode(15, OUTPUT);
  pinMode(16, OUTPUT);
  pinMode(18, OUTPUT);
  pinMode(19, OUTPUT);
  pinMode(20, OUTPUT);
  pinMode(21, OUTPUT);
  pinMode(RING_PIN, OUTPUT);
  digitalWrite(2, 1);
  delay(2000);
  digitalWrite(2, 0);
  digitalWrite(3, 1);
  digitalWrite(4, 1);
  digitalWrite(5, 1);
  digitalWrite(6, 1);
  digitalWrite(7, 1);
  digitalWrite(8, 1);
  digitalWrite(9, 1);
  digitalWrite(10, 1);
  digitalWrite(14, 1);
  digitalWrite(15, 1);
  digitalWrite(16, 1);
  digitalWrite(18, 1);
  digitalWrite(19, 1);
  digitalWrite(20, 1);
  digitalWrite(21, 1);
  mp3.begin();
  mp3.setVolume(24);
  while (!Serial) {
    ;
  }
  Serial.begin(9600);
  Serial.println("Arduino connected and answering");
  delay(1000);
  Serial.flush();
}

void loop() {
  if (Serial) {
    while (Serial.available() > 0) {
      char c = '0';
      while (c != ';') {
        c = Serial.read();
        currentCommand += c;
        delay(1);
      }
      runCommand(currentCommand);
      currentCommand = "";
    }
    Serial.flush();
  }
}

void ringTrack(int n, uint16_t duration) {
  digitalWrite(RING_PIN, HIGH);
  delay(4000);
  digitalWrite(RING_PIN, LOW);
  delay(500);
  if (n == 777) {
    mp3.playMp3FolderTrack(777);
  } else {
    int t = (int) random(1, 6);
    Serial.println(t);
    if (t < 3) {
      mp3.playMp3FolderTrack(1);
    } else {
      mp3.playMp3FolderTrack(2);
    }
  }
  
  waitMilliseconds(duration);
}

void waitMilliseconds(uint16_t msWait)
{
  uint32_t start = millis();

  while ((millis() - start) < msWait)
  {
    // calling mp3.loop() periodically allows for notifications
    // to be handled without interrupts
    mp3.loop();
    delay(1);
  }
}


void runCommand(String command) {
  //Décomposition de la commande en ID + arguments
  int curIndex = command.indexOf('_');
  String id = command.substring(0, curIndex);
  Serial.print(id);
  String args[5] = {"0", "0", "0", "0", "0"}; //Max 5 args
  for (int i = 0; i < 5; i++) {
    int nextIndex = command.indexOf('_', curIndex + 1);
    args[i] = command.substring(curIndex + 1, nextIndex);
    Serial.print(args[i]);
    curIndex = nextIndex;
    if (args[i].endsWith(";")) {
      args[i].remove(args[i].indexOf(';'));
      break;
    }
  }


  //Lancement des diverses commandes
  if (id == "IO") {
    turnIO(args[0].toInt(), args[1].toInt());
  } else if (id == "DELAY") {
    waitForUnlock(args[0].toInt());
  } else if (id == "RING") {
    ringTrack(args[0].toInt(), 10000);
  }


}

/* FONCTIONS METIER */

void turnIO(int pin, boolean val) {
  digitalWrite(pin, val);
}

void waitForUnlock(int delayMs) {
  delay(delayMs);
  Serial.println("UNLOCK;");
}
