<!doctype html>
<html>

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
  <link rel="stylesheet" media="all" href="style.css">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css">
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/maxima.min.js"></script>
  <script type="text/javascript" src="yamwi.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/jszip@3.10.1/dist/jszip.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.9.2/html2pdf.bundle.min.js"></script>
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS_HTML"></script>
  <title>Maxima Online 2</title>
</head>


<body>

<h2>
<a href="index.php" class="homepage">
  <img src="logo.jpg" alt="Maxima Online 2 Logo" style="height: 3em; width: auto;">
</a>
</h2>

<p class="small-right">Maxima Online 2 : 
<a href="help/help_fr.html" target="_blank">Guide pratique</a>
</p>
<br>
<p class="small-right">Maxima : 
<a href="help/aidememoiremaxima2.pdf" target="_blank">Aide mémoire 1 (Yves Lemaire)</a>
</p>
<br>
<p class="small-right">Maxima : 
<a href="help/aidememoiremaxima.pdf" target="_blank">Aide mémoire 2 (Lycée Stendhal)</a>
</p>

<div class="menu-row">

<select id="menu-simplify" class="cmd-menu">
<option value="">Simplifier...</option>
<option value="expand((x+1)^2);">Développer</option>
<option value="factor(x^3-1);">Factoriser</option>
<option value="gfactor(x^2+1);">Factorisation complexe </option>
<option value="ratsimp((x^2-1)/(x-1));">Simplifier fraction</option>
<option value="trigsimp(cos(x)^2+sin(x)^2);">Simplifier trigonométrie</option>
<option value="radcan(sqrt(8)+log(16));">Simplifier log/racines</option>
<option value="trigexpand(sin(x+y));">Développer trigonométrie</option>
<option value="fullratsimp((x^3-1)/(x^2-1));">Simplification complète</option>
<option value="num((x^2-1)/(x+1));">Numerateur</option>
<option value="denom((x^2-1)/(x+1));">Denominateur</option>
<option value="rectform(3*exp(%pi*%i/3));">Forme cartésienne</option>
<option value="polarform(1+%i);">Forme polaire</option>
</select>

<select id="menu-solve" class="cmd-menu">
<option value="">Résoudre...</option>
<option value="solve(x^2-4=0,x);">Résoudre équation</option>
<option value="find_root(sin(x),x,3,4);">Résoudre numériquement</option>
<option value="realroots(x^3-x-1);">Racines réelles d'un polynôme</option>
<option value="allroots(x^3-1);">Toutes les racines d'un polynôme</option>
<option value="linsolve([x+y=5,3*x-y=1],[x,y]);">Système linéaire</option>
<option value="algsys([x^2+y=5,x*y=2],[x,y]);">Système non linéaire</option>
<option value="subst(a+b,x,x^2);">Substitution</option>
<option value="ode2('diff(y,x)-y=x^2,y,x);">Equation différentielle O1</option>
<option value="ic1(ode2('diff(y,x)-y=2,y,x),x=0,y=1);">EDO ordre1 avec condition initiale</option>
<option value="ode2('diff(y,x,2)+y=0,y,x);">Equation différentielle O2</option>
<option value="ic2(ode2('diff(y,x,2)+y=0,y,x),x=0,y=1,'diff(y,x)=1);">EDO ordre2 avec conditions initiales</option>
</select>

<select id="menu-deriv" class="cmd-menu">
<option value="">Calcul différentiel...</option>
<option value="diff(x^3+2*x,x);">Dérivée</option>
<option value="diff(x^2*exp(-x),x,3);">Dérivée n-ième</option>
<option value="integrate(x^2+log(x),x);">Intégrale</option>
<option value="integrate((x^2-3*x+1)/(x^2+1),x,0,1);">Intégrale définie</option>
<option value="risch(x^2*exp(x^2),x);">Intégration Risch</option>
<option value="romberg(sin(x)+x^2,x,0,%pi);">Intégration Romberg</option>
<option value="f(x):=x+sin(x);">Définir fonction f(x)</option>
</select>


<select id="menu-ana" class="cmd-menu">
<option value="">Analyse...</option>
<option value="limit(sin(x)/x,x,0);">Limite</option>
<option value="sum(1/i^2,i,1,inf),simpsum;">Somme</option>
<option value="product(k/(k^2+1),k,1,10);">Produit</option>
<option value="partfrac((x^3+5*x-5)/(x^2-1),x);">Fractions partielles</option>
<option value="taylor(log(1+x),x,0,5);">Série de Taylor</option>
<option value="gcd(2356,128);">PGCD</option>
</select>


<select id="menu-plot" class="cmd-menu">
<option value="">Graphiques...</option>
<option value="draw2d(grid=true,xaxis=true,yaxis=true,xrange=[-5,5],yrange=[-2,12],color=black,line_width=1,explicit(sin(x)*x^3,x,-5,5));">Courbe 2D</option>
<option value="draw2d(parametric(cos(t),sin(t),t,0,2*%pi),xrange=[-1.5,1.5],yrange=[-1.5,1.5],grid=true,xaxis=true,yaxis=true,line_width=1);">Courbe 2D paramétrique</option>
<option value="draw2d(grid=true,line_width=2,color=red,implicit(x^3-3*x*y^2-1=0,x,-2,2,y,-2,2),grid=true,xaxis=true,yaxis=true);">Courbe 2D implicite</option>
<option value="draw3d(surface_hide=true,palette=[blue,cyan,green,yellow,orange,red],explicit(sin(sqrt(x^2+y^2))/(sqrt(x^2+y^2)),x,-6,6,y,-6,6));">Surface 3D</option>
<option value="draw3d(surface_hide=true,parametric_surface((2-0.2*cos(phi))*sin(theta),(2-0.2*cos(phi))*cos(theta),0.2*sin(phi),phi,0,2*%pi,theta,0,2*%pi));">Surface 3D paramétrique</option>
<option value="draw3d(nticks=200,parametric((2-0.5*cos(t))*sin(t/4),(2-0.5*cos(t))*cos(t/4),0.5*sin(t),t,0,8*%pi)); ">Courbe 3D</option>
<option value="draw2d(grid=true,xrange=[-10,10],yrange=[-5,10],point_type=7,points([[-3,1],[2,5]]));">Dessiner des points</option>
<option value="draw2d(xrange=[-10,10],yrange=[-5,10],point_type=5,points_joined = true,points([[-3,1],[2,5],[5,-2],[-3,1]]));">Dessiner des lignes</option>
</select>

<select id="menu-matrix" class="cmd-menu">
<option value="">Matrices...</option>
<option value="M:matrix([2,1,0],[1,0,1],[0,1,4]);">Définir une matrice</option>
<option value="invert(matrix([2,1,0],[1,0,1],[0,1,4]));">Inverser une matrice</option>
<option value="transpose(matrix([-2,1,5],[1,8,4],[0,1,4]));">Transposer une matrice</option>
<option value="matrix([1,2],[3,4]).matrix([-1,5],[0,8]);">Multiplier deux matrices</option>
<option value="determinant(matrix([2,1,0],[1,0,1],[0,1,4]));">Déterminant</option>
<option value="expand(charpoly(matrix([2,1,0],[1,0,1],[0,1,4]),x)); ">Polynôme caractéristique</option>
<option value="eigenvalues(matrix([6,-11,6],[1,0,0],[0,1,0]));">Valeurs propres</option>
<option value="eigenvectors(matrix([6,-11,6],[1,0,0],[0,1,0]));">Vecteurs propres</option>
</select>

<button id="btn-assistant-courbe-2d"
        type="button"
        title="Assistant graphique 2D"
        onclick="openGraphAssistant('2d')"
        style="margin-left:8px;padding:4px 10px;font-size:0.85em;cursor:pointer;background:#e8f4f8;border:1px solid #5b9bbd;border-radius:4px;color:#1a4a6b;font-weight:bold;vertical-align:middle;white-space:nowrap;">
  📈 Courbe 2D
</button>

<button id="btn-assistant-courbe-param"
        type="button"
        title="Assistant courbe paramétrique 2D"
        onclick="openGraphAssistant('param2d')"
        style="margin-left:8px;padding:4px 10px;font-size:0.85em;cursor:pointer;background:#eef7ea;border:1px solid #6b9d5b;border-radius:4px;color:#2f5b1a;font-weight:bold;vertical-align:middle;white-space:nowrap;">
  🔄 Param 2D
</button>

<button id="btn-assistant-courbe-3d"
        type="button"
        title="Assistant graphique 3D"
        onclick="openGraphAssistant('3d')"
        style="margin-left:8px;padding:4px 10px;font-size:0.85em;cursor:pointer;background:#f4ecfb;border:1px solid #8a63b8;border-radius:4px;color:#4a2870;font-weight:bold;vertical-align:middle;white-space:nowrap;">
  🧊 Surface 3D
</button>

<button id="btn-assistant-courbe-param3d"
        type="button"
        title="Assistant courbe 3D paramétrique"
        onclick="openGraphAssistant('param3d')"
        style="margin-left:8px;padding:4px 10px;font-size:0.85em;cursor:pointer;background:#fff3e8;border:1px solid #c07835;border-radius:4px;color:#7a3c00;font-weight:bold;vertical-align:middle;white-space:nowrap;">
  🌀 Courbe 3D
</button>

</div>

<hr>


<?php
include('yamwi.php');

$default_code =
   "expand((x-2)^3*(x+1/3)^2);\n".
   "solve(x^2-x+2=0);\n".
   "invert(matrix([2,3,1], [a,0,0], [1,4,8]));\n".
   "integrate(x * sin(x), x);\n".
   "draw3d(explicit(x^2+y^2,x,-1,1,y,-1,1));\n".
   "plot2d(exp(-x)*sin(x),[x,0,2*%pi]);";

start($default_code);
?>


<hr>

<button id="btn-pdf">Enregistrer la page en PDF</button>

<script>
document.getElementById('btn-pdf').addEventListener('click', function () {
    window.print();
});
</script>

<button id="saveBtn">Sauvegarder les commandes (.mac)</button>
<script>
// Fonction pour sauvegarder le contenu de la textarea "max"
document.getElementById("saveBtn").addEventListener("click", function() {
    var textarea = document.getElementById("max");
    if (!textarea) {
        alert("La zone de texte 'max' est introuvable !");
        return;
    }
    var contenu = textarea.value;
    var blob = new Blob([contenu], {type: "text/plain"});
    var link = document.createElement("a");
    link.href = URL.createObjectURL(blob);
    link.download = "yamwi_commandes.mac";
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    URL.revokeObjectURL(link.href);
});
</script>

<button id="loadFileBtn">Charger des commandes (.mac)</button>
<input type="file" id="fileInput" accept=".mac" style="display:none" />

<script>
const loadFileBtn = document.getElementById('loadFileBtn');
const fileInput = document.getElementById('fileInput');
const textarea = document.getElementById('max');  // utilise la textarea unique

loadFileBtn.addEventListener('click', () => {
  fileInput.click();
});

fileInput.addEventListener('change', (event) => {
  const file = event.target.files[0];
  if (file) {
    const reader = new FileReader();
    reader.onload = function(e) {
      textarea.value = e.target.result;  // Remplace le contenu existant
    };
    reader.readAsText(file);
  }
});
</script>

<button id="saveBatchBtn">Enregistrer un batch pour wxmaxima (.mac)</button>
<script>
// Fonction pour sauvegarder le contenu modifié de la textarea "max"
document.getElementById("saveBatchBtn").addEventListener("click", function() {
    var textarea = document.getElementById("max");
    if (!textarea) {
        alert("La zone de texte 'max' est introuvable !");
        return;
    }
    var contenu = textarea.value;
    var lignes = contenu.split('\n');
    for (var i = 0; i < lignes.length; i++) {
        // Remplacer toute commande en début de ligne commençant par 'plot' par 'wxplot'
        lignes[i] = lignes[i].replace(/^plot/, 'wxplot');
        // Remplacer toute commande en début de ligne commençant par 'draw' par 'wxdraw'
        lignes[i] = lignes[i].replace(/^draw/, 'wxdraw');
    }
    var contenuModifie = lignes.join('\n');
    var blob = new Blob([contenuModifie], {type: "text/plain"});
    var link = document.createElement("a");
    link.href = URL.createObjectURL(blob);
    link.download = "batch-wxmaxima.mac";
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    URL.revokeObjectURL(link.href);
});
</script>

<button id="loadWxmBtn">Importer fichier wxm (.wxm)</button>
<input type="file" id="fileInputWxm" accept=".wxm" style="display:none">

<script>
const loadWxmBtn = document.getElementById('loadWxmBtn');
const fileInputWxm = document.getElementById('fileInputWxm');

loadWxmBtn.addEventListener('click', () => {
  fileInputWxm.click();
});

fileInputWxm.addEventListener('change', (event) => {
  const file = event.target.files[0];
  if (file) {
    const reader = new FileReader();
    reader.onload = function(e) {
      const raw = e.target.result;
      const extracted = extractWxmCommands(raw);
      textarea.value = extracted;
    };
    reader.readAsText(file);
  }
});

function extractWxmCommands(text) {
  const lines = text.split('\n');
  let inside = false;
  const commandLines = [];

  for (let line of lines) {
    // Détection début de bloc input
    if (/\/\*\s*\[wxMaxima:\s*input\s+start\s*\]/.test(line)) {
      inside = true;
      continue;
    }
    // Détection fin de bloc input
    if (/\/\*\s*\[wxMaxima:\s*input\s+end\s*\]/.test(line)) {
      inside = false;
      continue;
    }
    // Collecte uniquement les lignes dans un bloc input
    if (inside) {
      commandLines.push(line);
    }
  }

  // Reconstitue le texte, supprime les commentaires /* ... */ sur une même ligne
  // et les lignes vides
  let result = commandLines
    .map(line => line.replace(/\/\*.*?\*\//g, ''))  // supprime les /* ... */ inline
    .map(line => line.trimEnd())
    .filter(line => line.trim() !== '')              // supprime les lignes vides
    .join('\n');

  return result;
}
</script>

<button id="loadWxmxBtn">Importer fichier wxmw (.wxmx)</button>
<input type="file" id="fileInputWxmx" accept=".wxmx" style="display:none">

<script>
const loadWxmxBtn = document.getElementById('loadWxmxBtn');
const fileInputWxmx = document.getElementById('fileInputWxmx');

loadWxmxBtn.addEventListener('click', () => {
  fileInputWxmx.click();
});

fileInputWxmx.addEventListener('change', (event) => {
  const file = event.target.files[0];
  if (!file) return;

  const reader = new FileReader();
  reader.onload = async function(e) {
    try {
      // Décompression du fichier wxmx (ZIP)
      const zip = await JSZip.loadAsync(e.target.result);

      // Extraction de content.xml
      const contentFile = zip.file('content.xml');
      if (!contentFile) {
        alert('Fichier content.xml introuvable dans le .wxmx');
        return;
      }
      const xmlText = await contentFile.async('string');

      // Parse XML et extraction des commandes
      const commands = extractWxmxCommands(xmlText);
      textarea.value = commands;

    } catch (err) {
      alert('Erreur lors de la lecture du fichier .wxmx : ' + err.message);
    }
  };
  reader.readAsArrayBuffer(file);  // JSZip nécessite ArrayBuffer
});

function extractWxmxCommands(xmlText) {
  const parser = new DOMParser();
  const doc = parser.parseFromString(xmlText, 'application/xml');

  // Récupère toutes les balises <line> dans les blocs <input>
  const inputBlocks = doc.querySelectorAll('cell[type="code"] input line');

  const lines = [];
  inputBlocks.forEach(lineNode => {
    let content = lineNode.textContent;

    // &#010; = \n encodé dans le XML (cellules multi-lignes comme les matrices)
    content = content.replace(/\n/g, '\n');  // déjà converti par textContent

    // Découpe en sous-lignes si la cellule contenait des \n (matrices, etc.)
    const subLines = content.split('\n');
    subLines.forEach(subLine => {
      const trimmed = subLine.trimEnd();
      if (trimmed.trim() !== '') {
        lines.push(trimmed);
      }
    });
  });

  return lines.join('\n');
}
</script>

<button onclick="window.scrollTo({top: 0, behavior: 'smooth'});">Retour haut de page</button>

<!-- Conteneur des boutons PDF -->

<div class="pdf-options">
    <div>
        <label for="fontSize">Taille de la police du PDF :</label>
        <select id="fontSize">
            <option value="10pt">10pt</option>
            <option value="11pt" selected>11pt</option>
            <option value="12pt">12pt</option>
        </select>
    </div>    
    <div>
        <label for="imgScale">&nbsp;Échelle des graphiques du PDF :</label>
        <select id="imgScale">
            <option value="0.3">30%</option>
            <option value="0.5" selected>50%</option>
            <option value="0.7">70%</option>
            <option value="0.8">80%</option>
            <option value="1.0">100%</option>
        </select>
    </div>
</div>

<!-- Conteneur des boutons PDF EN DESSOUS -->
<div class="pdf-buttons">
        <button id="generateBtn" class="btn-generate-pdf">Générer le PDF des résultats</button>
    <button id="viewPdfBtn" class="btn-view-pdf" style="display:none;">Voir le PDF</button>
    <button id="downloadPdfBtn" class="btn-download-pdf" style="display:none;">Télécharger le PDF</button>
</div>

<script>
// Variables globales pour stocker les URLs du dernier PDF généré
var lastPdfViewUrl = null;
var lastPdfDownloadUrl = null;



// Bouton pour GÉNÉRER le PDF (sans téléchargement automatique)
document.getElementById("generateBtn").addEventListener("click", function() {
    var textarea = document.getElementById("max");
    if (!textarea || !textarea.value.trim()) {
        alert("Aucune commande à traiter !");
        return;
    }
    
    // Désactiver le bouton pendant le traitement
    this.disabled = true;
    this.textContent = "Génération en cours...";
    
    // Masquer les boutons Voir et Télécharger pendant la génération
    document.getElementById("viewPdfBtn").style.display = "none";
    document.getElementById("downloadPdfBtn").style.display = "none";
    
    // Récupérer les options
    var fontSize = document.getElementById("fontSize").value;
    var imgScale = document.getElementById("imgScale").value;
    
    // Préparer les données
    var formData = new FormData();
    formData.append('commandes', textarea.value);
    formData.append('fontSize', fontSize);
    formData.append('imgScale', imgScale);
    
    // Envoyer la requête AJAX
    fetch('generer_pdf.php', {
        method: 'POST',
        body: formData
    })
    .then(response => response.json())
    .then(data => {
        if (data.success) {
            // Stocker les URLs pour visualisation et téléchargement
            lastPdfViewUrl = data.view_url;
            lastPdfDownloadUrl = data.download_url;
            
            // Afficher les boutons "Voir le PDF" et "Télécharger le PDF"
            document.getElementById("viewPdfBtn").style.display = "inline-block";
            document.getElementById("downloadPdfBtn").style.display = "inline-block";
            
            // Message de confirmation (optionnel)
            console.log("PDF généré avec succès !");
        } else {
            alert("Erreur: " + data.error);
            console.error(data.details);
        }
    })
    .catch(error => {
        alert("Erreur de connexion: " + error);
    })
    .finally(() => {
        this.disabled = false;
        this.textContent = "Générer le PDF";
    });
});

// Bouton pour VISUALISER le PDF
document.getElementById("viewPdfBtn").addEventListener("click", function() {
    if (lastPdfViewUrl) {
        window.open(lastPdfViewUrl, '_blank');
    } else {
        alert("Aucun PDF disponible. Générez d'abord un PDF.");
    }
});

// Bouton pour TÉLÉCHARGER le PDF
document.getElementById("downloadPdfBtn").addEventListener("click", function() {
    if (lastPdfDownloadUrl) {
        window.location.href = lastPdfDownloadUrl;
    } else {
        alert("Aucun PDF disponible. Générez d'abord un PDF.");
    }
});
</script>

<!-- À ajouter dans index.php après les boutons PDF existants -->

<div class="pdf-buttons">
    <button id="exportLatexBtn" class="btn-export-latex">Exporter en LaTeX (.zip)</button>
</div>

<script>
// Variables globales pour l'export LaTeX
var lastLatexDownloadUrl = null;

// Bouton pour EXPORTER en LaTeX
document.getElementById("exportLatexBtn").addEventListener("click", function() {
    var textarea = document.getElementById("max");
    if (!textarea || !textarea.value.trim()) {
        alert("Aucune commande à traiter !");
        return;
    }
    
    // Désactiver le bouton pendant le traitement
    this.disabled = true;
    this.textContent = "Export en cours...";
    
    // Récupérer les options (même que pour le PDF)
    var fontSize = document.getElementById("fontSize").value;
    var imgScale = document.getElementById("imgScale").value;
    
    // Préparer les données
    var formData = new FormData();
    formData.append('commandes', textarea.value);
    formData.append('fontSize', fontSize);
    formData.append('imgScale', imgScale);
    
    // Envoyer la requête AJAX
    fetch('exporter_latex.php', {
        method: 'POST',
        body: formData
    })
    .then(response => response.json())
    .then(data => {
        if (data.success) {
            // Télécharger automatiquement le fichier ZIP
            window.location.href = data.download_url;
            console.log("Export LaTeX généré avec succès !");
        } else {
            alert("Erreur: " + data.error);
            console.error(data.details);
        }
    })
    .catch(error => {
        alert("Erreur de connexion: " + error);
    })
    .finally(() => {
        this.disabled = false;
        this.textContent = "Exporter en LaTeX (.zip)";
    });
});
</script>



<p class="small-left">
  Maxima Online 2 - version 5.1 -  
  <a href="https://maxima-french-doc.fr/interfaces/" target = "_blank">Site du logiciel</a> - 
  <a href="check_version.php">Vérifier les mises à jour</a>
  <br>
  Maxima Online 2 est basé sur le code de Yamwi, écrit par Leo Butler : 
  <a href="https://github.com/leo-butler/yamwi/" target = "_blank">Yamwi Source</a>
  <br>
  Distribué sous licence GNU GENERAL PUBLIC LICENSE (GPL) v3.0
</p>

<div id="graph-assistant-overlay"
     onclick="closeGraphAssistant()"
     style="display:none;position:fixed;inset:0;background:rgba(0,0,0,0.35);z-index:999;"></div>

<div id="graph-assistant-panel"
     style="display:none;position:fixed;top:0;right:0;width:390px;max-width:96vw;height:100vh;background:#f9f9f9;border-left:2px solid #5b9bbd;box-shadow:-4px 0 24px rgba(0,0,0,0.18);z-index:1000;overflow-y:auto;padding:18px 16px 30px 16px;font-family:sans-serif;font-size:0.88em;box-sizing:border-box;transform:translateX(100%);transition:transform 0.28s cubic-bezier(0.16,1,0.3,1);">

  <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:14px;">
    <strong id="ga-title" style="font-size:1.05em;color:#1a4a6b;">Assistant graphique</strong>
    <button type="button" onclick="closeGraphAssistant()" title="Fermer" style="background:none;border:none;font-size:1.4em;cursor:pointer;color:#555;padding:2px 6px;">✕</button>
  </div>

  <div id="ga-subtitle" style="font-size:0.82em;color:#666;margin-bottom:14px;">
    Génère du code wxMaxima inséré dans l'éditeur.
  </div>

  <div id="ga-form-container"></div>

  <div style="margin-top:12px;margin-bottom:10px;">
    <div style="font-weight:bold;color:#1a4a6b;margin-bottom:4px;font-size:0.9em;">Aperçu du code généré :</div>
    <pre id="ga-preview"
         style="background:#fff;border:1px solid #c5d8e8;border-radius:4px;padding:8px 10px;font-size:0.8em;font-family:monospace;white-space:pre-wrap;word-break:break-word;color:#333;min-height:60px;max-height:220px;overflow-y:auto;margin:0;">Remplissez le formulaire...</pre>
  </div>

  <div style="display:flex;gap:8px;flex-wrap:wrap;">
    <button type="button" onclick="insertGraphAssistantCode()"
            style="flex:1;padding:8px 12px;background:#1a4a6b;color:#fff;border:none;border-radius:4px;font-weight:bold;cursor:pointer;font-size:0.92em;">
      ✅ Insérer dans l'éditeur
    </button>
    <button type="button" id="ga-copy-btn" onclick="copyGraphAssistantCode()"
            style="padding:8px 12px;background:#f7f1df;color:#6a4b00;border:1px solid #d5bf74;border-radius:4px;cursor:pointer;font-size:0.92em;">
      📋 Copier
    </button>
    <button type="button" onclick="resetGraphAssistantForm()"
            style="padding:8px 12px;background:#eee;color:#555;border:1px solid #bbb;border-radius:4px;cursor:pointer;font-size:0.92em;">
      🔄 Réinitialiser
    </button>
  </div>

  <div id="ga-error" style="color:#c0392b;font-size:0.82em;margin-top:8px;display:none;"></div>
</div>

<script>
(function() {
  var currentAssistantType = '2d';

  function getCommonStyleInput() {
    return 'width:100%;margin:3px 0 8px;padding:4px 6px;box-sizing:border-box;border:1px solid #bbb;border-radius:3px;';
  }

  function getGrid2Style() {
    return 'display:grid;grid-template-columns:1fr 1fr;gap:6px;';
  }

  function render2DForm() {
    return `
      <fieldset style="border:1px solid #c5d8e8;border-radius:5px;padding:10px 12px;margin-bottom:10px;">
        <legend style="color:#1a4a6b;font-weight:bold;padding:0 4px;">Cadre du graphique</legend>
        <label>Titre <em>(optionnel)</em><br>
          <input id="ga-2d-title" type="text" placeholder="ex: Courbes comparées" style="${getCommonStyleInput()}">
        </label>
        <div style="${getGrid2Style()}">
          <label>x min cadre *<br><input id="ga-2d-xmin" type="text" placeholder="-5" style="${getCommonStyleInput()}"></label>
          <label>x max cadre *<br><input id="ga-2d-xmax" type="text" placeholder="5" style="${getCommonStyleInput()}"></label>
          <label>y min cadre *<br><input id="ga-2d-ymin" type="text" placeholder="-5" style="${getCommonStyleInput()}"></label>
          <label>y max cadre *<br><input id="ga-2d-ymax" type="text" placeholder="5" style="${getCommonStyleInput()}"></label>
        </div>
      </fieldset>

      <fieldset style="border:1px solid #c5d8e8;border-radius:5px;padding:10px 12px;margin-bottom:10px;">
        <legend style="color:#1a4a6b;font-weight:bold;padding:0 4px;">Courbe 1</legend>
        <label>f(x) = *<br><input id="ga-2d-fx1" type="text" placeholder="sin(x)" style="${getCommonStyleInput()}font-family:monospace;"></label>
        <div style="${getGrid2Style()}">
          <label>x min tracé *<br><input id="ga-2d-xmin1" type="text" placeholder="-5" style="${getCommonStyleInput()}"></label>
          <label>x max tracé *<br><input id="ga-2d-xmax1" type="text" placeholder="5" style="${getCommonStyleInput()}"></label>
        </div>
        <label>Étiquette <em>(optionnel)</em><br><input id="ga-2d-key1" type="text" placeholder="f(x)=sin(x)" style="${getCommonStyleInput()}"></label>
        <div style="${getGrid2Style()}">
          <label>Couleur<br>
            <select id="ga-2d-color1" style="${getCommonStyleInput()}">
              <option value="black">black</option><option value="blue">blue</option><option value="red">red</option>
              <option value="green">green</option><option value="magenta">magenta</option><option value="cyan">cyan</option>
              <option value="brown">brown</option><option value="yellow">yellow</option>
            </select>
          </label>
          <label>Épaisseur<br>
            <select id="ga-2d-width1" style="${getCommonStyleInput()}">
              <option value="1">1</option><option value="2" selected>2</option><option value="3">3</option>
              <option value="4">4</option><option value="5">5</option><option value="6">6</option>
            </select>
          </label>
        </div>
      </fieldset>

      <div style="margin-bottom:10px;">
        <button type="button" id="ga-add-second-curve"
                onclick="toggleSecondCurve2D()"
                style="padding:7px 10px;background:#eef7ea;color:#2f5b1a;border:1px solid #6b9d5b;border-radius:4px;cursor:pointer;font-size:0.92em;">
          ➕ Ajouter une 2e courbe
        </button>
      </div>

      <fieldset id="ga-2d-second-curve"
                style="display:none;border:1px solid #d7e6c9;border-radius:5px;padding:10px 12px;margin-bottom:10px;background:#fcfefb;">
        <legend style="color:#2f5b1a;font-weight:bold;padding:0 4px;">Courbe 2</legend>
        <label>g(x) = <br><input id="ga-2d-fx2" type="text" placeholder="cos(x)" style="${getCommonStyleInput()}font-family:monospace;"></label>
        <div style="${getGrid2Style()}">
          <label>x min tracé<br><input id="ga-2d-xmin2" type="text" placeholder="-5" style="${getCommonStyleInput()}"></label>
          <label>x max tracé<br><input id="ga-2d-xmax2" type="text" placeholder="5" style="${getCommonStyleInput()}"></label>
        </div>
        <label>Étiquette <em>(optionnel)</em><br><input id="ga-2d-key2" type="text" placeholder="g(x)=cos(x)" style="${getCommonStyleInput()}"></label>
        <div style="${getGrid2Style()}">
          <label>Couleur<br>
            <select id="ga-2d-color2" style="${getCommonStyleInput()}">
              <option value="red" selected>red</option><option value="blue">blue</option><option value="black">black</option>
              <option value="green">green</option><option value="magenta">magenta</option><option value="cyan">cyan</option>
              <option value="brown">brown</option><option value="yellow">yellow</option>
            </select>
          </label>
          <label>Épaisseur<br>
            <select id="ga-2d-width2" style="${getCommonStyleInput()}">
              <option value="1">1</option><option value="2" selected>2</option><option value="3">3</option>
              <option value="4">4</option><option value="5">5</option><option value="6">6</option>
            </select>
          </label>
        </div>
      </fieldset>

      <fieldset style="border:1px solid #c5d8e8;border-radius:5px;padding:10px 12px;margin-bottom:10px;">
        <legend style="color:#1a4a6b;font-weight:bold;padding:0 4px;">Options</legend>
        <div style="display:flex;gap:16px;flex-wrap:wrap;">
          <label style="display:flex;align-items:center;gap:5px;cursor:pointer;"><input type="checkbox" id="ga-2d-grid" checked> Quadrillage</label>
          <label style="display:flex;align-items:center;gap:5px;cursor:pointer;"><input type="checkbox" id="ga-2d-xaxis" checked> Axe des x</label>
          <label style="display:flex;align-items:center;gap:5px;cursor:pointer;"><input type="checkbox" id="ga-2d-yaxis" checked> Axe des y</label>
        </div>
      </fieldset>
    `;
  }

  function renderParam2DForm() {
    return `
      <fieldset style="border:1px solid #c5d8e8;border-radius:5px;padding:10px 12px;margin-bottom:10px;">
        <legend style="color:#2f5b1a;font-weight:bold;padding:0 4px;">Cadre paramétrique 2D</legend>
        <label>Titre <em>(optionnel)</em><br><input id="ga-p-title" type="text" placeholder="ex: Cercle" style="${getCommonStyleInput()}"></label>
        <div style="${getGrid2Style()}">
          <label>x min cadre *<br><input id="ga-p-xmin" type="text" placeholder="-2" style="${getCommonStyleInput()}"></label>
          <label>x max cadre *<br><input id="ga-p-xmax" type="text" placeholder="2" style="${getCommonStyleInput()}"></label>
          <label>y min cadre *<br><input id="ga-p-ymin" type="text" placeholder="-2" style="${getCommonStyleInput()}"></label>
          <label>y max cadre *<br><input id="ga-p-ymax" type="text" placeholder="2" style="${getCommonStyleInput()}"></label>
        </div>
        <label>x(t) = *<br><input id="ga-p-fx" type="text" placeholder="cos(t)" style="${getCommonStyleInput()}font-family:monospace;"></label>
        <label>y(t) = *<br><input id="ga-p-fy" type="text" placeholder="sin(t)" style="${getCommonStyleInput()}font-family:monospace;"></label>
        <div style="${getGrid2Style()}">
          <label>Paramètre<br><input id="ga-p-var" type="text" placeholder="t" value="t" style="${getCommonStyleInput()}"></label>
          <label>Étiquette <em>(optionnel)</em><br><input id="ga-p-key" type="text" placeholder="cercle" style="${getCommonStyleInput()}"></label>
          <label>t min *<br><input id="ga-p-tmin" type="text" placeholder="0" style="${getCommonStyleInput()}"></label>
          <label>t max *<br><input id="ga-p-tmax" type="text" placeholder="2*%pi" style="${getCommonStyleInput()}"></label>
        </div>
        <div style="${getGrid2Style()}">
          <label>Couleur<br>
            <select id="ga-p-color" style="${getCommonStyleInput()}">
              <option value="black">black</option><option value="blue">blue</option><option value="red">red</option>
              <option value="green">green</option><option value="magenta">magenta</option><option value="cyan">cyan</option>
              <option value="brown">brown</option><option value="yellow">yellow</option>
            </select>
          </label>
          <label>Épaisseur<br>
            <select id="ga-p-width" style="${getCommonStyleInput()}">
              <option value="1">1</option><option value="2" selected>2</option><option value="3">3</option>
              <option value="4">4</option><option value="5">5</option><option value="6">6</option>
            </select>
          </label>
        </div>
        <div style="display:flex;gap:16px;flex-wrap:wrap;">
          <label style="display:flex;align-items:center;gap:5px;cursor:pointer;"><input type="checkbox" id="ga-p-grid" checked> Quadrillage</label>
          <label style="display:flex;align-items:center;gap:5px;cursor:pointer;"><input type="checkbox" id="ga-p-xaxis" checked> Axe des x</label>
          <label style="display:flex;align-items:center;gap:5px;cursor:pointer;"><input type="checkbox" id="ga-p-yaxis" checked> Axe des y</label>
        </div>
      </fieldset>
    `;
  }

  function renderParam3DForm() {
    return `
      <fieldset style="border:1px solid #f0d0a0;border-radius:5px;padding:10px 12px;margin-bottom:10px;">
        <legend style="color:#7a3c00;font-weight:bold;padding:0 4px;">Courbe 3D paramétrique</legend>
        <label>Titre <em>(optionnel)</em><br><input id="ga-p3-title" type="text" placeholder="ex: Hélice" style="${getCommonStyleInput()}"></label>
        <label>x(t) = *<br><input id="ga-p3-fx" type="text" placeholder="cos(t)" style="${getCommonStyleInput()}font-family:monospace;"></label>
        <label>y(t) = *<br><input id="ga-p3-fy" type="text" placeholder="sin(t)" style="${getCommonStyleInput()}font-family:monospace;"></label>
        <label>z(t) = *<br><input id="ga-p3-fz" type="text" placeholder="t/(2*%pi)" style="${getCommonStyleInput()}font-family:monospace;"></label>
        <div style="${getGrid2Style()}">
          <label>Paramètre<br><input id="ga-p3-var" type="text" placeholder="t" value="t" style="${getCommonStyleInput()}"></label>
          <label>nticks<br><input id="ga-p3-nticks" type="text" placeholder="200" value="200" style="${getCommonStyleInput()}"></label>
          <label>t min *<br><input id="ga-p3-tmin" type="text" placeholder="0" style="${getCommonStyleInput()}"></label>
          <label>t max *<br><input id="ga-p3-tmax" type="text" placeholder="4*%pi" style="${getCommonStyleInput()}"></label>
        </div>
        <div style="${getGrid2Style()}">
          <label>Couleur<br>
            <select id="ga-p3-color" style="${getCommonStyleInput()}">
              <option value="black">black</option><option value="blue">blue</option><option value="red">red</option>
              <option value="green">green</option><option value="magenta">magenta</option><option value="cyan">cyan</option>
              <option value="brown">brown</option><option value="orange">orange</option>
            </select>
          </label>
          <label>Épaisseur<br>
            <select id="ga-p3-width" style="${getCommonStyleInput()}">
              <option value="1">1</option><option value="2" selected>2</option><option value="3">3</option>
              <option value="4">4</option><option value="5">5</option><option value="6">6</option>
            </select>
          </label>
        </div>
      </fieldset>
    `;
  }

    function render3DForm() {
    return `
      <fieldset style="border:1px solid #c5d8e8;border-radius:5px;padding:10px 12px;margin-bottom:10px;">
        <legend style="color:#4a2870;font-weight:bold;padding:0 4px;">Graphique 3D</legend>
        <label>Titre <em>(optionnel)</em><br><input id="ga-3d-title" type="text" placeholder="ex: Surface 3D" style="${getCommonStyleInput()}"></label>
        <label>z = f(x,y) *<br><input id="ga-3d-f" type="text" placeholder="sin(sqrt(x^2+y^2))/sqrt(x^2+y^2)" style="${getCommonStyleInput()}font-family:monospace;"></label>
        <div style="${getGrid2Style()}">
          <label>x min *<br><input id="ga-3d-xmin" type="text" placeholder="-6" style="${getCommonStyleInput()}"></label>
          <label>x max *<br><input id="ga-3d-xmax" type="text" placeholder="6" style="${getCommonStyleInput()}"></label>
          <label>y min *<br><input id="ga-3d-ymin" type="text" placeholder="-6" style="${getCommonStyleInput()}"></label>
          <label>y max *<br><input id="ga-3d-ymax" type="text" placeholder="6" style="${getCommonStyleInput()}"></label>
        </div>
        <div style="${getGrid2Style()}">
          <label>Palette<br>
            <select id="ga-3d-palette" style="${getCommonStyleInput()}">
              <option value="[blue,cyan,green,yellow,orange,red]">Arc-en-ciel (blue→red)</option>
              <option value="[red,orange,yellow]">Chaud (red→yellow)</option>
              <option value="[black,white]">Niveaux de gris</option>
              <option value="[violet,blue,cyan,green]">Froid (violet→green)</option>
              <option value="[blue,cyan,white]">Océan (blue→white)</option>
            </select>
          </label>
          <label>nticks<br><input id="ga-3d-nticks" type="text" placeholder="60" value="60" style="${getCommonStyleInput()}"></label>
        </div>
        <div style="display:flex;gap:16px;flex-wrap:wrap;">
          <label style="display:flex;align-items:center;gap:5px;cursor:pointer;"><input type="checkbox" id="ga-3d-enhanced" checked> surface_hide</label>
          <label style="display:flex;align-items:center;gap:5px;cursor:pointer;"><input type="checkbox" id="ga-3d-enhanced3d" checked> enhanced3d (palette active)</label>
        </div>
      </fieldset>
    `;
  }

  function renderAssistantForm(type) {
    var container = document.getElementById('ga-form-container');
    var title = document.getElementById('ga-title');
    var subtitle = document.getElementById('ga-subtitle');

    if (type === '2d') {
      title.textContent = '📈 Assistant courbe 2D';
      subtitle.textContent = 'Génère un wxdraw2d(...) avec une ou deux courbes explicites.';
      container.innerHTML = render2DForm();
    } else if (type === 'param2d') {
      title.textContent = '🔄 Assistant courbe paramétrique 2D';
      subtitle.textContent = 'Génère un wxdraw2d(...) avec parametric(x(t),y(t),t,...)';
      container.innerHTML = renderParam2DForm();
    } else if (type === 'param3d') {
      title.textContent = '🌀 Assistant courbe 3D paramétrique';
      subtitle.textContent = 'Génère un wxdraw3d(...) avec parametric(x(t),y(t),z(t),t,...).';
      container.innerHTML = renderParam3DForm();
    } else {
      title.textContent = '🧊 Assistant graphique 3D';
      subtitle.textContent = 'Génère un wxdraw3d(...) pour une surface explicite z=f(x,y).';
      container.innerHTML = render3DForm();
    }

    attachPreviewListeners();
    updateGraphAssistantPreview();
  }

  window.openGraphAssistant = function(type) {
    currentAssistantType = type || '2d';
    renderAssistantForm(currentAssistantType);
    var panel = document.getElementById('graph-assistant-panel');
    var overlay = document.getElementById('graph-assistant-overlay');
    panel.style.display = 'block';
    overlay.style.display = 'block';
    panel.getBoundingClientRect();
    panel.style.transform = 'translateX(0)';
  };

  window.closeGraphAssistant = function() {
    var panel = document.getElementById('graph-assistant-panel');
    var overlay = document.getElementById('graph-assistant-overlay');
    panel.style.transform = 'translateX(100%)';
    setTimeout(function() {
      panel.style.display = 'none';
      overlay.style.display = 'none';
    }, 290);
  };

  window.toggleSecondCurve2D = function() {
    var block = document.getElementById('ga-2d-second-curve');
    var btn = document.getElementById('ga-add-second-curve');
    if (!block || !btn) return;
    var visible = block.style.display !== 'none';
    block.style.display = visible ? 'none' : 'block';
    btn.textContent = visible ? '➕ Ajouter une 2e courbe' : '➖ Retirer la 2e courbe';
    updateGraphAssistantPreview();
  };

  function val(id) {
    var el = document.getElementById(id);
    return el ? el.value.trim() : '';
  }

  function checked(id) {
    var el = document.getElementById(id);
    return !!(el && el.checked);
  }

  function build2DCode() {
    var missing = [];
    var title = val('ga-2d-title');
    var xmin = val('ga-2d-xmin');
    var xmax = val('ga-2d-xmax');
    var ymin = val('ga-2d-ymin');
    var ymax = val('ga-2d-ymax');
    var fx1 = val('ga-2d-fx1');
    var xmin1 = val('ga-2d-xmin1');
    var xmax1 = val('ga-2d-xmax1');
    var key1 = val('ga-2d-key1');
    var color1 = val('ga-2d-color1');
    var width1 = val('ga-2d-width1');

    if (!xmin) missing.push('x min cadre');
    if (!xmax) missing.push('x max cadre');
    if (!ymin) missing.push('y min cadre');
    if (!ymax) missing.push('y max cadre');
    if (!fx1) missing.push('Courbe 1 : f(x)');
    if (!xmin1) missing.push('Courbe 1 : x min tracé');
    if (!xmax1) missing.push('Courbe 1 : x max tracé');

    var secondVisible = document.getElementById('ga-2d-second-curve') && document.getElementById('ga-2d-second-curve').style.display !== 'none';
    var fx2 = val('ga-2d-fx2');
    var xmin2 = val('ga-2d-xmin2');
    var xmax2 = val('ga-2d-xmax2');
    var key2 = val('ga-2d-key2');
    var color2 = val('ga-2d-color2');
    var width2 = val('ga-2d-width2');

    if (secondVisible && fx2) {
      if (!xmin2) missing.push('Courbe 2 : x min tracé');
      if (!xmax2) missing.push('Courbe 2 : x max tracé');
    }

    if (missing.length) return { ok:false, msg:'Champs obligatoires manquants : ' + missing.join(', ') };

    var lines = [];
    lines.push('wxdraw2d(');
    if (title) lines.push('  title="' + title + '",');
    if (checked('ga-2d-grid')) lines.push('  grid=true,');
    if (checked('ga-2d-xaxis')) lines.push('  xaxis=true,');
    if (checked('ga-2d-yaxis')) lines.push('  yaxis=true,');
    lines.push('  xrange=[' + xmin + ',' + xmax + '],');
    lines.push('  yrange=[' + ymin + ',' + ymax + '],');

    var curves = [];
    var c1 = [];
    c1.push('color=' + color1);
    c1.push('line_width=' + width1);
    if (key1) c1.push('key="' + key1 + '"');
    c1.push('explicit(' + fx1 + ',x,' + xmin1 + ',' + xmax1 + ')');
    curves.push('  ' + c1.join(',\n  '));

    if (secondVisible && fx2) {
      var c2 = [];
      c2.push('color=' + color2);
      c2.push('line_width=' + width2);
      if (key2) c2.push('key="' + key2 + '"');
      c2.push('explicit(' + fx2 + ',x,' + xmin2 + ',' + xmax2 + ')');
      curves.push('  ' + c2.join(',\n  '));
    }

    lines.push(curves.join(',\n'));
    lines.push(')$');
    return { ok:true, code:lines.join('\n') };
  }

  function buildParam2DCode() {
    var missing = [];
    var title = val('ga-p-title');
    var xmin = val('ga-p-xmin');
    var xmax = val('ga-p-xmax');
    var ymin = val('ga-p-ymin');
    var ymax = val('ga-p-ymax');
    var fx = val('ga-p-fx');
    var fy = val('ga-p-fy');
    var v = val('ga-p-var') || 't';
    var tmin = val('ga-p-tmin');
    var tmax = val('ga-p-tmax');
    var key = val('ga-p-key');
    var color = val('ga-p-color');
    var width = val('ga-p-width');

    if (!xmin) missing.push('x min cadre');
    if (!xmax) missing.push('x max cadre');
    if (!ymin) missing.push('y min cadre');
    if (!ymax) missing.push('y max cadre');
    if (!fx) missing.push('x(t)');
    if (!fy) missing.push('y(t)');
    if (!tmin) missing.push('t min');
    if (!tmax) missing.push('t max');
    if (missing.length) return { ok:false, msg:'Champs obligatoires manquants : ' + missing.join(', ') };

    var lines = [];
    lines.push('wxdraw2d(');
    if (title) lines.push('  title="' + title + '",');
    if (checked('ga-p-grid')) lines.push('  grid=true,');
    if (checked('ga-p-xaxis')) lines.push('  xaxis=true,');
    if (checked('ga-p-yaxis')) lines.push('  yaxis=true,');
    lines.push('  xrange=[' + xmin + ',' + xmax + '],');
    lines.push('  yrange=[' + ymin + ',' + ymax + '],');
    lines.push('  color=' + color + ',');
    lines.push('  line_width=' + width + ',');
    if (key) lines.push('  key="' + key + '",');
    lines.push('  parametric(' + fx + ',' + fy + ',' + v + ',' + tmin + ',' + tmax + ')');
    lines.push(')$');
    return { ok:true, code:lines.join('\n') };
  }

  function build3DCode() {
    var missing = [];
    var title = val('ga-3d-title');
    var f = val('ga-3d-f');
    var xmin = val('ga-3d-xmin');
    var xmax = val('ga-3d-xmax');
    var ymin = val('ga-3d-ymin');
    var ymax = val('ga-3d-ymax');
    var palette = val('ga-3d-palette');
    var nticks = val('ga-3d-nticks') || '60';

    if (!f) missing.push('z=f(x,y)');
    if (!xmin) missing.push('x min');
    if (!xmax) missing.push('x max');
    if (!ymin) missing.push('y min');
    if (!ymax) missing.push('y max');
    if (missing.length) return { ok:false, msg:'Champs obligatoires manquants : ' + missing.join(', ') };

    var lines = [];
    lines.push('wxdraw3d(');
    if (checked('ga-3d-enhanced')) lines.push('  surface_hide=true,');
    if (title) lines.push('  title="' + title + '",');
    if (checked('ga-3d-enhanced3d')) {
      lines.push('  enhanced3d=true,');
      lines.push('  palette=' + palette + ',');
    }
    lines.push('  nticks=' + nticks + ',');
    lines.push('  explicit(' + f + ',x,' + xmin + ',' + xmax + ',y,' + ymin + ',' + ymax + ')');
    lines.push(')$');
    return { ok:true, code:lines.join('\n') };
  }

    function buildParam3DCode() {
    var missing = [];
    var title = val('ga-p3-title');
    var fx = val('ga-p3-fx');
    var fy = val('ga-p3-fy');
    var fz = val('ga-p3-fz');
    var v = val('ga-p3-var') || 't';
    var tmin = val('ga-p3-tmin');
    var tmax = val('ga-p3-tmax');
    var nticks = val('ga-p3-nticks') || '200';
    var color = val('ga-p3-color') || 'blue';
    var width = val('ga-p3-width') || '2';

    if (!fx) missing.push('x(t)');
    if (!fy) missing.push('y(t)');
    if (!fz) missing.push('z(t)');
    if (!tmin) missing.push('t min');
    if (!tmax) missing.push('t max');
    if (missing.length) return { ok:false, msg:'Champs obligatoires manquants : ' + missing.join(', ') };

    var lines = [];
    lines.push('wxdraw3d(');
    if (title) lines.push('  title="' + title + '",');
    lines.push('  nticks=' + nticks + ',');
    lines.push('  color=' + color + ',');
    lines.push('  line_width=' + width + ',');
    lines.push('  parametric(' + fx + ',' + fy + ',' + fz + ',' + v + ',' + tmin + ',' + tmax + ')');
    lines.push(')$');
    return { ok:true, code:lines.join('\n') };
  }

  function buildCurrentCode() {
    if (currentAssistantType === '2d') return build2DCode();
    if (currentAssistantType === 'param2d') return buildParam2DCode();
    if (currentAssistantType === 'param3d') return buildParam3DCode();
    return build3DCode();
  }

  window.updateGraphAssistantPreview = function() {
    var result = buildCurrentCode();
    var preview = document.getElementById('ga-preview');
    var err = document.getElementById('ga-error');
    err.style.display = 'none';
    if (result.ok) {
      preview.textContent = result.code;
      preview.style.color = '#1a3a2a';
    } else {
      preview.textContent = result.msg;
      preview.style.color = '#999';
    }
  };

  window.insertGraphAssistantCode = function() {
    var result = buildCurrentCode();
    var err = document.getElementById('ga-error');
    err.style.display = 'none';
    if (!result.ok) {
      err.textContent = result.msg;
      err.style.display = 'block';
      return;
    }

    var textarea = document.getElementById('max');
    if (!textarea) {
      err.textContent = 'Éditeur introuvable (textarea#max).';
      err.style.display = 'block';
      return;
    }

    var maybe_newline = (textarea.value === '' || textarea.value.endsWith('\n')) ? '' : '\n';
    textarea.value += maybe_newline + result.code;
    textarea.dispatchEvent(new Event('input'));
    textarea.focus();
    textarea.scrollTop = textarea.scrollHeight;
    closeGraphAssistant();
  };

  window.copyGraphAssistantCode = function() {
    var result = buildCurrentCode();
    var err = document.getElementById('ga-error');
    var btn = document.getElementById('ga-copy-btn');
    err.style.display = 'none';

    if (!result.ok) {
      err.textContent = result.msg;
      err.style.display = 'block';
      return;
    }

    navigator.clipboard.writeText(result.code).then(function() {
      var old = btn.textContent;
      btn.textContent = '✅ Copié !';
      setTimeout(function() { btn.textContent = old; }, 1500);
    }).catch(function() {
      err.textContent = 'Impossible de copier dans le presse-papiers.';
      err.style.display = 'block';
    });
  };

  window.resetGraphAssistantForm = function() {
    renderAssistantForm(currentAssistantType);
    document.getElementById('ga-error').style.display = 'none';
  };

  function attachPreviewListeners() {
    var container = document.getElementById('ga-form-container');
    if (!container) return;
    var elements = container.querySelectorAll('input, select, textarea');
    elements.forEach(function(el) {
      var evt = (el.type === 'checkbox' || el.tagName === 'SELECT') ? 'change' : 'input';
      el.addEventListener(evt, updateGraphAssistantPreview);
    });
  }
})();
</script>

</body>
</html>

