#include <Arduino.h>
#include "AudioGeneratorMP3.h"
#include "AudioOutputI2S.h"
#include "AudioFileSourceSD.h"
#include "driver/SinglePinI2SDriver.h"
#include <SD.h>
#include <WiFi.h>
#include "Arduino.h"
#include <WebServer.h>
#include <ESPmDNS.h>
#include <Adafruit_NeoPixel.h>

const char* ssid     = "DnD";
const char* password = "dndpassword";

//define trigger pins

#define TRIGGER0 2
#define TRIGGER1 0
#define TRIGGER2 4
#define TRIGGER3 16
#define TRIGGER4 17
#define TRIGGER5 21
#define TRIGGER6 13
#define TRIGGER7 12
#define TRIGGER8 14
#define TRIGGER9 27

//define SD Card pins
#define SD_MISO     19
#define SD_MOSI     23
#define SD_SCLK     18
#define SD_CS       5

//define LED/Player pins
#define LED_COUNT 7
#define LED_PIN 15
#define COLOR_POT 33
#define BRIGHT_POT 32
#define PLAYER_POT 35

volatile byte playernumber = 0;
int pix;
int pot = 1;
int bright = 1;
String result = " ";

Adafruit_NeoPixel strip = Adafruit_NeoPixel (LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

WebServer server(80);

 
// Define routing
void restServerRouting() {
    server.on("/", HTTP_GET, []() {
        server.send(200, F("text/html"),
            F("Welcome to the DnD REST Web Server"));
    });
    server.on(F("/dnd"), HTTP_GET, loop);
}
 
// Manage not found URL
void handleNotFound() {
  String message = "File Not Found\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i = 0; i < server.args(); i++) {
    message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);
}


//Initialize ESP8266 Audio Library classes
AudioGeneratorMP3 *mp3;
AudioFileSourceSD *file;
AudioOutputI2S *out;

volatile bool playing = 0;
volatile byte loadTrack = 0;

//External Interrupt function with software switch debounce
void IRAM_ATTR handleInterrupt()
{
  static unsigned long last_interrupt_time = 0;
  unsigned long interrupt_time = millis();
  // If interrupts come faster than 200ms, assume it's a bounce and ignore
  if (interrupt_time - last_interrupt_time > 200) 
  {
    //Figure out which switch was triggered, and which track to play
    if(!digitalRead(TRIGGER0)) loadTrack = 1;
    else if(!digitalRead(TRIGGER1)) loadTrack = 2;
    else if(!digitalRead(TRIGGER2)) loadTrack = 3;
    else if(!digitalRead(TRIGGER3)) loadTrack = 4;
    else if(!digitalRead(TRIGGER4)) loadTrack = 5;
    else if(!digitalRead(TRIGGER5)) loadTrack = 6;
    else if(!digitalRead(TRIGGER6)) loadTrack = 7;
    else if(!digitalRead(TRIGGER7)) loadTrack = 8;
    else if(!digitalRead(TRIGGER8)) loadTrack = 9;
    else if(!digitalRead(TRIGGER9)) loadTrack = 10;

    playing = 1;
    Serial.print(loadTrack);
  }
  last_interrupt_time = interrupt_time;
}

void setup()
{  
  Serial.begin(115200);
  //Configure trigger pins to inputs with internal pull-up resistors enabled
  pinMode(TRIGGER0,INPUT_PULLUP);
  pinMode(TRIGGER1,INPUT_PULLUP);
  pinMode(TRIGGER2,INPUT_PULLUP);
  pinMode(TRIGGER3,INPUT_PULLUP);
  pinMode(TRIGGER4,INPUT_PULLUP);
  pinMode(TRIGGER5,INPUT_PULLUP);
  pinMode(TRIGGER6,INPUT_PULLUP);
  pinMode(TRIGGER7,INPUT_PULLUP);
  pinMode(TRIGGER8,INPUT_PULLUP);
  pinMode(TRIGGER9,INPUT_PULLUP);

  //Create interrupts for each trigger
  attachInterrupt(digitalPinToInterrupt(TRIGGER0),handleInterrupt,FALLING);
  attachInterrupt(digitalPinToInterrupt(TRIGGER1),handleInterrupt,FALLING);
  attachInterrupt(digitalPinToInterrupt(TRIGGER2),handleInterrupt,FALLING);
  attachInterrupt(digitalPinToInterrupt(TRIGGER3),handleInterrupt,FALLING);
  attachInterrupt(digitalPinToInterrupt(TRIGGER4),handleInterrupt,FALLING);
  attachInterrupt(digitalPinToInterrupt(TRIGGER5),handleInterrupt,FALLING);
  attachInterrupt(digitalPinToInterrupt(TRIGGER6),handleInterrupt,FALLING);
  attachInterrupt(digitalPinToInterrupt(TRIGGER7),handleInterrupt,FALLING);
  attachInterrupt(digitalPinToInterrupt(TRIGGER8),handleInterrupt,FALLING);
  attachInterrupt(digitalPinToInterrupt(TRIGGER9),handleInterrupt,FALLING);


  out = new AudioOutputI2S();
  mp3 = new AudioGeneratorMP3();

 delay(1000);

  Serial.print("Initializing SD card...");
  if (!SD.begin(5))
  {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");
  delay(100);

    Serial.println("\n[*] Creating AP");
    WiFi.mode(WIFI_AP);
    WiFi.softAP(ssid, password);
    Serial.print("[+] AP Created with IP Gateway ");
    Serial.println(WiFi.softAPIP());
    strip.begin();
    strip.show();

      if (MDNS.begin("esp8266")) {
    Serial.println("MDNS responder started");
  }
 
  // Set server routing
  restServerRouting();
  // Set not found response
  server.onNotFound(handleNotFound);
  // Start server
  server.begin();
  Serial.println("HTTP server started");
}

void loop()
{

  int pot = analogRead (COLOR_POT);
  //Serial.println(pot);
  int playernumber = analogRead (PLAYER_POT);
  //Serial.println(playernumber);
  int bright = analogRead (BRIGHT_POT);

  Serial.println(pot);
  Serial.println(playernumber);
  Serial.println(bright);

  int bright_v = bright / 16;
  int pot_v = pot / 4;
  //Serial.println(bright);
  //Serial.println(bright_v);
  for(int a=6;a<LED_COUNT;a++){
   setPixel_Torch(a,pot_v,bright_v);
}

  if ((playernumber > 0) && (playernumber < 682))
      strip.clear();{  
      for(int a=5;a<6;a++){
          setPixel_Player(a,0,bright_v);
          }
      for(int a=6;a<LED_COUNT;a++){
          setPixel_Torch(a,pot_v,bright_v);
}
}

  if ((playernumber > 682) && (playernumber < 1364 ))
     strip.clear();{  
     for(int a=4;a<5;a++){
         setPixel_Player(a,0,bright_v);
         }
     for(int a=6;a<LED_COUNT;a++){
          setPixel_Torch(a,pot_v,bright_v);
}
}
  if ((playernumber > 1365) && (playernumber < 2046 ))
     strip.clear();{  
     for(int a=3;a<4;a++){
         setPixel_Player(a,0,bright_v);
         }
     for(int a=6;a<LED_COUNT;a++){
          setPixel_Torch(a,pot_v,bright_v);
}
}

  if ((playernumber > 2047) && (playernumber < 2728 ))
     strip.clear();{  
     for(int a=2;a<3;a++){
         setPixel_Player(a,0,bright_v);
         }
     for(int a=6;a<LED_COUNT;a++){
          setPixel_Torch(a,pot_v,bright_v);
}
}

  if ((playernumber > 2729) && (playernumber < 3410 ))
     strip.clear();{  
     for(int a=1;a<2;a++){
         setPixel_Player(a,0,bright_v);
         }
     for(int a=6;a<LED_COUNT;a++){
          setPixel_Torch(a,pot_v,bright_v);
}
}

  if ((playernumber > 3411) && (playernumber < 4096 ))
     strip.clear();{  
     for(int a=0;a<1;a++){
         setPixel_Player(a,0,bright_v);
         }
     for(int a=6;a<LED_COUNT;a++){
          setPixel_Torch(a,pot_v,bright_v);
}
}

  strip.show();
  String potStr;
  String brightStr;
  potStr = String(pot);
  brightStr = String(bright);
  result = potStr + " " + brightStr;
  
  server.send(200, "text/json", result);
  
  server.handleClient();


  
  if(loadTrack) //Load the track we want to play
  {
    //Stop the current track if playing
    if(playing && mp3->isRunning()) mp3->stop();

    if(loadTrack == 1) file = new AudioFileSourceSD("/TRACK1.mp3");
    else if(loadTrack == 2) file = new AudioFileSourceSD("/TRACK2.mp3");
    else if(loadTrack == 3) file = new AudioFileSourceSD("/TRACK3.mp3");
    else if(loadTrack == 4) file = new AudioFileSourceSD("/TRACK4.mp3");
    else if(loadTrack == 5) file = new AudioFileSourceSD("/TRACK5.mp3");
    else if(loadTrack == 6) file = new AudioFileSourceSD("/TRACK6.mp3");
    else if(loadTrack == 7) file = new AudioFileSourceSD("/TRACK7.mp3");
    else if(loadTrack == 8) file = new AudioFileSourceSD("/TRACK8.mp3");
    else if(loadTrack == 9) file = new AudioFileSourceSD("/TRACK9.mp3");
    else if(loadTrack == 10) file = new AudioFileSourceSD("/TRACK10.mp3");

    out -> SetGain(0.08); //Set the volume
    mp3 -> begin(file,out); //Start playing the track loaded
    loadTrack = 0;
  }

  if(playing && mp3->isRunning()) {
    if (!mp3->loop())
    {
      mp3->stop();
      playing = 0;
      Serial.println("Stopped");
    }
  }
}



void setPixel_Torch(int pixelz, int colorz, long unsigned fadez) {
  fadez*=fadez;
  fadez/=255;
  strip.setPixelColor(pixelz,strip.ColorHSV(colorz*64,255,fadez));
}


void setPixel_Player(int pixelz, int colorz, long unsigned fadez) {
  fadez*=fadez;
  fadez/=255;
  strip.setPixelColor(pixelz,strip.ColorHSV(colorz*64,255,fadez));
}
