#include <WiFi.h>
#include <DNSServer.h>
#include <Adafruit_GFX.h>         // Core graphics library
#include <Adafruit_ILI9341.h>     // Hardware-specific library
#include <SdFat.h>                // SD card & FAT filesystem library
#include <Adafruit_SPIFlash.h>    // SPI / QSPI flash library
#include <Adafruit_ImageReader.h> // Image-reading functions

const byte DNS_PORT = 53;
IPAddress apIP(8,8,4,4); // The default android DNS
DNSServer dnsServer;
WiFiServer server(80);

// Comment out the next line to load from SPI/QSPI flash instead of SD card:
#define USE_SD_CARD

// TFT display and SD card share the hardware SPI interface, using
// 'select' pins for each to identify the active device on the bus.

#define SD_CS   4 // SD card select pin
#define TFT_CS  10 // TFT select pin
#define TFT_DC  9 // TFT display/command pin

#if defined(USE_SD_CARD)
  SdFat                SD;         // SD card filesystem
  Adafruit_ImageReader reader(SD); // Image-reader object, pass in SD filesys
#else
  // SPI or QSPI flash filesystem (i.e. CIRCUITPY drive)
  #if defined(__SAMD51__) || defined(NRF52840_XXAA)
    Adafruit_FlashTransport_QSPI flashTransport(PIN_QSPI_SCK, PIN_QSPI_CS,
      PIN_QSPI_IO0, PIN_QSPI_IO1, PIN_QSPI_IO2, PIN_QSPI_IO3);
  #else
    #if (SPI_INTERFACES_COUNT == 1)
      Adafruit_FlashTransport_SPI flashTransport(SS, &SPI);
    #else
      Adafruit_FlashTransport_SPI flashTransport(SS1, &SPI1);
    #endif
  #endif
  Adafruit_SPIFlash    flash(&flashTransport);
  FatVolume        filesys;
  Adafruit_ImageReader reader(filesys); // Image-reader, pass in flash filesys
#endif

Adafruit_ILI9341     tft    = Adafruit_ILI9341(TFT_CS, TFT_DC);
Adafruit_Image       img;        // An image loaded into RAM
int32_t              width  = 0, // BMP image dimensions
                     height = 0;

String responseHTML = ""
  "<!DOCTYPE html><html><head><title>CaptivePortal</title></head><body>"
  "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
  "<center><H2>Penny's Computer Book / <br>Libro del computer di Penny</H2>"
  "<H4>Wireless Functions / <br>Funzioni Wi-Fi:</H4><br>"
  "<a href=\"/H\"><button type=\"button\">Track the MAD operation / <br>Tieni traccia dell'operazione MAD</button></a><br><br>"
  "<a href=\"/L\"><button type=\"button\">Call Brain / Chiama Brain</button></a><br><br>"
  "<a href=\"/T\"><button type=\"button\">See the parts for this build / <br>Vedi le parti di questo progetto</button></a><br><br><br>"
  "<p>Created by / Creato da<br> Becky Stern <br>for / per Digi-Key 2023</p><br>"
  "</center></body></html>";

void setup() { 
  ImageReturnCode stat; // Status from image-reading functions

  pinMode(LED_BUILTIN, OUTPUT);

  Serial.begin(115200);
  
 #if !defined(ESP32)
   while(!Serial);       // Wait for Serial Monitor before continuing
 #endif
Serial.println();
  Serial.println("Configuring access point...");
  tft.begin();          // Initialize screen

  // The Adafruit_ImageReader constructor call (above, before setup())
  // accepts an uninitialized SdFat or FatVolume object. This MUST
  // BE INITIALIZED before using any of the image reader functions!
  Serial.print(F("Initializing filesystem..."));
#if defined(USE_SD_CARD)
  // SD card is pretty straightforward, a single call...
  if(!SD.begin(SD_CS, SD_SCK_MHZ(25))) { // ESP32 requires 25 MHz limit
    Serial.println(F("SD begin() failed"));
    for(;;); // Fatal error, do not continue
  }
#else
  // SPI or QSPI flash requires two steps, one to access the bare flash
  // memory itself, then the second to access the filesystem within...
  if(!flash.begin()) {
    Serial.println(F("flash begin() failed"));
    for(;;);
  }
  if(!filesys.begin(&flash)) {
    Serial.println(F("filesys begin() failed"));
    for(;;);
  }
#endif
  Serial.println(F("OK!"));

  // Fill screen blue. Not a required step, this just shows that we're
  // successfully communicating with the screen.
  tft.fillScreen(ILI9341_BLUE);

  // Load full-screen BMP file 'purple.bmp' at position (0,0) (top left).
  // Notice the 'reader' object performs this, with 'tft' as an argument.
  Serial.print(F("Loading 3.bmp to screen..."));
  stat = reader.drawBMP("/3.bmp", tft, 0, 0);
  reader.printStatus(stat);   // How'd we do?

  // Query the dimensions of image 'parrot.bmp' WITHOUT loading to screen:
  Serial.print(F("Querying 3.bmp image size..."));
  stat = reader.bmpDimensions("/3.bmp", &width, &height);
  reader.printStatus(stat);   // How'd we do?
  if(stat == IMAGE_SUCCESS) { // If it worked, print image size...
    Serial.print(F("Image dimensions: "));
    Serial.print(width);
    Serial.write('x');
    Serial.println(height);
  }
  WiFi.mode(WIFI_AP);
  WiFi.softAP("Penny's Computer Book");
  WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));

  // if DNSServer is started with "*" for domain name, it will reply with
  // provided IP to all DNS request
  dnsServer.start(DNS_PORT, "*", apIP);

  server.begin();
}

void loop() {
  dnsServer.processNextRequest();
  WiFiClient client = server.available();   // listen for incoming clients

  if (client) {
    String currentLine = "";
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        if (c == '\n') {
          if (currentLine.length() == 0) {
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println();
            client.print(responseHTML);
            break;
          } else {
            currentLine = "";
          }
        } else if (c != '\r') {
          currentLine += c;
        }
        // Check to see if the client request was "GET /H" or "GET /L":
        if (currentLine.endsWith("GET /H")) {
          //digitalWrite(LED_BUILTIN, HIGH);               // GET /H turns the LED on
          reader.drawBMP("/mad.bmp", tft, 0, 0);
          delay(1300);
          tft.fillScreen(ILI9341_BLACK);
          reader.drawBMP("/3.bmp", tft, 0, 0);
        }
        if (currentLine.endsWith("GET /L")) {
          digitalWrite(LED_BUILTIN, LOW);                // GET /L turns the LED off
          tft.fillScreen(ILI9341_BLACK);
          reader.drawBMP("/brain.bmp", tft, 0, 0);
          delay(2000);
          tft.fillScreen(ILI9341_BLACK);
          reader.drawBMP("/3.bmp", tft, 0, 0);
        
        }
        if (currentLine.endsWith("GET /T")) {
          tft.fillScreen(ILI9341_WHITE);
          reader.drawBMP("/esp32.bmp", tft, 0, 0);
          delay(1000);
          tft.fillScreen(ILI9341_WHITE);
          reader.drawBMP("/mega.bmp", tft, 0, 0);
          delay(1000);
          tft.fillScreen(ILI9341_WHITE);
          reader.drawBMP("/greybutton.bmp", tft, 0, 0);
          delay(1000);
          tft.fillScreen(ILI9341_WHITE);
          reader.drawBMP("/greenbutton.bmp", tft, 0, 0);
          delay(1000);
          tft.fillScreen(ILI9341_WHITE);
          reader.drawBMP("/whitebutton.bmp", tft, 0, 0);
          delay(1000);
          tft.fillScreen(ILI9341_BLACK);
          reader.drawBMP("/3.bmp", tft, 0, 0);
        }
      }
    }
    client.stop();
    Serial.println("Client Disconnected.");
  }
}