/*************************************************************************************************************************************************************
*  Sous Programme : ServeurWEB 2 pages WEB  --- index.htm // configIP.htm
*  Fonction : Serveur WEB avec echange d'information en javascript AJAX
*  Version 3
************************************************************************************************************************************************************
*  Entree :
*  boolean loginWEB;                                                  // ON / OFF : Login et Password du site WEB
*  char loginPasswordWEB[40];                                         // dXNlcjpwYXNz = 'user:pass' (user:pass) base64  /////  (admin:01_Admin YWRtaW46MDFfQWRtaW4=)   https://www.base64encode.org/
*
*  Sortie : client.Print ---> Ethernet HTML
*  Variables (configIP)
*  Variables modifiees (via AJAX ajax_outputs) :
*   conf.dhcp         (boolean)   -- Arduino configure en IP STATC = 0 // Arduino configure en IP DHCP = 1
*   conf.ip[4]        (uint8_t)   -- nouvelle adresse IP
*   conf.subnet[4]    (uint8_t)   -- nouveau masque de sous-reseau
*   conf.gateway[4]   (uint8_t)   -- nouvelle passerelle
*   conf.loginWEB     (boolean)   -- activation authentification WEB
*   conf.led          (boolean)   -- 0=OFF / 1=ON (via BoutonON/BoutonOFF)
************************************************************************************************************************************************************/
// Declaration Nom des Fichers WEB *.html en Partition SD

const char * fichierSD_index  = "index.htm";                          // Nom du Fichier copier dans la partition SD !!! Voir procedure pour televerser le fichier !!!!
const char * fichierSD_ConfIP = "ConfIP.htm";                         // Nom du Fichier copier dans la partition SD !!! Voir procedure pour televerser le fichier !!!!

// Variable Moteur Serveur WEB
#define REQ_BUF_SZ   512                                              // taille de la memoire tampon utilisee pour capturer les requetes HTTP
char HTTP_req[REQ_BUF_SZ] = {0};                                      // buffered HTTP request stored as null terminated string
int req_index = 0;                                                    // index into HTTP_req buffer
unsigned long previousMillisWEB = 0;                                  // TimeOut Serveur WEB : variable pour un break dans la boucle du serveur WEB 
char c = 0;                                                           // caractere recu pas le client
//EthernetServer server(80);                                          // PORT du serveur WEB Definit dans prog principale
//boolean etatServeurWEB = 0;                                         // Variable connexion au serveur WEB --> definit dans LCD -- Permet de detecter serveur WEB actif

// Declaration Fonctions
void StrClear(char *str, int taille);                                 // Efface string
char StrContains(char *str, const char *sfind);                       // Detect chaine de caractere
void PageWEB(EthernetClient &client);                                 // Gestion Pages WEB / AJAX
void SendFile(EthernetClient &client, const char *fichierSD);         // 

/*************************************************************************************************************************************************************
* Sous Programme : ServeurWEB
*=============================================================================================================
* Fonction   : Point d'entree du serveur WEB -- accepte un client HTTP entrant,
*              gere l'authentification Basic (Base64) et route vers PageWEB()
*-----------------------------------------------------------------------------
* Entree     : EthernetClient &client  -- client HTTP fourni par server.available()
*-----------------------------------------------------------------------------
* Sortie     : Appel de PageWEB(client) si authentification OK
*              HTTP 401 Unauthorized si authentification refusee
*              cmdLine.println -- messages de debug dans le terminal
*-----------------------------------------------------------------------------
* Variables modifiees :
*   req_index         (int)           -- index courant dans le buffer HTTP_req
*   HTTP_req[]        (char[512])     -- buffer de la requete HTTP recue
*   previousMillisWEB (unsigned long) -- horodatage pour le timeout (5 secondes)
*   currentLineIsBlank(boolean)       -- detecte la fin des en-tetes HTTP
*-----------------------------------------------------------------------------
* Machine d'etat :
*   client connecte ?
*     OUI -> lire octets HTTP dans HTTP_req jusqu'a ligne vide
*       conf.loginWEB == 1 ?
*         OUI -> loginPasswordWEB present dans HTTP_req ?
*                  OUI -> PageWEB(client)
*                  NON -> HTTP 401 Unauthorized
*         NON -> PageWEB(client) directement
*       Timeout > 5s -> flush + stop + break
*     NON -> rien
*-----------------------------------------------------------------------------
* Commande : appelee depuis loop() si conf.SrvWEBswitch == 1
*************************************************************************************************************************************************************/
void ServeurWEB(EthernetClient &client)
{
  if (client) {                                                                                                    // client obtenu?
    Serial.println();  Serial.println( F("ooooo Serveur WEB : Nouveau Client connecte ...."));                     // Si un nouveau client se connecte,imprimer un message sur le port serie
    previousMillisWEB = millis();
    boolean currentLineIsBlank = true;                                                                             // SRV WEB actif --> pour Affichage LCD
    //etatServeurWEB = 1;                                                                                            // Variable pour le LCD
    while (client.connected()) {
      // Sortie de la boucle while en cas de bloquage pendant une minute
      if ( millis() - previousMillisWEB >= 5 * 1000) {                                                             // Test le fonctionnement pendant 5sec (en ms : Exemple 2 min = 2*60*1000)
        Serial.println( F("oo Serveur WEB : TimeOut connexion !!!!"));
        client.flush();
        client.stop();
        break;
      }

      if (client.available()) {                                                                                    // donnees client disponibles pour lire lire 1 octet (caractere) du clientla derniere ligne de la demande du client est vide et se termine par \ n
        c = client.read();                                                                                         // repondre au client seulement apres la derniere ligne recue  Tamponner la premiere partie de la requete HTTP dans le tableau HTTP_req (chaine)
                                                                                                                   // laisse le dernier element dans le tableau de 0 a null termine la chaine (REQ_BUF_SZ - 1)
        if (req_index < (REQ_BUF_SZ - 1)) {
          HTTP_req[req_index] = c;                                                                                 // enregistrer le caractere de requete HTTP
          req_index++;
        }
        //Serial.print(c);                                                                                         // Impression du caractere de requete HTTP sur le moniteur serie
        if (c == '\n' && currentLineIsBlank) {                                                                     // la derniere ligne de la requete client est vide et se termine par \ n
                                                                                                                   // repond au client seulement apres la derniere ligne recue// open requested web page file
          for (int i = 0 ; i < req_index ; i++) {
              Serial.print( HTTP_req[i]);                                                                          // Impression du caractere de requete HTTP sur le moniteur serie
          }

          // ============================================================================================================================
          // BLOC AUTH : Verification des identifiants Basic Auth (Base64)
          // ----------------------------------------------------------------------------------------------------------------------------
          // Donnee traitee  : HTTP_req[]                -- en-tetes HTTP complets recus du navigateur
          //                                                contient "Authorization: Basic dXNlcjpwYXNz" si login present
          // Resultat        : si credential trouve      -> PageWEB(client)
          //                   sinon                     -> HTTP 401 Unauthorized (le navigateur affiche la boite login)
          // Variables entree: HTTP_req[]                   (char[512])  -- buffer de la requete HTTP
          //                   conf.loginPasswordWEB        (char[40])   -- credential Base64 attendu ex: "dXNlcjpwYXNz"
          // Variables sortie: PageWEB(client)           -- routage vers les pages si authentifie
          //                   client.println()          -- reponse HTTP 401 si echec
          // ============================================================================================================================
          if (conf.loginWEB == 1)  {                                                                               // Selecteur ON /OFF Login password
            if (strstr(HTTP_req, conf.loginPasswordWEB) != NULL)                                                   // checking if header is valid : dXNlcjpwYXNz = 'user:pass' (user:pass) base64 encode Finding the right credential string, then loads web page
            {                                                                                                      // https://www.base64encode.org/

              PageWEB(client);

            }
            // Utilisateur ou mot de passe incorrect, la requete HTTP echoue donc ...
            else  {
              client.println(F("HTTP/1.1 401 Unauthorized"));
              client.println(F("WWW-Authenticate: Basic realm=\"Secure\""));
              client.println(F("Content-Type: text/html"));
              client.println();
              client.println(F("<html>Authentication failed</html>"));
            } // Fin else IF Login / user

          } // Fin selecteur ON Login password
          else  {                                                                                                  // Selecteur OFF login password
            PageWEB(client);
          } // Fin selecteur Login Password

          //delay(10);

          // reinitialiser l'index du tampon et tous les elements du tampon a 0
          //Serial.println(F"Reset HTTP_req"));
          req_index = 0;
          StrClear(HTTP_req, REQ_BUF_SZ);
          //client.flush();
          client.stop();
          break;
        } // end if (c == '\n' && currentLineIsBlank)


        if (c == '\n') {                                                                                         // chaque ligne de texte recue du client se termine par \r \n
          // dernier caractere en ligne du texte recu Commencer une nouvelle ligne avec le prochain caractere lu
          currentLineIsBlank = true;
        }
        else if (c != '\r') {                                                                                    // un caractere de texte a ete recu du client
          currentLineIsBlank = false;
        }
      } // end if (client.available())
    } // end while (client.connected())
    //delay(10);                                                                                                 // donnez au navigateur le temps de recevoir les donnees
    //while (client.available()) client.read();
    //client.flush();
    client.stop();                                                                                               // close the connection
    Serial.println( F("ooooo Client Deconnecte (Fin boucle)"));
    Serial.println( F("-------------------------------------------------------"));
    Serial.println();
    Serial.print( F("> "));
  } // end if (client)
}

/*************************************************************************************************************************************************************
* Sous Programme : StrClear
*=============================================================================================================
* Fonction   : Efface un tableau de caracteres en mettant tous les elements a 0
*-----------------------------------------------------------------------------
* Entree     : char *str    -- pointeur vers le tableau a effacer
*              int taille   -- nombre d'octets a mettre a 0
*-----------------------------------------------------------------------------
* Sortie     : str[]        -- tous les elements mis a 0 (null)
*-----------------------------------------------------------------------------
* Variables modifiees :
*   str[0..taille-1]  -- mis a 0 octet par octet
*-----------------------------------------------------------------------------
* Utilisation : StrClear(HTTP_req, REQ_BUF_SZ) apres traitement de la requete
*************************************************************************************************************************************************************/
void StrClear(char *str, int taille)
{
  //Serial.print("taille : "); Serial.println(taille);
  for (int i = 0; i < taille; i++) {
    str[i] = 0;
  }
}

/*************************************************************************************************************************************************************
* Sous Programme : SendFile
*=============================================================================================================
* Fonction   : Lit un fichier sur la carte SD et l'envoie par blocs au client Ethernet
*              Envoi optimise par blocs de 512 octets (TAILLE_BUF)
*-----------------------------------------------------------------------------
* Entrees    : EthernetClient &client      -- client HTTP destination (navigateur)
*              const char *fichierSD       -- nom du fichier a lire sur la SD
*                                            ex: "index.htm" ou "ConfIP.htm"
*-----------------------------------------------------------------------------
* Sortie     : client.write(buffer, n)    -- envoi du contenu au navigateur
*              cmdLine.println            -- messages de progression dans le terminal
*-----------------------------------------------------------------------------
* Variables locales :
*   pageWeb     (FsFile)      -- objet fichier SdFat pour la lecture (O_RDONLY)
*   clientBuf[] (byte[512])   -- buffer de lecture par blocs (TAILLE_BUF=512)
*   n           (int)         -- nombre d'octets lus au dernier read()
*-----------------------------------------------------------------------------
* Algorithme :
*   1. Verifier l'existence du fichier (sd.exists)
*   2. Ouvrir en lecture seule (O_RDONLY)
*   3. Boucle : lire 512 octets -> envoyer au client -> repeter jusqu'a EOF (n<=0)
*   4. Fermer le fichier
*************************************************************************************************************************************************************/
void SendFile(EthernetClient &client, const char *fichierSD)
{
//void SendFile(EthernetClient &client, EthernetClient &clientTelnet, const char *fichierSD)

  // Verifie si le fichier existe sur la carte SD
  if (!sd.exists(fichierSD))
      {
        Serial.println( F("oo Fichier introuvable sur SD"));
        return;
      }

  #define TAILLE_BUF 512      // taille du buffer (multiple de 512 conseille pour SD)

  // Ouverture du fichier en lecture seule
  FsFile pageWeb = sd.open(fichierSD, O_RDONLY);

  if (!pageWeb)
      {
        Serial.println( F("oo Erreur ouverture fichier SD"));
        return;
      }

  byte clientBuf[TAILLE_BUF];

  Serial.println();
  Serial.print( F("Envoie Page WEB : "));
  Serial.println( fichierSD);

  // Lecture du fichier par blocs
  while (true)
      {
        int n = pageWeb.read(clientBuf, TAILLE_BUF);  // lit jusqu'a 512 octets

        if (n <= 0)                                   // fin de fichier
          break;

        client.write(clientBuf, n);                   // envoi au client Ethernet

        Serial.print( F("..."));                     // progression
      }

  // fermeture du fichier
  pageWeb.close();

  Serial.println();
  Serial.println( F("Fin envoi fichier"));
}


/*************************************************************************************************************************************************************
* Sous Programme : StrContains
*=============================================================================================================
* Fonction   : Recherche la sous-chaine sfind dans la chaine str
*              Equivalent simplifie de strstr() avec retour char (0 ou 1)
*-----------------------------------------------------------------------------
* Entrees    : char *str         -- chaine source (buffer HTTP_req)
*              const char *sfind -- chaine a rechercher
*                                   ex: "ajax_inputs", "BoutonON", loginPasswordWEB
*-----------------------------------------------------------------------------
* Sortie     : char -- 1 = sous-chaine trouvee / 0 = non trouvee
*-----------------------------------------------------------------------------
* Variables locales :
*   found  (unsigned int) -- nb de caracteres consecutifs correspondants
*   index  (unsigned int) -- position courante dans str
*   len    (unsigned int) -- longueur de str
*-----------------------------------------------------------------------------
* Algorithme :
*   Si sfind plus long que str    : retourner 0 immediatement
*   Parcourir str octet par octet :
*     str[index] == sfind[found]  ? -> found++
*     found == strlen(sfind)      ? -> retourner 1
*     sinon                       : found = 0
*************************************************************************************************************************************************************/
char StrContains(char *str, const char *sfind)
{
  // Serial.print( F("Start StrContains !!! chaine : "));
  unsigned int found = 0;
  unsigned int index = 0;
  unsigned int len;

  len = strlen(str);

  if (strlen(sfind) > len) {                               // longueur de la chaine http://koor.fr/C/cstring/strlen.wp
    return 0;
  }
  while (index < len) {
    if (str[index] == sfind[found]) {                      // Compare caracter par caractere les deux chaines
      found++;

      // Serial.print( str[index] );
      if (strlen(sfind) == found) {

        // Serial.println(); Serial.println( F("chaine : found") );
        return 1;
      }
    }
    else {
      found = 0;
    }
    index++;
  }

  // Serial.println(); Serial.println( F("chaine : not found") );
  return 0;
}

/*************************************************************************************************************************************************************
* Sous Programme : PageWEB
*=============================================================================================================
* Fonction   : Routeur de pages WEB -- analyse HTTP_req et aiguille vers la page
*              ou la reponse AJAX appropriee
*-----------------------------------------------------------------------------
* Entree     : EthernetClient &client  -- client HTTP destination
*              HTTP_req[]  (global)    -- buffer de la requete HTTP deja rempli
*-----------------------------------------------------------------------------
* Sortie     : client.print/println/write -- contenu HTTP/HTML/XML vers le navigateur
*              cmdLine.println            -- messages de debug dans le terminal
*-----------------------------------------------------------------------------
* Variables modifiees (via AJAX ajax_outputs) :
*   conf.dhcp         (boolean)   -- 0=IP fixe / 1=DHCP
*   conf.ip[4]        (uint8_t)   -- nouvelle adresse IP
*   conf.subnet[4]    (uint8_t)   -- nouveau masque de sous-reseau
*   conf.gateway[4]   (uint8_t)   -- nouvelle passerelle
*   conf.loginWEB     (boolean)   -- activation authentification WEB
*   conf.led          (boolean)   -- 0=OFF / 1=ON (via BoutonON/BoutonOFF)
*-----------------------------------------------------------------------------
* Machine d'etat (routage par analyse de HTTP_req) :
*
*   "ajax_outputs" dans HTTP_req ?
*     OUI -> decoder IP/MSR/GAT/LOG via strtok -> sauvegarder EEPROM -> ResetNow()
*
*   "ajax_inputs" dans HTTP_req ?
*     OUI -> repondre XML avec etat courant (DHCP, IP, MSR, GAT, LOG)
*
*   "ConfIP.htm" dans HTTP_req ?
*     OUI -> HTTP 200 + SendFile(ConfIP.htm)
*
*   "GET /" ou "index.htm" ou "BoutonON" ou "BoutonOFF" dans HTTP_req ?
*     OUI -> HTTP 200 + SendFile(index.htm)
*            "BoutonON"  -> conf.led=1 + digitalWrite HIGH + Datalogger()
*            "BoutonOFF" -> conf.led=0 + digitalWrite LOW  + Datalogger()
*-----------------------------------------------------------------------------
* Remarque : chaque branche se termine par return pour eviter les envois multiples
*************************************************************************************************************************************************************/
void PageWEB(EthernetClient &client)
{
  Serial.println(); Serial.println();
  // ============================================================================================================================
  // BLOC AJAX : Reception configuration IP (envoi depuis ConfIP.htm apres validation)
  // ----------------------------------------------------------------------------------------------------------------------------
  // Donnee traitee  : HTTP_req[]         -- requete HTTP brute ex: "GET /ajax_outputs&DHCP=0&IPA=192&...&LOG=0&nocache=xxx"
  // Resultat        : decodage des parametres IP/MSR/GAT/DHCP/LOG -> sauvegarde EEPROM -> ResetNow()
  // Variables entree: HTTP_req[]  (char[512])      -- buffer de la requete HTTP
  // Variables sortie: conf.dhcp   (boolean)        -- 0=IP fixe / 1=DHCP
  //                   conf.ip[4]  (uint8_t[4])     -- nouvelle adresse IP
  //                   conf.subnet[4](uint8_t[4])   -- nouveau masque de sous-reseau
  //                   conf.gateway[4](uint8_t[4])  -- nouvelle passerelle
  //                   conf.loginWEB (boolean)      -- activation login WEB
  // ============================================================================================================================
  if (strstr(HTTP_req, "ajax_outputs") != NULL) {

    //GET /ajax_outputs&DHCP=0&IPA=192&IPB=168&IPC=0&IPD=10&MSRA=255&MSRB=255&MSRC=255&MSRD=0&GATA=192&GATB=168&GATC=0&GATD=254&LOG=0&nocache=247665.43744572057 HTTP/1.1

    //if ( (StrContains(HTTP_req ,"GET /ajax_outputs")) )
    //    sscanf(HTTP_req, "GET /ajax_outputs&DHCP=%hhu&IPA=%hhu&IPB=%hhu&IPC=%hhu&IPD=%hhu&MSRA=%hhu&MSRB=%hhu&MSRC=%hhu&MSRD=%hhu&GATA=%hhu&GATB=%hhu&GATC=%hhu&GATD=%hhu&LOG=%hhu", &conf.dhcp, &conf.ip[0], &conf.ip[1], &conf.ip[2], &conf.ip[3], &conf.subnet[0], &conf.subnet[1], &conf.subnet[2], &conf.subnet[3], &conf.gateway[0], &conf.gateway[1], &conf.gateway[2], &conf.gateway[3], &conf.loginWEB );


    // Analyse de la chaine de caracter Fonction strtok :  http://koor.fr/C/cstring/strtok.wp
    boolean error = 0;
    int test = 0;
    const char * separators = "GET /ajax_outputs&DHCP=IPABCDMSRGATLOG";                            // on enleve de la chaine les caracter suivant Attention IP MSR GAT sans les chiffre !!!!
    char * strToken = strtok ( HTTP_req, separators );
    //Serial.print("strToken :" );   Serial.println(strToken );
    conf.dhcp  = atoi(strToken);

    for (int i = 0 ; i < 4 ; i++)
    {
      strToken = strtok ( NULL, separators );
      //Serial.println(strToken );
      test = atoi(strToken);
      //Serial.println(test);
      if ( test < 0 || test > 255 ) {
        error = 1;
        break;
      }
      conf.ip[i] = test;
    }
    for (int i = 0 ; i < 4 ; i++)
    {
      strToken = strtok ( NULL, separators );
      //Serial.println(strToken );
      test = atoi(strToken);
      if ( test < 0 || test > 255 ) {
        error = 1;
        break;
      }
      conf.subnet[i] = test;
    }
    for (int i = 0 ; i < 4 ; i++)
    {
      strToken = strtok ( NULL, separators );
      //Serial.println(strToken );
      test = atoi(strToken);
      if ( test < 0 || test > 255 ) {
        error = 1;
        break;
      }
      conf.gateway[i] = test;
    }
    strToken = strtok ( NULL, separators );
    //Serial.println(strToken );
    conf.loginWEB = atoi(strToken);

    if (error == 1)
    {
      SetDefaultConf(nullptr);
      Serial.println( F("ERROR !! Parametre entre Invalide !")); Serial.println();
      client.print(F("<p> ERROR !! Parametre entre Invalide !!!!!!!! <p> "));
    }


    PrintConf("1");                    // Affiche toute la configuration reseau
    SaveConfEEPROM(nullptr);
    delay(200);
    Serial.println( F("Enregistrement de la configuration IP en EEPROM : Ok!")); Serial.println();


    // Affiche dans le cadre vert aligne a gauche
    client.print(F("<p style=\"text-align:left\"> Configuration Enregistre"));
    client.print(F("<br> L'Arduino UNO R4 est accessible dans quelques instant a l'adresse IP : "));
    if ( conf.dhcp == 0)
    {
      client.print(conf.ip[0], DEC);   client.print(".");     client.print(conf.ip[1], DEC);     client.print(".");     client.print(conf.ip[2], DEC);     client.print(".");     client.print(conf.ip[3], DEC);
    }
    else client.print(F("DHCP OK !"));
    delay(500);
    client.print(F("<br><br> Reboot : Now ..............."));
    client.print(F("<br><br>Attendre 5 secondes<br><br></p>"));
    delay(200);
    client.flush();
    client.stop();
    Serial.println( F("------- RESET Arduino UNO R4  !!!! -------")); Serial.println();
    ResetNow(nullptr);
    return;
  } // Fin page HTML  AJAX
// =============================================================================
// BLOC ARDUINO — AJAX État LED (conf.led)
// À insérer dans votre gestionnaire de requêtes HTTP,
// à la suite du bloc "ajax_inputs" existant (conf IP).
//
// PRINCIPE :
//   Le navigateur envoie : GET /ajax_inputs?led&nocache=xxxxx HTTP/1.1
//   L'Arduino répond     : XML contenant <LED>0</LED> ou <LED>1</LED>
//
// PARAMÈTRE PARTAGÉ :
//   conf.led  (boolean) → état actuel de la LED
//
// INTERVALLE CÔTÉ NAVIGATEUR : 10 secondes (variable LED_POLL_MS dans index.htm)
//
// INTÉGRATION :
//   Ce bloc doit être placé AVANT le bloc "ajax_inputs" général (conf IP),
//   car StrContains("ajax_inputs?led") est plus spécifique.
//   L'ordre des if() détermine quelle branche est prise en premier.
// =============================================================================

// ============================================================================================================================
// BLOC AJAX : Etat LED — polling periodique depuis index.htm (toutes les LED_POLL_MS ms)
// ----------------------------------------------------------------------------------------------------------------------------
// Donnee traitee  : HTTP_req[]                     -- requete HTTP ex: "GET /ajax_inputs?led&nocache=xxxxx HTTP/1.1"
//                   "?led"                         -- parametre distinctif, separe ce bloc du bloc ajax_inputs general
// Resultat        : reponse XML renvoyee au navigateur  ex: <?xml...?><inputs><LED>1</LED></inputs>
// Variables entree: HTTP_req[]        (char[512])  -- buffer de la requete HTTP
//                   conf.led          (boolean)    -- etat courant de la LED (0=OFF / 1=ON)
// Variables sortie: client.print()                 -- flux HTTP/XML vers le navigateur
// ============================================================================================================================
if (strstr(HTTP_req, "ajax_inputs") != NULL && strstr(HTTP_req, "?led") != NULL) {

  Serial.println(F("oo Envoie Page WEB : AJAX : LED Status"));

  // --- En-tête HTTP ---
  // HTTP/1.1 200 OK  → requête traitée avec succès
  // Content-Type: text/xml → on envoie du XML (lu par responseXML côté JS)
  // Connection: keep-alive → maintient la connexion TCP (performant sur Arduino)
  client.println(F("HTTP/1.1 200 OK"));
  client.println(F("Content-Type: text/xml"));
  client.println(F("Connection: keep-alive"));
  client.println(); // Ligne vide obligatoire → sépare l'en-tête du corps

  // --- Corps : document XML ---
  // Structure attendue par index.htm :
  //   <?xml version="1.0"?>
  //   <inputs>
  //     <LED>1</LED>      ← 1 si allumée, 0 si éteinte
  //   </inputs>
  //
  // Du côté JavaScript (index.htm) :
  //   var val = this.responseXML.getElementsByTagName('LED')[0].childNodes[0].nodeValue;
  //   mettreAJourLed(val === '1');

  client.print(F("<?xml version = \"1.0\" ?>"));
  client.print(F("<inputs>"));
  client.print(F("<LED>"));
  client.print(conf.led ? "1" : "0" );   // true → "1", false → "0"
  client.print(F("</LED>"));
  client.print(F("</inputs>"));

  return; // Arrêt du traitement → ne pas tomber dans les autres blocs if()

} // Fin bloc AJAX LED


  // ============================================================================================================================
  // BLOC AJAX : Envoi etat configuration IP vers le navigateur (lecture depuis ConfIP.htm)
  // ----------------------------------------------------------------------------------------------------------------------------
  // Donnee traitee  : HTTP_req[]           -- requete HTTP ex: "GET /ajax_inputs&nocache=xxxxx HTTP/1.1"
  // Resultat        : reponse XML renvoyee au navigateur avec l'etat complet de la conf reseau
  //                   ex: <?xml...?><inputs><DHCP>0</DHCP><IPA>192</IPA>...<LOG>0</LOG></inputs>
  // Variables entree: HTTP_req[]  (char[512])      -- buffer de la requete HTTP
  //                   conf.dhcp   (boolean)        -- 0=IP fixe / 1=DHCP
  //                   conf.ip[4]  (uint8_t[4])     -- adresse IP courante
  //                   conf.subnet[4](uint8_t[4])   -- masque de sous-reseau courant
  //                   conf.gateway[4](uint8_t[4])  -- passerelle courante
  //                   conf.loginWEB (boolean)      -- etat login WEB
  // Variables sortie: client.print()               -- flux HTTP/XML vers le navigateur
  // ============================================================================================================================
  if (strstr(HTTP_req, "ajax_inputs") != NULL) {
    Serial.println( F("oo Envoie Page WEB : AJAX : Emission"));
    // send rest of HTTP header
    client.println(F("HTTP/1.1 200 OK"));
    client.println(F("Content-Type: text/xml"));
    client.println(F("Connection: keep-alive"));
    client.println();
    // send XML file containing input states

    client.print(F("<?xml version = \"1.0\" ?>"));
    client.print(F("<inputs>"));

    client.print(F("<DHCP>"));      client.print(conf.dhcp);        client.print(F("</DHCP>"));

    client.print(F("<IPA>"));       client.print(conf.ip[0]);       client.print(F("</IPA>"));
    client.print(F("<IPB>"));       client.print(conf.ip[1]);       client.print(F("</IPB>"));
    client.print(F("<IPC>"));       client.print(conf.ip[2]);       client.print(F("</IPC>"));
    client.print(F("<IPD>"));       client.print(conf.ip[3]);       client.print(F("</IPD>"));

    client.print(F("<MSRA>"));      client.print(conf.subnet[0]);   client.print(F("</MSRA>"));
    client.print(F("<MSRB>"));      client.print(conf.subnet[1]);   client.print(F("</MSRB>"));
    client.print(F("<MSRC>"));      client.print(conf.subnet[2]);   client.print(F("</MSRC>"));
    client.print(F("<MSRD>"));      client.print(conf.subnet[3]);   client.print(F("</MSRD>"));

    client.print(F("<GATA>"));      client.print(conf.gateway[0]);  client.print(F("</GATA>"));
    client.print(F("<GATB>"));      client.print(conf.gateway[1]);  client.print(F("</GATB>"));
    client.print(F("<GATC>"));      client.print(conf.gateway[2]);  client.print(F("</GATC>"));
    client.print(F("<GATD>"));      client.print(conf.gateway[3]);  client.print(F("</GATD>"));

    client.print(F("<LOG>"));       client.print(conf.loginWEB);    client.print(F("</LOG>"));

    client.print(F("</inputs>"));
    return;
  } // Fin page HTML AJAX

  // ============================================================================================================================
  // BLOC PAGE : Envoi de la page de configuration IP (ConfIP.htm)
  // ----------------------------------------------------------------------------------------------------------------------------
  // Donnee traitee  : HTTP_req[]           -- requete HTTP ex: "GET /ConfIP.htm HTTP/1.1"
  // Resultat        : envoi HTTP 200 + contenu du fichier ConfIP.htm depuis la carte SD
  // Variables entree: HTTP_req[]           (char[512])  -- buffer de la requete HTTP
  //                   fichierSD_ConfIP     (const char*)-- nom du fichier sur SD : "ConfIP.htm"
  // Variables sortie: client.println()                  -- en-tete HTTP vers le navigateur
  //                   SendFile(client, fichierSD_ConfIP)-- corps HTML vers le navigateur
  // ============================================================================================================================
  if (strstr(HTTP_req, "ConfIP.htm") != NULL) {

    Serial.println( F("Routine Envoie Page WEB : ConfigIP.htm"));
    Serial.println(); Serial.println( F("oo Envoie Entete de la page WEB"));                       // envoi d'une reponse http standard
    client.println(F("HTTP/1.1 200 OK"));
    client.println(F("Content-Type: text/html"));
    client.println(F("Connection: close"));                                                                            // la connection sera ferme apres l'achevement de la reponse
    //         client.println(F("Refresh: 2"));                                                                                 // actualise la page automatiquement toutes les secondes 2 sec
    client.println();
    SendFile(client, fichierSD_ConfIP);
  return;
} // Fin Page WEB configuration



// Page HTML : Boutons BoutonON / BoutonOFF (traitement AVANT envoi page) **********************
// Ces requetes arrivent sous la forme : GET /?BoutonON HTTP/1.1
// Elles doivent etre traitees AVANT le bloc "GET / " pour modifier conf.led
// avant que la page index.htm ne soit envoyee avec l'etat a jour.

// ============================================================================================================================
// BLOC BOUTON : Commande LED ON (clic bouton "Allumer" depuis index.htm)
// ----------------------------------------------------------------------------------------------------------------------------
// Donnee traitee   : HTTP_req[]                        -- requete HTTP ex: "GET /?BoutonON HTTP/1.1"
// Resultat         : conf.led = 1, sortie digitale HIGH, log datalogger si actif
//                    pas de return -> execution continue vers le bloc "GET / " pour renvoyer index.htm
// Variables entree : HTTP_req[]           (char[512])  -- buffer de la requete HTTP
// Variables sortie : conf.led             (boolean)    -- mis a 1 (LED allumee)
//                    pinled               (uint8_t)    -- broche mise a HIGH via digitalWrite()
// ============================================================================================================================
  if (strstr(HTTP_req, "GET /?BoutonON") != NULL) {
    conf.led = 1;
    digitalWrite(pinled, HIGH);
    Serial.println( F("LED est ON"));
    //client.print(F("<style>p { color: green;}</style><br><br><p><a>LED est ON</a></p>"));
    //client.print(F("<br><br><p><font color=\"green\"><font size=6><strong><a>LED est ON</a></strong></font></p>"));
    //client.print(F("<p style=\"color=green\"> LED est ON </p>"));
    //client.print(F("<p> <font color=\"green\"> LED est ON </font></p>"));   // ON couleur vert

    if (conf.dataloggerSwitch == 1 ) Datalogger();
    // pas de return : on laisse tomber dans le bloc "GET / " pour renvoyer la page
  }
// ============================================================================================================================
// BLOC BOUTON : Commande LED OFF (clic bouton "Eteindre" depuis index.htm)
// ----------------------------------------------------------------------------------------------------------------------------
// Donnee traitee  : HTTP_req[]           -- requete HTTP ex: "GET /?BoutonOFF HTTP/1.1"
// Resultat        : conf.led = 0, sortie digitale LOW, log datalogger si actif
//                   pas de return -> execution continue vers le bloc "GET / " pour renvoyer index.htm
// Variables entree: HTTP_req[]           (char[512])  -- buffer de la requete HTTP
// Variables sortie: conf.led             (boolean)    -- mis a 0 (LED eteinte)
//                   pinled               (uint8_t)    -- broche mise a LOW via digitalWrite()
// ============================================================================================================================
  if (strstr(HTTP_req, "GET /?BoutonOFF") != NULL) {
    conf.led = 0;
    digitalWrite(pinled, LOW);
    Serial.println( F("LED est OFF"));
    //client.print(F("<style>p { color: red;}</style><br><br><p><a>LED est OFF</a></p>"));
    //client.print(F("<br><br><p><font color=\"red\"><font size=6><strong><a>LED est OFF</a></strong></font></p>"));
    //client.print(F("<p style=\"color=red\"> LED est OFF </p>"));
    //client.print(F("<p><font color=\"red\"> LED est OFF </font></p>"));   // OFF couleur rouge

    if (conf.dataloggerSwitch == 1 ) Datalogger();
    // pas de return : on laisse tomber dans le bloc "GET / " pour renvoyer la page
  }

// Page HTML : favicon.ico → repondre 404 pour eviter d'envoyer index.htm ******************
// Le navigateur demande automatiquement /favicon.ico apres chaque chargement de page.
// Sans ce bloc, "GET /favicon.ico" contient "GET /" et declencherait l'envoi de index.htm.
// On repond 404 Not Found : le navigateur cesse de demander le favicon.

// ============================================================================================================================
// BLOC PAGE : Reponse 404 pour favicon.ico (requete automatique du navigateur)
// ----------------------------------------------------------------------------------------------------------------------------
// Donnee traitee  : HTTP_req[]                        -- requete HTTP ex: "GET /favicon.ico HTTP/1.1"
// Resultat        : reponse HTTP 404 Not Found -> le navigateur cesse de redemander le favicon
//                   sans ce bloc, "GET /favicon.ico" contient "GET / " et declencherait index.htm
// Variables entree: HTTP_req[]           (char[512])  -- buffer de la requete HTTP
// Variables sortie: client.println()                  -- en-tete HTTP 404 vers le navigateur
// ============================================================================================================================
  if (strstr(HTTP_req, "favicon.ico") != NULL) {
    Serial.println( F("oo Requete favicon.ico -> 404 (ignore)"));
    client.println(F("HTTP/1.1 404 Not Found"));
    client.println(F("Content-Type: text/plain"));
    client.println(F("Connection: close"));
    client.println();
    return;
  } // Fin bloc favicon.ico

// Page HTML : index.htm (page principale) ****************************************************
// Condition :  "GET / "    -> chemin racine exact   (espace apres / = fin de l'URL)
//              "GET /index.htm"  -> demande explicite de la page
//              "GET /?"    -> requetes avec parametres (?BoutonON, ?BoutonOFF, etc.)
// IMPORTANT :  "GET / " avec espace FINAL evite que "GET /favicon.ico" ou "GET /ConfIP.htm"
//              tombent dans ce bloc. "GET /" sans espace attraperait tout.
// ============================================================================================================================
// BLOC PAGE : Envoi de la page principale index.htm
// ----------------------------------------------------------------------------------------------------------------------------
// Donnee traitee  : HTTP_req[]           -- requete HTTP, l'une des formes suivantes :
//                     "GET / "           -- chemin racine exact (espace apres / = fin URL)
//                     "GET /index.htm"   -- demande explicite de la page
//                     "GET /?"           -- requete avec parametre (BoutonON/OFF deja traites)
// Resultat        : envoi HTTP 200 + contenu du fichier index.htm depuis la carte SD
// Variables entree: HTTP_req[]           (char[512])   -- buffer de la requete HTTP
//                   fichierSD_index      (const char*) -- nom du fichier sur SD : "index.htm"
// Variables sortie: client.println()                   -- en-tete HTTP vers le navigateur
//                   SendFile(client, fichierSD_index)  -- corps HTML vers le navigateur
// ============================================================================================================================
  if (strstr(HTTP_req, "GET / ") != NULL || strstr(HTTP_req, "GET /index.htm") != NULL || strstr(HTTP_req, "GET /?") != NULL) {
    Serial.println( F("oo Routine Envoie Page WEB : index.html"));
    Serial.println(); Serial.println( F("oo Envoie Entete de la page WEB"));                     // envoi d'une reponse http standard
    client.println(F("HTTP/1.1 200 OK"));
    client.println(F("Content-Type: text/html"));
    client.println(F("Connection: close"));                                                       // la connection sera ferme apres l'achevement de la reponse
    //         client.println(F("Refresh: 2"));                                                   // actualise la page automatiquement toutes les secondes 2 sec
    client.println();
    SendFile(client, fichierSD_index);
    return;
  } // Fin page HTML index.htm



// ***********************************************************************************************************************
// ICI on peut placer une autre pages WEB



} // FIN pages WEB
