volatile bool ringStopped = false;
#include <SPI.h>
#include <Wire.h>
#define LED0   26
#define LED1   25

// LoRa
///////////////////////////////////////////////////////////
#include <LoRa.h>
#define RFM95_CS   27 // A
#define RFM95_INT  33 // Must be a hardware interrupt pin IRQ, B
#define RFM95_RST  4 // F
byte msgCount = 0;


// WIFI
///////////////////////////////////////////////////////////
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <SPIFFS.h>
const char* ssid     = "your_network_name";
const char* password = "your_network_pwd";
AsyncWebServer server(8006);
IPAddress local_IP(10,0,0,5);
int wifiRequest;
int wifiAlertBool = false;
void postaAction(AsyncWebServerRequest *request) {
  ringStopped = false;
  wifiAlertBool = true;
  AsyncWebParameter* p = request->getParam(0); // parameters are broken into array to be indexed
  wifiRequest = (p->value()).toInt();
  request->send_P(200, "application/json", "{\"esp32\":\"activated\"}");
}

// OLED
///////////////////////////////////////////////////////////
#define BUTTON_A 15
#define BUTTON_B 32
#define BUTTON_C 14
#include "cokeBitMap.h"
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>
Adafruit_SH1107 display = Adafruit_SH1107(64, 128, &Wire);
void turnOffOLED()
{
  display.clearDisplay();
  display.drawBitmap(0, 0, dietcokeBitMap, 128, 64, SH110X_WHITE);
  display.display();delay(1000);
  display.invertDisplay(true);delay(400);
  display.invertDisplay(false);delay(400);
  display.invertDisplay(true);delay(400);
  display.invertDisplay(false);delay(400);
  display.invertDisplay(true);delay(400);
  display.invertDisplay(false);
  display.clearDisplay();
  display.display(); 
}
void displayOledWiFi( int requestType )
{
  display.clearDisplay();display.setTextSize(2);display.setCursor(0,8);
  display.println("Request:");
  display.setTextSize(1);
  if (requestType == 0)
  {
    display.println("Diet Coke");
    display.println("");
    display.println("Via Wi-Fi");
    display.display();
    return;
  }
  else if (requestType == 1)
  {
    display.println("Genearl Inquiry");
    display.println("");
    display.println("Via Wi-Fi");
    display.display();
    return;
  }
  else
  {
    display.println("Canceled");
    display.println("");
    display.println("Via Wi-Fi");
    display.display();
    return;
  }
}

void displayOledLoRa( int RRSI )
{
  display.clearDisplay();display.setTextSize(2);display.setCursor(0,8);
  display.println("Request:");
  display.setTextSize(1);  
  display.println("Diet Coke");
  display.println("");display.println("Via Radio");
  display.print("RSSI: ");display.println(String(RRSI));
  display.display();
}




// MUSIC
///////////////////////////////////////////////////////////
#include "pitches.h"
#define TONE_PIN 13
void play_melody(int *user_melody, unsigned int notes, int tempo){
  int wholenote = (60000 * 4) / tempo;
  int divider = 0, noteDuration = 0;  
  for (int thisNote = 0; thisNote < notes * 2; thisNote = thisNote + 2) {
    if(ringStopped){break;}
    divider = user_melody[thisNote + 1];
    if (divider > 0) {
      noteDuration = (wholenote) / divider;
    } else if (divider < 0) {
      noteDuration = (wholenote) / abs(divider);
      noteDuration *= 1.5; // increases the duration in half for dotted notes
    }
    tone(TONE_PIN, user_melody[thisNote], noteDuration*0.9);
    delay(noteDuration);
    noTone(TONE_PIN);
  }  
}
void stopRequest() {ringStopped = true;}

//

void wifiAlarm( int requestType )
{
  wifiAlertBool = false;
  if (requestType == 0)
  {
    // bool WiFiStatus = (WiFi.status()== WL_CONNECTED);
    digitalWrite(LED0, HIGH);
    displayOledWiFi(0);
    unsigned int notes = sizeof(imperialMarchMelody) / sizeof(imperialMarchMelody[0]) / 2;
    play_melody(imperialMarchMelody,notes,108);  
    return;
  }
  else if (requestType == 1)
  {
    // bool WiFiStatus = (WiFi.status()== WL_CONNECTED);
    digitalWrite(LED1, HIGH);
    displayOledWiFi(1);
    unsigned int notes = sizeof(hedwigMelody) / sizeof(hedwigMelody[0]) / 2;
    play_melody(hedwigMelody,notes,144);  
    return;
  }
  else
  {
    // bool WiFiStatus = (WiFi.status()== WL_CONNECTED);
    displayOledWiFi(2);
    return;
  }
}

void LoRaAlarm( int requestType, int RRSI )
{
  ringStopped = false;
  if (requestType == 0)
  {
    digitalWrite(LED0, HIGH);
    displayOledLoRa(RRSI);
    unsigned int notes = sizeof(imperialMarchMelody) / sizeof(imperialMarchMelody[0]) / 2;
    play_melody(imperialMarchMelody,notes,108); 
  }
}


void setup() {

  Serial.begin(115200);

  // WIFI
  if(!SPIFFS.begin(true)){return;}
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {delay(1000);}  //
  Serial.println(WiFi.localIP());
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/index.html");
  });
  server.on("/ESPdata", HTTP_POST, postaAction);
  server.begin();

  // OLED
  display.begin(0x3C, true);display.setRotation(1);display.setTextColor(SH110X_WHITE);
  delay(1000);
  turnOffOLED();
  delay(250);
  pinMode(BUTTON_A, INPUT_PULLUP);
  pinMode(BUTTON_B, INPUT_PULLUP);
  pinMode(BUTTON_C, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(BUTTON_A), stopRequest, CHANGE);

  // LoRa
  LoRa.setPins(RFM95_CS, RFM95_RST, RFM95_INT);
  if (!LoRa.begin(915E6)){Serial.println("Starting LoRa failed!"); while (1);}

  pinMode(LED0, OUTPUT);
  pinMode(LED1, OUTPUT);
  digitalWrite(LED0, HIGH);
  digitalWrite(LED1, HIGH);

}

void loop() {
  if(wifiAlertBool){wifiAlarm(wifiRequest);}
  if(!digitalRead(BUTTON_B))
  {
    digitalWrite(LED0, HIGH);
    digitalWrite(LED1, HIGH);
    display.clearDisplay();
    display.drawBitmap(0, 0, dietcokeBitMap, 128, 64, SH110X_WHITE);
    display.display();delay(1500);
    display.clearDisplay();
    display.display(); 
    digitalWrite(LED0, LOW);
    digitalWrite(LED1, LOW);
    delay(500);
  }
  if(!digitalRead(BUTTON_C))
  {
    digitalWrite(LED0, HIGH);
    digitalWrite(LED1, HIGH);
    display.clearDisplay();
    display.drawBitmap(0, 0, dietcokeBitMap, 128, 64, SH110X_WHITE);
    display.display();delay(1500);
    display.clearDisplay();
    display.display(); 
    digitalWrite(LED0, LOW);
    digitalWrite(LED1, LOW);
    delay(500);
  }  

  int packetSize = LoRa.parsePacket();
  if (packetSize) 
  {

    int recipient = LoRa.read();        // recipient address
    byte sender = LoRa.read();          // sender address
    byte requestType = LoRa.read();     // sender request ID, 0,1,2,....
    if (sender != 0b111000 && recipient != 0b101111) 
    {
      Serial.println("This message is not for me.");
      return;
    }
    int Rssi = LoRa.packetRssi();
    LoRaAlarm(requestType,Rssi);
  }

}