/*********************************************************************************************************************
 *
 *   ██████╗ ███╗   ███╗██████╗ ██╗     ██╗███╗   ██╗███████╗
 *  ██╔════╝ ████╗ ████║██╔══██╗██║     ██║████╗  ██║██╔════╝
 *  ██║      ██╔████╔██║██║  ██║██║     ██║██╔██╗ ██║█████╗
 *  ██║      ██║╚██╔╝██║██║  ██║██║     ██║██║╚██╗██║██╔══╝
 *  ╚██████╗ ██║ ╚═╝ ██║██████╔╝███████╗██║██║ ╚████║███████╗
 *   ╚═════╝ ╚═╝     ╚═╝╚═════╝ ╚══════╝╚═╝╚═╝  ╚═══╝╚══════╝
 *
 *  CmdLine — Documentation d'utilisation
 *  Version v24 — addCommands() : second tableau de commandes utilisateur optionnel
 *  Fichiers : CmdLine.h  /  CmdLine.cpp  /  CmdLineKey.h
 *
 *  Auteur   : Biechy Jean-Marc — Ecole d'Informatique Institution Saint-Jean Colmar France 2026
 *
 *********************************************************************************************************************/

/*====================================================================================================================
 *  NOUVEAUTÉ v24 — addCommands() : SECOND TABLEAU DE COMMANDES UTILISATEUR
 *====================================================================================================================
 *
 *  PROBLÈME OBSERVÉ
 *  ─────────────────
 *  Dans IoToS, deux tableaux de commandes coexistent :
 *
 *    const cmd_t commands[]      → commandes système (Shell_CmdLine_SD.h)
 *    const cmd_t user_commands[] → commandes utilisateur (IoToS_User.h)
 *
 *  cmdLine.begin() n'acceptait qu'un seul tableau. Les approches envisagées
 *  pour fusionner les deux (macro CONCAT, tableau de pointeurs) présentaient
 *  des contraintes sur l'ordre des #include ou nécessitaient une modification
 *  invasive de l'architecture du sketch.
 *
 *  SOLUTION v24
 *  ─────────────
 *  Ajout de la méthode addCommands() dans CmdLine.h et CmdLine.cpp.
 *  La recherche de commande dans processCommand() et tabComplete()
 *  parcourt d'abord commands[] (système), puis user_commands[] (utilisateur).
 *  Les deux tableaux restent indépendants — aucune fusion, aucune macro.
 *
 *  APPEL DANS LE SKETCH
 *  ─────────────────────
 *  // AVANT v24 — un seul tableau possible :
 *  cmdLine.begin(commands, countof(commands));
 *
 *  // DEPUIS v24 — second tableau optionnel :
 *  cmdLine.begin(commands,      countof(commands));
 *  cmdLine.addCommands(user_commands, countof(user_commands));
 *
 *  RÉTROCOMPATIBILITÉ TOTALE
 *  ──────────────────────────
 *  Si addCommands() n'est pas appelé, _user_commands reste nullptr.
 *  processCommand() et tabComplete() fonctionnent exactement comme en v23.
 *  Aucune modification requise dans les sketches existants.
 *
 *  ORDRE DE RECHERCHE
 *  ───────────────────
 *
 *    Commande saisie par l'utilisateur
 *          │
 *          ▼
 *    Parcours commands[]          ← tableau système (toujours présent)
 *          │
 *    Trouvé ──────────────────►  Exécuter et return
 *          │
 *    Non trouvé
 *          │
 *          ▼
 *    _user_commands != nullptr ?  ← addCommands() a-t-il été appelé ?
 *          │
 *    OUI → Parcours user_commands[]
 *          │
 *    Trouvé ──────────────────►  Exécuter et return
 *          │
 *    Non trouvé
 *          │
 *          ▼
 *    println("Invalid command")
 *
 *  COMPLÉTION TAB
 *  ───────────────
 *  tabComplete() est également étendu :
 *    - Comptage des matchs : parcours commands[] + user_commands[]
 *    - Affichage liste N matchs : toutes les correspondances des deux tableaux
 *    - Cycle Re-TAB : séquence commands[] puis user_commands[]
 *  Les commandes système apparaissent en premier dans la liste et le cycle.
 *
 *====================================================================================================================
 *  FICHIERS DE LA LIBRAIRIE
 *====================================================================================================================
 *
 *  CmdLineKey.h     Sélection de plateforme, inclusion librairie réseau,
 *                   codes touches (KEY_xxx), machine d'état TelnetState,
 *                   constantes IAC Telnet.
 *                   → INCLUS AUTOMATIQUEMENT par CmdLine.h
 *
 *  CmdLine.h        Classe CmdLine, constantes paramétrables (#define),
 *                   structure CanalState, déclarations publiques/privées.
 *
 *  CmdLine.cpp      Implémentation complète de toutes les méthodes.
 *
 *====================================================================================================================
 *  PLATEFORMES SUPPORTÉES
 *====================================================================================================================
 *
 *  Plateforme               Connexion réseau    Librairie requise
 *  ──────────────────────   ─────────────────   ────────────────────────────
 *  Arduino UNO R4 Minima    Telnet TCP           Ethernet@2.0.2
 *  + Shield Ethernet W5500  port 23
 *
 *  ESP8266                  Telnet TCP           ESP8266WiFi (core incluse)
 *                           port 23
 *
 *  ESP32                    Telnet TCP           WiFi (core incluse)
 *                           port 23
 *
 *  ESP32                    Bluetooth Serial     BluetoothSerial (core incluse)
 *                           (pas de port TCP)
 *
 *====================================================================================================================
 *  ARCHITECTURE 3 CANAUX (inchangée depuis v22)
 *====================================================================================================================
 *
 *  cmdLine.print("texte") — ou — cmdLine.print(hexByte) — ou — cmdLine.print(42)
 *       │
 *       ├──► _stream.print()    → Canal 1 : Serial / SerialBT
 *       ├──► _c->print()        → Canal 2 : Telnet TCP (si client connecté)
 *       └──► _btStream->print() → Canal 3 : Bluetooth SerialBT (si activé v22)
 *
 *====================================================================================================================
 *  TABLEAU DES SURCHARGES print / println (inchangé depuis v23)
 *====================================================================================================================
 *
 *  Surcharge                           Définie dans   Depuis
 *  ──────────────────────────────────  ─────────────  ──────
 *  println()                           .cpp           v16
 *  print(const char *str)              .cpp           v23
 *  println(const char *str)            .cpp           v23
 *  print(const __FlashStringHelper*)   .cpp           v16
 *  println(const __FlashStringHelper*) .cpp           v16
 *  print<T>(T a)          [template]   .h             v16
 *  println<T>(T a)        [template]   .h             v16
 *  print(long, int base)               .cpp           v21
 *  println(long, int base)             .cpp           v21
 *  print(unsigned long, int base)      .cpp           v21
 *  println(unsigned long, int base)    .cpp           v21
 *  write(const uint8_t*, size_t)       .cpp           v21
 *
 *  Règle de résolution du compilateur C++ (du plus prioritaire au moins) :
 *    1. Surcharge exacte non-template → const char*, F(), long+base...
 *    2. Template générique T          → String, int, float, bool...
 *  Depuis v23 : char* résolu par surcharge exacte (1). Inchangé en v24.
 *
 *====================================================================================================================
 *  MEMBRES PRIVÉS AJOUTÉS EN v24
 *====================================================================================================================
 *
 *  Dans CmdLine.h — section membres privés :
 *
 *    const cmd_t *_user_commands = nullptr;  // Tableau utilisateur (optionnel)
 *    size_t       _user_num      = 0;        // Nombre d'entrées (0 = inactif)
 *
 *  Initialisés à nullptr/0 → comportement v23 si addCommands() non appelé.
 *
 *====================================================================================================================
 *  HISTORIQUE DES VERSIONS
 *====================================================================================================================
 *
 *  v24  Ajout addCommands(const cmd_t *cmds, size_t n).
 *       Contexte IoToS : deux tableaux coexistent (commands[] système et
 *       user_commands[] utilisateur). addCommands() enregistre le second
 *       tableau sans fusion ni macro. processCommand() : second parcours
 *       sur _user_commands après _commands. tabComplete() : comptage,
 *       affichage et cycle Re-TAB étendus aux deux tableaux en séquence.
 *       Rétrocompatibilité totale : _user_commands = nullptr si non appelé.
 *       FIX v24 : CmdLine.h (déclaration + membres privés) + CmdLine.cpp
 *       (addCommands, processCommand, tabComplete). CmdLineKey.h : version
 *       mise à jour uniquement.
 *
 *  v23  Ajout surcharges explicites print(const char*) / println(const char*).
 *       Cas d'usage : formatage hexadécimal sprintf(buf, "%02X", val) + print(buf).
 *       Avant v23 : T=char* passait par le template, ce qui fonctionnait mais
 *       sans garantie de résolution en présence des autres surcharges.
 *       Crash ESP32 observé (StoreProhibited, EXCVADDR=0x0) dans ce contexte.
 *       FIX v23 : déclaration dans CmdLine.h + implémentation dans CmdLine.cpp.
 *       Architecture BT 3 canaux inchangée. Aucune autre modification.
 *
 *  v22  CORRECTION BUG retour Bluetooth absent — 3 passes successives.
 *       Passe 1 : Serial hardcodé → _stream (print/println/write dans .cpp et templates .h).
 *       Passe 2 : ajout 3ème canal _btStream (Stream*) + setBluetoothOutput().
 *       Passe 3 : BluetoothSerial* → Stream* (conflit symboles WiFi/BT résolu).
 *
 *  v21  Ajout print(long, int base) / println(long, int base) / write(buf, len).
 *       Compatible Serial.print(val, DEC/HEX/OCT/BIN).
 *
 *  v20  Multi-plateforme : UNO R4, ESP8266, ESP32 WiFi, ESP32 Bluetooth.
 *       Fichier CmdLineKey.h séparé. Renommage CmdLineTelnet_UNOR4 → CmdLine.
 *       updateTelnet() → updateNetwork(). _clientConnected() abstrait.
 *
 *  v19  Correction bug casse — cmdStrcmpLower() / cmdStrncmpLower().
 *
 *  v18  setEcho(bool) / getEcho(). CMDLINE_ECHO_DEFAULT. HISTORY_SIZE renommé.
 *
 *  v17  Documentation complète. CMDLINE_CASE_INSENSITIVE.
 *
 *  v16  Réécriture basée sur Terminal.cpp (rweather, MIT).
 *       Machine d'état Telnet 9 états. Timeout ESC 40ms. Backspace "\b \b".
 *
 *====================================================================================================================
 *  FICHIERS MODIFIÉS EN v24
 *====================================================================================================================
 *
 *  CmdLine.h
 *    - En-tête : version v24
 *    - Membres privés : _user_commands (const cmd_t*) et _user_num (size_t) ajoutés
 *    - Section publique : déclaration addCommands(const cmd_t *cmds, size_t n)
 *    - Commentaire addCommands() : description + VAR modifiées + FIX v24
 *
 *  CmdLine.cpp
 *    - En-tête : version v24
 *    - Nouvelle fonction : addCommands() — enregistre _user_commands et _user_num
 *    - processCommand() : second parcours sur _user_commands après _commands
 *      "Invalid command" déclenché seulement si les deux tableaux sont épuisés
 *    - tabComplete() : trois zones étendues (comptage, affichage liste, Re-TAB)
 *      Système prioritaire dans le cycle ; variable done pour sortie propre
 *    - Bloc FIX v24 en fin de fichier
 *
 *  CmdLineKey.h
 *    - En-tête : version v24
 *    (aucune modification fonctionnelle)
 *
 *====================================================================================================================
 *  USAGE — EXEMPLE COMPLET UNO R4 Minima + IoToS (nouveau en v24)
 *====================================================================================================================
 *
 *  // ── Dans IoToS_User.h ────────────────────────────────────────────────────────
 *
 *  void PrintHelp(const char *arg);
 *  void PrintConf_user(const char *arg);
 *
 *  const cmd_t user_commands[] = {
 *    {"help",   PrintHelp},   {"man",   PrintHelp},
 *    {"?",      PrintHelp},   {"h",     PrintHelp},
 *    {"print",  PrintConf},   {"conf",  PrintConf},
 *    {"info",   PrintConf},   {"p",     PrintConf},
 *  };
 *
 *  // ── Dans IoToS_Boot_Driver.h (setup) ─────────────────────────────────────────
 *
 *  cmdLine.begin(commands, countof(commands));
 *  cmdLine.addCommands(user_commands, countof(user_commands));
 *
 *  // ── Dans Shell_CmdLine_SD.h ───────────────────────────────────────────────────
 *
 *  const cmd_t commands[] = {
 *    {"save",    SaveConfEEPROM},
 *    {"reset",   ResetNow},
 *    {"netstat", Netstat},
 *    // ... toutes les commandes système IoToS
 *  };
 *
 *  // ── Dans le sketch .ino ──────────────────────────────────────────────────────
 *
 *  #include <IoToS_Firmware.h>   // inclut Shell_CmdLine_SD.h → commands[]
 *  #include <IoToS_User.h>       // inclut user_commands[]
 *
 *  void setup() { IoToS_Boot(); }   // appelle begin() + addCommands()
 *  void loop()  { IoToS_Kernel(); }
 *
 *====================================================================================================================
 *  USAGE — EXEMPLE COMPLET ESP32 WiFi + Bluetooth (identique v23)
 *====================================================================================================================
 *
 *  // ── Dans le sketch .ino ──────────────────────────────────────────────────────
 *
 *  #define CMDLINE_PLATFORM_ESP32
 *  #include <CmdLine.h>
 *  #include "BluetoothSerial.h"
 *
 *  BluetoothSerial SerialBT;
 *
 *  CmdLine       cmdLine(Serial);
 *  CmdLineServer serverTelnet(23);
 *  CmdLineClient clientTelnet;
 *
 *  void cmdStatus(const char *arg) {
 *      // Affichage adresse MAC — v23 : surcharge char* explicite
 *      uint8_t mac[6] = { 0x08, 0x3A, 0xF2, 0xB9, 0x1F, 0xC4 };
 *      for (int i = 0; i < 6; i++) {
 *          char hexByte[3];
 *          sprintf(hexByte, "%02X", mac[i]);    // formate en hex majuscule avec zéro
 *          cmdLine.print(hexByte);              // surcharge const char* → Serial+Telnet+BT
 *          if (i < 5) cmdLine.print(F(":"));
 *      }
 *      cmdLine.println();
 *  }
 *
 *  void setup() {
 *      Serial.begin(115200);
 *      SerialBT.begin("ESP32-CmdLine");
 *      cmdLine.setBluetoothOutput(&SerialBT);
 *      WiFi.begin(ssid, password);
 *      serverTelnet.begin();
 *      cmdLine.begin(commands, countof(commands));
 *      // addCommands() optionnel : non appelé ici → comportement v23
 *  }
 *
 *  void loop() {
 *      cmdLine.update();
 *      if (serverTelnet.hasClient()) clientTelnet = serverTelnet.available();
 *      cmdLine.updateNetwork(clientTelnet);
 *  }
 *
 *********************************************************************************************************************/
