#include <Arduino.h>
#include <FS.h>
#include <LittleFS.h>
#include <FSWebServer.h>  //https://github.com/cotestatnt/async-esp-fs-webserver

// Timezone definition to get properly time from NTP server
#define MYTZ "CET-1CEST,M3.5.0,M10.5.0/3"
struct tm Time;

#define FILESYSTEM LittleFS
FSWebServer server(FILESYSTEM, 80, "myserver");

// Define built-in LED if not defined by board (eg. generic dev boards)
#ifndef LED_BUILTIN
#define LED_BUILTIN 2
#endif

#ifndef BOOT_PIN
#define BOOT_PIN    0
#endif

// Labels used in /setup webpage for options
#define LED_LABEL       "The LED pin number"
#define BOOL_LABEL      "A bool variable"
#define BOOL_LABEL2     "A second bool variable"
#define LONG_LABEL      "A long variable"
#define FLOAT_LABEL     "A float variable"
#define STRING_LABEL    "A String variable"
#define DROPDOWN_LABEL  "Days of week"
#define BRIGHTNESS_LABEL "Brightness"

// Test "options" values
uint8_t ledPin = LED_BUILTIN;
bool boolVar = true;
bool boolVar2 = false;
uint32_t longVar = 1234567890;
float floatVar = 15.51F;
String stringVar = "Test option String";

// Add a dropdown list box in /setup page
const char* days[] = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
uint8_t daySelected = 2;// Default to "Wednesday"
SetupConfig::DropdownList dayOfWeek{ DROPDOWN_LABEL, days, 7, daySelected}; 

// Add a slider in /setup page
SetupConfig::Slider brightness{ BRIGHTNESS_LABEL, 0.0, 100.0, 1.0, 50.0 };

static const char reload_btn_htm[] PROGMEM = R"EOF(
<div class="bar">
  <a class="btn" id="reload-btn">Reload options</a>
</div>
)EOF";

static const char reload_btn_script[] PROGMEM = R"EOF(
/* Add click listener to button */
const reloadCfg = () => {
  console.log('Reload configuration options');
  fetch('/reload')
  .then((response) => {
    if (response.ok) {
      openModal('Options loaded', 'Options was reloaded from configuration file');
      return;
    }
    throw new Error('Something goes wrong with fetch');
  })
  .catch((error) => {
    openModal('Error', 'Something goes wrong with your request');
  });
};
document.getElementById('reload-btn').addEventListener('click', reloadCfg);
)EOF";

// Generated from: .\custom_logo.png
// Size: 2150 bytes
// MIME type: image/png
const uint8_t custom_logo[] PROGMEM = {
  0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
  0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x08, 0x06, 0x00, 0x00, 0x00, 0xC3, 0x3E, 0x61,
  0xCB, 0x00, 0x00, 0x00, 0x04, 0x73, 0x42, 0x49, 0x54, 0x08, 0x08, 0x08, 0x08, 0x7C, 0x08, 0x64,
  0x88, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x03, 0xB1, 0x00, 0x00, 0x03,
  0xB1, 0x01, 0xF5, 0x83, 0xED, 0x49, 0x00, 0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6F,
  0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x00, 0x77, 0x77, 0x77, 0x2E, 0x69, 0x6E, 0x6B, 0x73, 0x63,
  0x61, 0x70, 0x65, 0x2E, 0x6F, 0x72, 0x67, 0x9B, 0xEE, 0x3C, 0x1A, 0x00, 0x00, 0x07, 0xE3, 0x49,
  0x44, 0x41, 0x54, 0x78, 0x9C, 0xED, 0x9D, 0x5D, 0x6C, 0x14, 0x55, 0x14, 0xC7, 0xFF, 0x77, 0x66,
  0xB7, 0x4A, 0x17, 0x02, 0x26, 0x2C, 0x1A, 0x45, 0x02, 0x22, 0x01, 0x0B, 0xBE, 0x98, 0xE0, 0x47,
  0x78, 0x10, 0xBF, 0xA5, 0x85, 0xB4, 0x10, 0xB7, 0x86, 0xE8, 0x8B, 0xA9, 0x42, 0x5B, 0x82, 0x56,
  0x49, 0x30, 0x1A, 0xA3, 0x68, 0x7C, 0xF1, 0x23, 0xC4, 0x58, 0x69, 0x81, 0x48, 0x34, 0x31, 0x06,
  0xD2, 0xE5, 0xCB, 0x96, 0x96, 0x07, 0x88, 0xC2, 0x83, 0x51, 0xD1, 0xF8, 0x22, 0x52, 0xD4, 0xA4,
  0xA2, 0x54, 0x8C, 0x96, 0x84, 0x8F, 0x96, 0x22, 0xB0, 0x33, 0xC7, 0x87, 0x52, 0xED, 0x6E, 0xE7,
  0xCE, 0xCC, 0x9D, 0xEE, 0xEC, 0xCE, 0xF6, 0x9E, 0xDF, 0xDB, 0xCE, 0x3D, 0x67, 0xE6, 0xE6, 0x9E,
  0xFF, 0x9E, 0xFB, 0xB1, 0xA7, 0x1D, 0x80, 0x61, 0x18, 0x86, 0x61, 0x18, 0x86, 0x61, 0x18, 0xBD,
  0x10, 0x41, 0x9C, 0x52, 0x1D, 0xAB, 0x66, 0x90, 0x30, 0xAB, 0x85, 0x81, 0x2A, 0x90, 0x98, 0x09,
  0x60, 0x3A, 0x80, 0x44, 0x3E, 0x3B, 0xC6, 0x78, 0x72, 0x01, 0x40, 0x2F, 0x04, 0x9D, 0x00, 0xC4,
  0x3E, 0xD3, 0xC4, 0x67, 0x3B, 0x1E, 0x69, 0x39, 0xA9, 0x7A, 0x13, 0x25, 0x01, 0xA4, 0x3A, 0xEA,
  0x6F, 0x82, 0x69, 0xBE, 0x0A, 0xA2, 0x3A, 0x00, 0xA6, 0xEA, 0xC3, 0x98, 0x50, 0xB1, 0x85, 0x10,
  0xBB, 0x0C, 0x61, 0xAD, 0xDF, 0xB1, 0x64, 0xF3, 0x09, 0xBF, 0x4E, 0xBE, 0x05, 0x50, 0xDB, 0xD5,
  0x50, 0x43, 0xB6, 0xF8, 0x04, 0x02, 0x13, 0x03, 0x75, 0x8F, 0x29, 0x14, 0xFD, 0x20, 0x7A, 0x32,
  0xBD, 0xB4, 0xB5, 0xDD, 0x8F, 0xB1, 0xE1, 0xC7, 0x28, 0xD5, 0xD9, 0xF8, 0x1C, 0x91, 0xD8, 0xC5,
  0xC1, 0x2F, 0x09, 0x26, 0x41, 0x88, 0x3D, 0xB5, 0x9D, 0x6B, 0x9E, 0xF5, 0x63, 0xEC, 0x99, 0x01,
  0x6A, 0xBB, 0x1A, 0x6A, 0x88, 0xC4, 0x2E, 0xF8, 0x14, 0x0B, 0x13, 0x19, 0x6C, 0x10, 0x2D, 0xF7,
  0xCA, 0x04, 0xAE, 0x02, 0x58, 0xD1, 0xB5, 0x76, 0xBA, 0x69, 0x5B, 0xDD, 0xFC, 0xCD, 0x2F, 0x59,
  0xFA, 0xCD, 0x8C, 0x31, 0x6F, 0x47, 0xF5, 0x07, 0xA7, 0x64, 0x06, 0x31, 0x37, 0xEF, 0x18, 0xD9,
  0x6F, 0x90, 0x24, 0xF8, 0xC2, 0x30, 0x90, 0x98, 0x36, 0x07, 0xE5, 0x53, 0x67, 0xA1, 0xAC, 0x7C,
  0x32, 0x84, 0x91, 0x7D, 0xAB, 0x93, 0x5F, 0x7F, 0x1A, 0xA8, 0xC7, 0x8C, 0x33, 0x37, 0xDF, 0xFD,
  0x44, 0xD6, 0x67, 0xB2, 0x33, 0xB8, 0x3C, 0x78, 0x0E, 0x17, 0x4F, 0xFF, 0x8A, 0x81, 0xBF, 0x7F,
  0x01, 0xD9, 0xB6, 0x93, 0xDB, 0x24, 0x3B, 0x66, 0xBD, 0x0E, 0xE0, 0x19, 0xD9, 0x7D, 0xA5, 0x19,
  0x20, 0xD5, 0xB1, 0x6A, 0x06, 0x8C, 0x58, 0x0F, 0x1C, 0x56, 0xFB, 0x66, 0x59, 0x39, 0x92, 0x73,
  0xEF, 0x43, 0x3C, 0x31, 0x45, 0xDA, 0x61, 0x16, 0x40, 0x7E, 0xC9, 0x15, 0xC0, 0x48, 0xAE, 0x5C,
  0x38, 0x83, 0xBE, 0x9F, 0x0E, 0xC1, 0xBA, 0x3C, 0xE8, 0xD4, 0x6C, 0x59, 0xC2, 0x9C, 0xB9, 0xBB,
  0xB2, 0xB9, 0xD7, 0xA9, 0x51, 0x3A, 0xAF, 0x0B, 0x23, 0x5E, 0x03, 0x87, 0xE0, 0x0B, 0xC3, 0xF0,
  0x0C, 0x3E, 0x53, 0x58, 0xE2, 0x89, 0xEB, 0x90, 0x9C, 0xBB, 0x18, 0xC2, 0x70, 0x0C, 0xA7, 0x19,
  0xA3, 0x4C, 0xB5, 0xCC, 0x57, 0x2A, 0x00, 0x02, 0x2D, 0x71, 0xBA, 0x9E, 0x98, 0x36, 0x87, 0x83,
  0x1F, 0x41, 0xE2, 0x89, 0xEB, 0x90, 0x48, 0xDE, 0xEA, 0xD8, 0x46, 0x24, 0x2A, 0x65, 0x7E, 0xF2,
  0x35, 0x00, 0xE1, 0x56, 0xA7, 0x09, 0x22, 0x31, 0x75, 0x66, 0xD6, 0xE7, 0x8B, 0x67, 0xFE, 0xC0,
  0x99, 0x5F, 0x8F, 0xC8, 0xD2, 0x8F, 0x27, 0xDB, 0x17, 0x9D, 0xCD, 0xFA, 0xBC, 0xF2, 0xCB, 0x29,
  0x91, 0x6A, 0x8F, 0x0A, 0xB9, 0x53, 0x6A, 0xAC, 0xAC, 0x1C, 0x53, 0x6E, 0xB9, 0x0B, 0x13, 0xA6,
  0xDC, 0xF8, 0xDF, 0xB5, 0x44, 0x72, 0x16, 0x06, 0xFE, 0xFA, 0x79, 0xB4, 0xB3, 0xC0, 0x6C, 0xD9,
  0x7D, 0xDD, 0xB6, 0x76, 0x37, 0x38, 0x5D, 0x8C, 0x97, 0x67, 0x0F, 0xD0, 0xD9, 0x31, 0x04, 0x9F,
  0x09, 0x4E, 0xE6, 0xF2, 0x20, 0xCE, 0xF4, 0x7C, 0x93, 0x75, 0x2D, 0x36, 0x61, 0xB2, 0xB3, 0x31,
  0xE1, 0x26, 0xD9, 0x7D, 0xE4, 0x19, 0x40, 0xBA, 0xFA, 0xCF, 0x76, 0xC9, 0x68, 0x12, 0xFC, 0xDC,
  0x4C, 0xA1, 0x4A, 0x18, 0x99, 0x25, 0xF7, 0x8B, 0x67, 0x98, 0x71, 0x67, 0x43, 0x97, 0x6D, 0x3C,
  0x1F, 0xEE, 0x68, 0x8E, 0xEB, 0x39, 0x40, 0x21, 0xF0, 0xFA, 0x66, 0x14, 0xBB, 0x7D, 0xBC, 0xC3,
  0x19, 0x40, 0x73, 0x94, 0x33, 0x00, 0x1F, 0xF0, 0x44, 0x8B, 0xB1, 0xC6, 0x83, 0x33, 0x80, 0xE6,
  0x48, 0x05, 0x70, 0x6D, 0xAC, 0x7C, 0xA2, 0x6D, 0x8A, 0x05, 0x00, 0x9A, 0x00, 0x1C, 0x2D, 0x5C,
  0x97, 0x98, 0x3C, 0xF1, 0x03, 0x80, 0x26, 0xDB, 0x14, 0x0B, 0xAE, 0x8D, 0x95, 0x4B, 0x77, 0x01,
  0xBE, 0x0A, 0x42, 0x52, 0x6D, 0x29, 0x53, 0x24, 0xA6, 0xD6, 0x13, 0x8C, 0x8D, 0x00, 0x95, 0xE5,
  0xAD, 0x8B, 0x25, 0x44, 0x14, 0xB7, 0x81, 0x12, 0x2E, 0x41, 0x88, 0xE7, 0xE7, 0x1F, 0x49, 0x6E,
  0xD9, 0xB0, 0x61, 0x83, 0xE3, 0x2F, 0x44, 0x23, 0x51, 0x2B, 0x09, 0xEB, 0xAA, 0xBF, 0x1F, 0x64,
  0xEE, 0xF7, 0x23, 0x82, 0x8F, 0xEE, 0x7D, 0x45, 0xE5, 0xD6, 0x78, 0x6B, 0x4B, 0x97, 0x92, 0x7D,
  0xA9, 0xF3, 0xE2, 0x6A, 0xE9, 0xE9, 0xAC, 0x23, 0x4F, 0x1D, 0x7E, 0xD3, 0x8F, 0xD9, 0x25, 0x41,
  0x58, 0xD2, 0xB6, 0xB4, 0xE5, 0x0B, 0xBF, 0xF7, 0x55, 0x5A, 0x03, 0xA4, 0x2B, 0x37, 0x7F, 0x0E,
  0x41, 0xEB, 0x54, 0x7C, 0x98, 0xC2, 0x21, 0x40, 0x4D, 0x2A, 0xC1, 0x07, 0x82, 0x2C, 0x02, 0x07,
  0xFA, 0x5A, 0x41, 0xF8, 0x51, 0xD9, 0x8F, 0x09, 0x9B, 0x1F, 0x2A, 0xBE, 0xBD, 0x7E, 0xAB, 0xAA,
  0x93, 0xB2, 0x00, 0xD2, 0xB5, 0x69, 0x4B, 0x08, 0x6C, 0x53, 0xF5, 0x63, 0xC2, 0x45, 0x40, 0x7C,
  0xE8, 0x67, 0xCE, 0xCF, 0x25, 0xD0, 0x36, 0x50, 0x90, 0x7D, 0x20, 0x88, 0x1F, 0x13, 0x1E, 0x24,
  0x32, 0x07, 0x83, 0xF8, 0x05, 0x12, 0xC0, 0x45, 0xEB, 0xF2, 0x6F, 0x41, 0xFC, 0x98, 0x10, 0x99,
  0x60, 0xFE, 0x1E, 0xC4, 0x2D, 0x90, 0x00, 0x26, 0xC5, 0x13, 0x81, 0xFE, 0xA2, 0x88, 0x09, 0x8F,
  0x4B, 0xE7, 0xFF, 0x09, 0x14, 0x93, 0x40, 0x02, 0xC8, 0xD8, 0x57, 0x66, 0x04, 0xF1, 0x63, 0xC2,
  0xE3, 0x9A, 0x78, 0xFC, 0xE6, 0x20, 0x7E, 0x81, 0x7E, 0x0D, 0xB4, 0x85, 0x78, 0xD8, 0xCB, 0xC6,
  0xE7, 0xBE, 0xF5, 0x3F, 0xE6, 0xE1, 0x0E, 0xD7, 0xF6, 0x83, 0x87, 0x0E, 0x29, 0xDD, 0xAF, 0xD8,
  0x3C, 0xB8, 0x78, 0xB1, 0x6B, 0xBB, 0xEA, 0xF8, 0x78, 0x42, 0xE6, 0x43, 0x00, 0x8E, 0xA9, 0xBA,
  0x29, 0x67, 0x80, 0x54, 0x5B, 0xCA, 0x04, 0x8C, 0x3A, 0x55, 0x3F, 0x26, 0x74, 0x9E, 0x1E, 0x8A,
  0x8D, 0x1A, 0xCA, 0x02, 0x10, 0x89, 0x69, 0x6B, 0x00, 0xAA, 0x50, 0xF5, 0x63, 0x42, 0x67, 0x81,
  0x48, 0x4C, 0xAD, 0x57, 0x75, 0x52, 0x12, 0x40, 0xED, 0xBE, 0x86, 0x07, 0x09, 0xF4, 0xAE, 0xEA,
  0x43, 0x98, 0xC2, 0x40, 0x30, 0x36, 0x3E, 0xB6, 0x7F, 0xCD, 0x03, 0x2A, 0x3E, 0xBE, 0xD6, 0x00,
  0x43, 0x3F, 0x06, 0x4D, 0x5B, 0x73, 0x35, 0xF8, 0x92, 0xC2, 0x33, 0xA6, 0xF8, 0x50, 0x99, 0xB0,
  0x45, 0x57, 0xAA, 0xAB, 0x71, 0x1D, 0x06, 0xFA, 0x5A, 0xD3, 0xB5, 0x69, 0xCB, 0xCB, 0x43, 0x2A,
  0x80, 0xD4, 0x17, 0x8D, 0x13, 0x8D, 0x0B, 0xF6, 0xCC, 0xA1, 0x05, 0x9F, 0x51, 0x47, 0x9C, 0xF6,
  0x4B, 0x04, 0x2A, 0x03, 0xA1, 0x19, 0xE5, 0xC9, 0xFA, 0xDA, 0xCE, 0xC6, 0x6D, 0x82, 0xEC, 0x03,
  0x76, 0xC2, 0x38, 0x91, 0xBE, 0xAF, 0x65, 0xC0, 0xC9, 0x5A, 0x9E, 0x01, 0x06, 0xD1, 0x6F, 0x8B,
  0xE1, 0x19, 0x82, 0xC2, 0xE8, 0x69, 0x5E, 0x38, 0xB0, 0xFD, 0xED, 0xAC, 0xCF, 0x0F, 0xAD, 0x5C,
  0x5F, 0xA4, 0x9E, 0x44, 0x0C, 0x81, 0xF9, 0x04, 0x6C, 0x24, 0x61, 0x00, 0x83, 0x57, 0xAF, 0x38,
  0xC0, 0x15, 0x41, 0x9A, 0x13, 0x5A, 0x55, 0xB0, 0x72, 0x3D, 0xC0, 0x71, 0xBD, 0xEA, 0x01, 0x54,
  0xC7, 0x27, 0xEF, 0xE7, 0x06, 0x57, 0xE1, 0x0C, 0xA0, 0x39, 0xCA, 0x19, 0xC0, 0xED, 0xCF, 0x94,
  0x8B, 0x81, 0x2E, 0x73, 0xBE, 0xDF, 0x71, 0x57, 0xAD, 0x12, 0xE6, 0x0C, 0xA0, 0x39, 0x2C, 0x00,
  0xCD, 0x61, 0x01, 0x68, 0xCE, 0x98, 0x77, 0x01, 0xD2, 0x39, 0x47, 0x71, 0x95, 0xCB, 0xB8, 0x23,
  0x1B, 0xE7, 0xB1, 0xAE, 0xC9, 0x38, 0x03, 0x68, 0x4E, 0x68, 0xE7, 0x00, 0xF9, 0xAE, 0x07, 0x18,
  0x6F, 0x84, 0xB5, 0xAF, 0x57, 0x85, 0x33, 0x80, 0xE6, 0xB0, 0x00, 0x34, 0x87, 0x05, 0xA0, 0x39,
  0x2C, 0x00, 0xCD, 0x61, 0x01, 0x68, 0x4E, 0xD1, 0xFF, 0x47, 0x50, 0xA9, 0x31, 0xDE, 0xEA, 0x0F,
  0x38, 0x03, 0x68, 0x0E, 0xD7, 0x03, 0x14, 0x09, 0xAE, 0x07, 0x60, 0x22, 0xC1, 0x98, 0x33, 0x40,
  0xD4, 0xEA, 0x03, 0xC6, 0x2B, 0x61, 0x8D, 0x33, 0x67, 0x00, 0xCD, 0x61, 0x01, 0x68, 0x0E, 0x0B,
  0x40, 0x73, 0xB4, 0xAD, 0x07, 0xF0, 0xDA, 0xCF, 0xE7, 0xB6, 0x17, 0x1B, 0xAE, 0x07, 0x60, 0x42,
  0x81, 0xEB, 0x01, 0x8A, 0x04, 0xD7, 0x03, 0x30, 0x91, 0x40, 0xDB, 0xDF, 0x02, 0xBC, 0xCE, 0xF0,
  0x4B, 0xFD, 0x8C, 0xDF, 0x2F, 0x9C, 0x01, 0x34, 0x87, 0x05, 0xA0, 0x39, 0x2C, 0x00, 0xCD, 0x61,
  0x01, 0x68, 0x0E, 0x0B, 0x40, 0x73, 0x4A, 0xA6, 0x1E, 0xC0, 0xEB, 0xFF, 0xEE, 0x95, 0x1A, 0x5C,
  0x0F, 0xC0, 0x44, 0x02, 0xAE, 0x07, 0x28, 0x11, 0xB8, 0x1E, 0x80, 0x09, 0x05, 0x16, 0x80, 0xE6,
  0xB0, 0x00, 0x34, 0x47, 0xDB, 0x7A, 0x80, 0x52, 0x83, 0xEB, 0x01, 0x98, 0x50, 0x88, 0x4C, 0x3D,
  0x00, 0xE6, 0xE5, 0xE7, 0xB9, 0xB9, 0xFB, 0x6B, 0x59, 0x3F, 0xBC, 0xEC, 0xF2, 0x75, 0x1F, 0x19,
  0x4F, 0x1D, 0xFE, 0xDE, 0x97, 0x5D, 0xD8, 0x70, 0x06, 0xD0, 0x1C, 0x16, 0x80, 0xE6, 0xB0, 0x00,
  0x34, 0x87, 0x05, 0xA0, 0x39, 0xE3, 0x4A, 0x00, 0x77, 0x26, 0xFD, 0xBD, 0xD2, 0xC0, 0xAF, 0x5D,
  0xA1, 0xEE, 0x5D, 0x4C, 0xF2, 0xBE, 0x0B, 0xC8, 0x7D, 0xCD, 0x7A, 0xA1, 0x5E, 0x9B, 0x7E, 0x67,
  0xB2, 0x02, 0xAB, 0x6E, 0xAB, 0xC9, 0xBA, 0x66, 0xD1, 0xE8, 0x37, 0xA9, 0xFA, 0xB5, 0xB3, 0xC8,
  0x86, 0x29, 0xFE, 0xFF, 0x7E, 0x0C, 0xFB, 0x1C, 0xE9, 0x3B, 0x16, 0xC8, 0x4E, 0x86, 0xD7, 0x78,
  0x85, 0x3D, 0x9E, 0xE3, 0x22, 0x03, 0x2C, 0xBC, 0x1A, 0xD4, 0x91, 0x81, 0xB0, 0xC9, 0xC6, 0xB6,
  0xE3, 0xED, 0x81, 0xEC, 0x00, 0x60, 0xF3, 0xB1, 0x3D, 0x59, 0xC2, 0x30, 0x85, 0x81, 0xD5, 0xB7,
  0xD5, 0xE0, 0x9E, 0xEB, 0x6F, 0x0F, 0x64, 0x17, 0x55, 0x4A, 0x5E, 0x00, 0x0B, 0x93, 0x15, 0x58,
  0xED, 0x10, 0xD4, 0x0F, 0x8F, 0xB7, 0xE3, 0xAB, 0xBF, 0x8F, 0x2A, 0xDB, 0x0D, 0xF3, 0xDD, 0xE9,
  0xEE, 0x51, 0xC1, 0x35, 0x84, 0x81, 0xA7, 0xE7, 0x2E, 0xCB, 0x0A, 0xAE, 0x5F, 0xBB, 0xA8, 0x52,
  0xF2, 0x02, 0xC8, 0x0D, 0xAA, 0x45, 0x36, 0xB6, 0x74, 0xEF, 0x1D, 0x15, 0x54, 0xBF, 0x76, 0x23,
  0xF9, 0xEE, 0x74, 0x37, 0xB6, 0x76, 0xEF, 0x1D, 0x15, 0xDC, 0xBA, 0xB9, 0xCB, 0x02, 0xD9, 0x45,
  0x91, 0xBC, 0xAF, 0x01, 0x0A, 0x35, 0xE7, 0x0F, 0x33, 0x32, 0xA8, 0x00, 0xB0, 0xB5, 0x7B, 0xAF,
  0xE3, 0xFC, 0xEB, 0xD7, 0x2E, 0x97, 0x61, 0x9B, 0x86, 0x8A, 0x15, 0xD2, 0x7B, 0xA9, 0xD8, 0xE5,
  0xE2, 0x35, 0x5E, 0x61, 0x8F, 0x67, 0xC9, 0x67, 0x80, 0x5C, 0xFC, 0x2E, 0xBE, 0xFC, 0xDA, 0x85,
  0x75, 0xCF, 0xA8, 0x30, 0xEE, 0x04, 0xC0, 0xA8, 0xC1, 0x02, 0xD0, 0x1C, 0x16, 0x80, 0xE6, 0xB0,
  0x00, 0x34, 0xC7, 0xF1, 0x6D, 0x92, 0x00, 0x90, 0xEA, 0x6C, 0x74, 0x7C, 0x5D, 0x68, 0x54, 0xAA,
  0x80, 0xDF, 0x36, 0x37, 0xB9, 0xB6, 0x5B, 0xDF, 0x9E, 0x73, 0x6D, 0x37, 0x17, 0x4E, 0x2E, 0xAA,
  0xFF, 0x4B, 0x77, 0xBC, 0xEC, 0xDA, 0x1E, 0x14, 0x59, 0xE5, 0x50, 0xBA, 0xAA, 0x85, 0xDF, 0x1C,
  0xCA, 0x8C, 0x86, 0x05, 0xA0, 0x39, 0x2C, 0x00, 0xCD, 0x51, 0x3E, 0x09, 0x54, 0x7D, 0x33, 0x65,
  0x68, 0x2C, 0x2A, 0x76, 0x07, 0xC6, 0x46, 0x54, 0xC6, 0x91, 0x33, 0x80, 0xE6, 0xB0, 0x00, 0x34,
  0x87, 0x05, 0xA0, 0x39, 0x2C, 0x00, 0xCD, 0x61, 0x01, 0x68, 0x0E, 0x0B, 0x40, 0x73, 0x58, 0x00,
  0x9A, 0x23, 0x3F, 0x07, 0x20, 0x0C, 0x40, 0x60, 0x62, 0x58, 0x0F, 0x96, 0x9D, 0x4D, 0x0F, 0x23,
  0xFB, 0x2D, 0x42, 0x17, 0xF2, 0x3C, 0x3E, 0xE7, 0x65, 0x0D, 0xF2, 0x0C, 0x20, 0x70, 0x4A, 0xE1,
  0x01, 0x4C, 0xB4, 0x91, 0xC6, 0xD2, 0x6D, 0x0A, 0xE8, 0x09, 0xA1, 0x23, 0x4C, 0x31, 0x20, 0x79,
  0x2C, 0xDD, 0x32, 0x40, 0x67, 0x28, 0x9D, 0x61, 0x0A, 0x8F, 0x21, 0xF6, 0xC9, 0x9A, 0xA4, 0x6B,
  0x00, 0xD3, 0xC4, 0x67, 0x56, 0x06, 0xEF, 0x01, 0x30, 0x43, 0xE9, 0xD4, 0x18, 0xF1, 0xAE, 0x96,
  0xF5, 0x68, 0xFF, 0xD2, 0xEB, 0x09, 0x21, 0xFB, 0x17, 0x8E, 0x8C, 0x05, 0xA3, 0x43, 0xD6, 0x28,
  0xCD, 0x00, 0x3B, 0x1E, 0x69, 0x39, 0x09, 0xE0, 0xE3, 0x30, 0x7A, 0xC4, 0x14, 0x0E, 0x01, 0x6C,
  0xDB, 0x5D, 0xD9, 0xDC, 0x2B, 0x6B, 0x77, 0xDF, 0x06, 0xDA, 0xF6, 0x6B, 0x00, 0xFA, 0xF3, 0xDD,
  0x29, 0xA6, 0x60, 0x9C, 0xCF, 0x98, 0x99, 0xD7, 0xDD, 0x0C, 0x5C, 0x05, 0x90, 0x5E, 0xB6, 0xF9,
  0x0F, 0x12, 0xF4, 0x38, 0x00, 0x2B, 0xAF, 0xDD, 0x62, 0x0A, 0x81, 0x2D, 0x04, 0x9E, 0xDC, 0xFD,
  0xE8, 0xD6, 0x3F, 0xDD, 0x8C, 0x3C, 0x0F, 0x82, 0x76, 0x56, 0xB6, 0xEE, 0x17, 0x10, 0x2F, 0x00,
  0x18, 0xFD, 0x27, 0xB4, 0x4C, 0x54, 0xB1, 0x89, 0xA8, 0xA9, 0xAD, 0xB2, 0x45, 0x3A, 0xF7, 0x0F,
  0xE3, 0xEB, 0x24, 0xB0, 0xAD, 0x6A, 0xD3, 0xFB, 0x20, 0x5A, 0x0E, 0x9E, 0x0E, 0x4A, 0x81, 0xF3,
  0x04, 0x51, 0xBD, 0x73, 0x69, 0x6B, 0xB3, 0x1F, 0x63, 0xDF, 0x47, 0xC1, 0xE9, 0xA5, 0xAD, 0xED,
  0x10, 0xE6, 0x6C, 0x02, 0xDE, 0x07, 0x90, 0x09, 0xDC, 0x3D, 0x26, 0x2C, 0x6C, 0x80, 0x3E, 0xB1,
  0xCC, 0xCC, 0xBC, 0x9D, 0x55, 0x9B, 0xA4, 0xDB, 0xBE, 0x5C, 0x94, 0x4A, 0xC2, 0xD2, 0x95, 0xCD,
  0x7D, 0x00, 0x9E, 0x5B, 0xD1, 0xB5, 0xF6, 0x9D, 0x18, 0x65, 0xAA, 0x09, 0xA2, 0x0A, 0xC0, 0x2C,
  0x10, 0xA6, 0x87, 0x79, 0x6C, 0xCC, 0x38, 0x30, 0x74, 0x54, 0xDF, 0x0B, 0x42, 0x0F, 0x01, 0x9D,
  0xB6, 0x61, 0xB6, 0xBB, 0xAD, 0xF6, 0x19, 0x86, 0x61, 0x18, 0x86, 0x61, 0x18, 0x86, 0x61, 0x86,
  0xF8, 0x17, 0xDE, 0x1A, 0xA1, 0xFA, 0xD8, 0xAA, 0xBF, 0x34, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45,
  0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82
};



/////////// Callback: notify user when the configuration file is saved  /////////////
void onConfigSaved(const char* path) {
  Serial.print("\n[Config] File salvato: ");
  Serial.println(path); 
}

////////////////////////////////  Filesystem  /////////////////////////////////////////
bool startFilesystem() {
  if (FILESYSTEM.begin()){
    server.printFileList(FILESYSTEM, "/", 2);
    return true;
  }
  else {
    Serial.println("ERROR on mounting filesystem. It will be reformatted!");
    FILESYSTEM.format();
    ESP.restart();
  }
  return false;
}

////////////////////  Load application options from filesystem  ////////////////////
bool loadOptions() {
  if (FILESYSTEM.exists(server.getConfiFileName())) {
    server.getOptionValue(LED_LABEL, ledPin);
    server.getOptionValue(BOOL_LABEL, boolVar);
    server.getOptionValue(BOOL_LABEL2, boolVar2);
    server.getOptionValue(LONG_LABEL, longVar);
    server.getOptionValue(FLOAT_LABEL, floatVar);
    server.getOptionValue(STRING_LABEL, stringVar);
    server.getDropdownSelection(dayOfWeek);    
    server.getSliderValue(brightness);
    server.closeSetupConfiguration();  // Close configuration to free resources

    Serial.println("\nThis are the current values stored: \n");
    Serial.print("LED pin value: "); Serial.println(ledPin);    
    Serial.print("Bool value: "); Serial.println(boolVar ? "true" : "false");
    Serial.print("Bool value2: "); Serial.println(boolVar2 ? "true" : "false");
    Serial.print("Long value: "); Serial.println(longVar);
    Serial.print("Float value: "); Serial.println(floatVar);
    Serial.print("String value: "); Serial.println(stringVar);
    Serial.print("Dropdown selected value: "); Serial.println(days[dayOfWeek.selectedIndex]);
    Serial.print("Slider value: "); Serial.println(brightness.value);
    return true;
  }
  else
    Serial.println(F("Config file not exist"));
  return false;
}


////////////////////////////  HTTP Request Handlers  ////////////////////////////////////
void handleLoadOptions() {
  server.send(200, "text/plain", "Options loaded");
  loadOptions();
  Serial.println("Application option loaded after web request");
}


void setup() {
  Serial.begin(115200);

  // FILESYSTEM INIT
  if (startFilesystem()){
    // Load configuration (if not present, default will be created when webserver will start)
    loadOptions();
  }

  // Firmware version is set to compile time internally with a macro, but you can set a custom string
  // Custom firmware version -> Major.Minor.Build
  // Build is a packed 32-bit value; for display use unpack or keep compact.
  String version = "1.0." + String(BUILD_TIMESTAMP);
  server.setFirmwareVersion(version);

  // Set custom title for /setup page
  server.setSetupPageTitle("Custom Options Example");

  // Set custom logo for /setup page (uncomment one of the lines below to test)
  // server.setSetupPageLogo(custom_logo_svg);  // Use SVG text directly
  server.setSetupPageLogo(custom_logo, sizeof(custom_logo), "image/png");  // Use binary image data (PNG, JPEG, GIF, or gzipped SVG)

  // Try to connect to WiFi (will start AP if not connected after timeout)
  if (!server.startWiFi(10000)) {
    Serial.println("\nWiFi not connected! Starting AP mode...");
    WiFiConnectParams params ("ESP_AP", "123456789");            
    params.config.local_ip = IPAddress(192, 168, 1, 1);
    params.config.gateway = IPAddress(192, 168, 1, 1);
    params.config.subnet = IPAddress(255, 255, 255, 0);    
    server.startCaptivePortal(params, "/setup");
  }

  // Add custom page handler
  server.on("/reload", HTTP_GET, handleLoadOptions);

  // Configure /setup page and start Web Server
  server.addOptionBox("My Options");

  // boolean options can be grouped or left inline by passing `grouped`
  // as the fourth argument (hidden is the third, preserving old sketches):
  // grouped = true  (default) → all switches collected in a row
  // grouped = false            → option appears exactly where added
  // server.addOption(BOOL_LABEL, boolVar);               // grouped
  // server.addOption(BOOL_LABEL, boolVar, false);        // hidden=false, grouped=true
  // server.addOption(BOOL_LABEL, boolVar, false, false); // not grouped

  server.addHTML(reload_btn_htm, "buttons", /*overwrite*/ false);
  server.addJavascript(reload_btn_script, "script", /*overwrite*/ false);
  server.addOption(BOOL_LABEL, boolVar, false, false);
  server.addOption(LED_LABEL, ledPin);
  server.addComment(LED_LABEL, "Select the GPIO for the LED");
  server.addOption(LONG_LABEL, longVar);
  server.addComment(LONG_LABEL, "Large integer value");
  server.addOption(FLOAT_LABEL, floatVar, 1.0, 100.0, 0.01);
  server.addComment(FLOAT_LABEL, "Adjust between 1 and 100");
  server.addOption(STRING_LABEL, stringVar);
  server.addComment(STRING_LABEL, "Small text string");
  server.addOption(BOOL_LABEL2, boolVar2, false, false);
  server.addComment(BOOL_LABEL2, "Second boolean setting");
  server.addDropdownList(dayOfWeek);
  server.addSlider(brightness);  

  bool boolLED1ENABLE, boolLED2ENABLE, boolLED3ENABLE, boolLED4ENABLE;
  byte byteLED1PIN, byteLED2PIN, byteLED3PIN, byteLED4PIN;
  server.addOptionBox("LEDs");
  server.addOption("LED1 enable", boolLED1ENABLE, "Enable LED1");
  server.addOption("LED1 PIN", byteLED1PIN);
  server.addOption("LED2 enable", boolLED2ENABLE , "Enable LED2");
  server.addOption("LED2 PIN", byteLED2PIN);
  server.addOption("LED3 enable", boolLED3ENABLE, "Enable LED3");
  server.addOption("LED3 PIN", byteLED3PIN);
  server.addOption("LED4 enable", boolLED4ENABLE, "Enable LED4");
  server.addOption("LED4 PIN", byteLED4PIN);


  // Enable ACE FS file web editor and add FS info callback function
  server.enableFsCodeEditor();

  // set /setup and /edit page authentication
  // server.setAuthentication("admin", "admin");

  // Inform user when config.json is saved via /edit or /upload
  server.setConfigSavedCallback(onConfigSaved);

  // Start server
  server.begin();
  Serial.print(F("\nESP Web Server started on IP Address: "));
  Serial.println(server.getServerIP());
  Serial.println(F(
      "\nThis is \"customOptions.ino\" example.\n"
      "Open /setup page to configure optional parameters.\n"
      "Open /edit page to view, edit or upload example or your custom webserver source files."
  ));

  Serial.print(F("Compile time (default firmware version): "));
  Serial.println(BUILD_TIMESTAMP);
}

void loop() {
  server.run(); // Handle client requests

  // Keep BOOT_PIN pressed 5 seconds to clear application options
  static uint32_t buttonPressStart = 0;
  static bool buttonPressed = false;
  
  if (digitalRead(BOOT_PIN) == LOW) {
    if (!buttonPressed) {
      buttonPressed = true;
      buttonPressStart = millis();
    } 
    else if (millis() - buttonPressStart >= 5000) {
      Serial.println("\nClearing application options...");
      server.clearConfigFile();
      delay(1000);
      ESP.restart();
    }
  } else {
    buttonPressed = false;
  }

  // Nothing to do here, just a small delay for task yield
  delay(10);  
}
