<?php
/**
 * @version $Id$
 * @author Thomas Crespin <thomas.crespin@sesamath.net>
 * @copyright Thomas Crespin 2009-2022
 * 
 * ****************************************************************************************************
 * SACoche <https://sacoche.sesamath.net> - Suivi d’Acquisitions de Compétences
 * © Thomas Crespin pour Sésamath <https://www.sesamath.net> - Tous droits réservés.
 * Logiciel placé sous la licence libre Affero GPL 3 <https://www.gnu.org/licenses/agpl-3.0.html>.
 * ****************************************************************************************************
 * 
 * Ce fichier est une partie de SACoche.
 * 
 * SACoche est un logiciel libre ; vous pouvez le redistribuer ou le modifier suivant les termes 
 * de la “GNU Affero General Public License” telle que publiée par la Free Software Foundation :
 * soit la version 3 de cette licence, soit (à votre gré) toute version ultérieure.
 * 
 * SACoche est distribué dans l’espoir qu’il vous sera utile, mais SANS AUCUNE GARANTIE :
 * sans même la garantie implicite de COMMERCIALISABILITÉ ni d’ADÉQUATION À UN OBJECTIF PARTICULIER.
 * Consultez la Licence Publique Générale GNU Affero pour plus de détails.
 * 
 * Vous devriez avoir reçu une copie de la Licence Publique Générale GNU Affero avec SACoche ;
 * si ce n’est pas le cas, consultez : <http://www.gnu.org/licenses/>.
 * 
 */

if(!defined('SACoche')) {exit('Ce fichier ne peut être appelé directement !');}
if($_SESSION['SESAMATH_ID']==ID_DEMO) {}

$remplissage             = Clean::post('f_remplissage'      , 'texte');
$colonne_bilan           = Clean::post('f_colonne_bilan'    , 'texte');
$colonne_vide            = Clean::post('f_colonne_vide'     , 'entier');
$tableau_synthese_format = Clean::post('f_synthese_format'  , 'texte');
$tableau_tri_etat_mode   = Clean::post('f_tri_etat_mode'    , 'texte');
$repeter_entete          = Clean::post('f_repeter_entete'   , 'bool');
$synthese_illimite       = Clean::post('f_synthese_illimite', 'bool');
$matiere_id              = Clean::post('f_matiere'          , 'entier');
$matiere_nom             = Clean::post('f_matiere_nom'      , 'texte');
$groupe_id               = Clean::post('f_groupe'           , 'entier');
$groupe_nom              = Clean::post('f_groupe_nom'       , 'texte');
$groupe_type             = Clean::post('f_groupe_type'      , 'lettres');
$periode_id              = Clean::post('f_periode'          , 'entier');
$date_debut              = Clean::post('f_date_debut'       , 'date_fr');
$date_fin                = Clean::post('f_date_fin'         , 'date_fr');
$retroactif              = Clean::post('f_retroactif'       , 'calcul_retroactif');
$only_etat               = Clean::post('f_only_etat'        , 'texte');
$only_arbo               = Clean::post('f_only_arbo'        , 'texte');
$only_diagnostic         = Clean::post('f_only_diagnostic'  , 'texte');
$only_socle              = Clean::post('f_only_socle'       , 'bool');
$only_valeur             = Clean::post('f_only_valeur'      , 'bool');
$only_prof               = Clean::post('f_only_prof'        , 'bool');
$aff_reference           = Clean::post('f_reference'        , 'bool');
$aff_coef                = Clean::post('f_coef'             , 'bool');
$aff_socle               = Clean::post('f_socle'            , 'bool');
$aff_comm                = Clean::post('f_comm'             , 'bool');
$aff_lien                = Clean::post('f_lien'             , 'bool');
$aff_panier              = Clean::post('f_panier'           , 'bool');
$orientation             = Clean::post('f_orientation'      , 'texte');
$couleur                 = Clean::post('f_couleur'          , 'texte');
$fond                    = Clean::post('f_fond'             , 'texte');
$legende                 = Clean::post('f_legende'          , 'texte');
$marge_min               = Clean::post('f_marge_min'        , 'texte');
$pages_nb                = Clean::post('f_pages_nb'         , 'texte');
$cases_auto              = Clean::post('f_cases_auto'       , 'bool');
$cases_nb                = Clean::post('f_cases_nb'         , 'entier');
$cases_largeur           = Clean::post('f_cases_largeur'    , 'entier');
$eleves_ordre            = Clean::post('f_eleves_ordre'     , 'eleves_ordre', 'nom'); // Non transmis par Safari si dans le <span> avec la classe "hide".
$prof_id                 = Clean::post('f_prof'             , 'entier');
$prof_texte              = Clean::post('f_prof_texte'       , 'texte');
$make_officiel           = FALSE;

// tableaux
$tab_niveau_id = Clean::post('f_niveau', array('array',','));
$tab_eleve_id  = Clean::post('f_eleve' , array('array',','));
$tab_type      = Clean::post('f_type'  , array('array',','));
$tab_niveau_id = array_filter( Clean::map('entier',$tab_niveau_id) , 'positif' );
$tab_eleve_id  = array_filter( Clean::map('entier',$tab_eleve_id)  , 'positif' );
$tab_type      = Clean::map('texte',$tab_type);

// En cas de manipulation du formulaire (avec les outils de développements intégrés au navigateur ou un module complémentaire)...
if(in_array($_SESSION['USER_PROFIL_TYPE'],array('parent','eleve')))
{
  $tab_type   = array('individuel');
  $aff_panier = 1;
}

// Pour un élève on surcharge avec les données de session
if($_SESSION['USER_PROFIL_TYPE']=='eleve')
{
  $tab_eleve_id = array($_SESSION['USER_ID']);
  $groupe_id    = $_SESSION['ELEVE_CLASSE_ID'];
}

// Pour un parent on vérifie que c’est bien un de ses enfants
if( isset($tab_eleve_id[0]) && ($_SESSION['USER_PROFIL_TYPE']=='parent') )
{
  Outil::verif_enfant_parent( $tab_eleve_id[0] );
}

// Pour un professeur on vérifie que ce sont bien ses élèves
if( ($_SESSION['USER_PROFIL_TYPE']=='professeur') && ($_SESSION['USER_JOIN_GROUPES']=='config') )
{
  Outil::verif_eleves_prof( $tab_eleve_id );
}

$type_generique  = (in_array('generique',$tab_type))  ? 1 : 0 ;
$type_individuel = (in_array('individuel',$tab_type)) ? 1 : 0 ;
$type_synthese   = (in_array('synthese',$tab_type))   ? 1 : 0 ;

if($type_generique)
{
  $groupe_id    = 0;
  $tab_eleve_id = array();
}

$liste_eleve = implode(',',$tab_eleve_id);

// Ces 3 choix sont passés de modifiables à imposés pour élèves & parents (25 février 2012) ; il faut les rétablir à leur bonnes valeurs si besoin (1ère soumission du formulaire depuis ce changement).
// Remarque : pour le profil élève on a besoin des notes pour le panier afin de solliciter une évaluation.
if(in_array($_SESSION['USER_PROFIL_TYPE'],array('parent','eleve')))
{
  $remplissage   = 'plein';
  $colonne_bilan = 'oui';
  $colonne_vide  = 0;
}

// Si pas grille générique et si notes demandées ou besoin pour colonne bilan ou besoin pour synthèse
$besoin_notes = ( !$type_generique && ( ($remplissage=='plein') || ($colonne_bilan=='oui') || $type_synthese ) ) ? TRUE : FALSE ;

$niveau_nb = count($tab_niveau_id);

if(
    !$matiere_id || !$niveau_nb || !$matiere_nom || !$remplissage || !$colonne_bilan ||
    ( !$type_generique && ( !$groupe_id || !$groupe_nom || !$groupe_type || !count($tab_eleve_id) ) ) ||
    ( $besoin_notes && !$periode_id && (!$date_debut || !$date_fin) ) ||
    ( $besoin_notes && ( !$retroactif || !$only_etat || !$only_arbo || !$only_diagnostic || ( $only_prof && !$prof_id ) ) ) ||
    !$orientation || !$couleur || !$fond || !$legende || !$marge_min || !$pages_nb || is_null($cases_nb) || !$cases_largeur ||
    !count($tab_type) || !$eleves_ordre
  )
{
  Json::end( FALSE , 'Erreur avec les données transmises !<br>'.pathinfo(__FILE__,PATHINFO_FILENAME).':'.__LINE__ );
}

// Enregistrer les préférences utilisateurs
Form::save_choix('grille_referentiel');

// Pour les évaluations à la volée.
if($_SESSION['USER_PROFIL_TYPE']=='professeur')
{
  Session::generer_jeton_anti_CSRF('evaluation_ponctuelle');
  $CSRF_eval_eclair = Session::$_CSRF_value;
}

// Fermeture de session (mais pas destruction, juste écriture et libération des données pour éviter un verrouillage en écriture)
Session::write_close();

// Bricoles restantes

if($type_generique)
{
  $remplissage   = 'vide';
  $colonne_bilan = 'non';
  $colonne_vide  = 0;
  $type_individuel = 0 ;
  $type_synthese   = 0 ;
}

if($type_generique && $cases_auto)
{
  $cases_nb = 4;
  $cases_largeur = 7;
}

Erreur500::prevention_et_gestion_erreurs_fatales( TRUE /*memory*/ , TRUE /*time*/ );

// Initialisation de tableaux

$tab_niveau             = array();  // [niveau_id] => array(niveau_nom,lignes_nb,longueur_ref_max,niveau_used)
$tab_domaine            = array();  // [niveau_id][domaine_id] => array(domaine_ref,domaine_nom,domaine_nb_lignes,domaine_used)
$tab_theme              = array();  // [domaine_id][theme_id] => array(theme_ref,theme_nom,theme_nb_lignes,theme_used)
$tab_item               = array();  // [theme_id][item_id] => array(item_ref,item_nom,item_coef,item_cart,item_lien,item_used)
$tab_item_synthese      = array();  // [item_id] => array(item_ref,item_nom)
$tab_liste_item         = array();  // [i] => item_id
$tab_eleve_infos        = array();  // [eleve_id] => eleve_nom_prenom
$tab_eval               = array();  // [eleve_id][item_id] => array(note,date,info)
$tab_theme_for_item     = array();  // [item_id] => theme_id
$tab_domaine_for_theme  = array();  // [theme_id] => domaine_id
$tab_niveau_for_domaine = array();  // [domaine_id] => niveau_id
$tab_remove_strong      = array('<strong>','</strong>');

$tab_titre_etat = array(
  'tous'              => 'évalués' ,
  'acquis'            => $tab_remove_strong[0].'réussis'.$tab_remove_strong[1] ,
  'acquis_moyens'     => $tab_remove_strong[0].'réussis ou médians'.$tab_remove_strong[1] ,
  'non_acquis_moyens' => $tab_remove_strong[0].'échoués ou médians'.$tab_remove_strong[1] ,
  'non_acquis'        => $tab_remove_strong[0].'échoués'.$tab_remove_strong[1] ,
  'en_baisse'         => $tab_remove_strong[0].'en baisse'.$tab_remove_strong[1] ,
);
$tab_precision_retroactif = array
(
  'auto'   => 'notes antérieures selon référentiels',
  'oui'    => $tab_remove_strong[0].'avec notes antérieures'.$tab_remove_strong[1],
  'non'    => $tab_remove_strong[0].'sans notes antérieures'.$tab_remove_strong[1],
  'annuel' => $tab_remove_strong[0].'notes antérieures de l’année scolaire'.$tab_remove_strong[1],
);

$bilan_titre_html    = ($besoin_notes) ? 'd’items '.$tab_titre_etat[$only_etat].' d’un référentiel' : 'd’items d’un référentiel' ;
$bilan_titre_pdf_csv = str_replace($tab_remove_strong,'',$bilan_titre_html);

$precision_socle      = $only_socle  ? ', '.$tab_remove_strong[0].'restreint au socle'.$tab_remove_strong[1] : '' ;
$precision_valeur     = $only_valeur ? ', '.$tab_remove_strong[0].'sans codes neutres'.$tab_remove_strong[1] : '' ;
$precision_diagnostic = ( $besoin_notes && ($only_diagnostic=='oui') ) ? ', '.$tab_remove_strong[0].'restreint aux évaluations diagnostiques'.$tab_remove_strong[1] : '' ;
$precision_prof       = ( $besoin_notes && $only_prof ) ? ', '.$tab_remove_strong[0].'restreint à '.$prof_texte.$tab_remove_strong[1] : '' ;

// Initialement de 15, mais certains en veulent toujours plus !
// (ne pas mettre moins de 15 car le formulaire permet de choisir entre 1 à 15 ou automatique selon le nombre de notes)
define('NB_CASES_MAX',50);

// ////////////////////////////////////////////////////////////////////////////////////////////////////
// Période concernée
// ////////////////////////////////////////////////////////////////////////////////////////////////////

if($besoin_notes)
{
  if(!$periode_id)
  {
    $date_sql_debut = To::date_french_to_sql($date_debut);
    $date_sql_fin   = To::date_french_to_sql($date_fin);
  }
  else
  {
    $DB_ROW = DB_STRUCTURE_COMMUN::DB_recuperer_dates_periode($groupe_id,$periode_id);
    if(empty($DB_ROW))
    {
      Json::end( FALSE , 'Le regroupement et la période ne sont pas reliés !' );
    }
    $date_sql_debut = $DB_ROW['jointure_date_debut'];
    $date_sql_fin   = $DB_ROW['jointure_date_fin'];
    $date_debut = To::date_sql_to_french($date_sql_debut);
    $date_fin   = To::date_sql_to_french($date_sql_fin);
  }
  if($date_sql_debut>$date_sql_fin)
  {
    Json::end( FALSE , 'La date de début est postérieure à la date de fin !' );
  }
  $texte_precisions_html = ' - Du '.$date_debut.' au '.$date_fin.', '.$tab_precision_retroactif[$retroactif].$precision_socle.$precision_diagnostic.$precision_valeur.$precision_prof.'.';
}
else
{
  $texte_precisions_html = $precision_socle ? ' - '.$tab_remove_strong[0].'Restreint au socle'.$tab_remove_strong[1] : '' ;
}

$texte_precisions_pdf_csv = str_replace($tab_remove_strong,'',$texte_precisions_html);

// ////////////////////////////////////////////////////////////////////////////////////////////////////
// Récupération de la liste des items pour la matière et le niveau sélectionné
// ////////////////////////////////////////////////////////////////////////////////////////////////////

$niveau_id = ($niveau_nb==1) ? $tab_niveau_id[0] : 0 ;
$DB_TAB = DB_STRUCTURE_COMMUN::DB_recuperer_arborescence( 0 /*prof_id*/ , $matiere_id , $niveau_id , $only_socle , FALSE /*only_item*/ , FALSE /*s2016_count*/ , TRUE /*item_comm*/ , FALSE /*item_module*/ );
if(!empty($DB_TAB))
{
  $niveau_key = 0;
  $domaine_id = 0;
  $theme_id   = 0;
  $item_id    = 0;
  foreach($DB_TAB as $DB_ROW)
  {
    if( ($niveau_nb==1) || in_array($DB_ROW['niveau_id'],$tab_niveau_id) )
    {
      if( (!is_null($DB_ROW['niveau_id'])) && ($DB_ROW['niveau_id']!=$niveau_key) )
      {
        $niveau_key = $DB_ROW['niveau_id'];
        $tab_niveau[$niveau_key] = array(
        'niveau_nom'       => $DB_ROW['niveau_nom'],
        'lignes_nb'        => 0,
        'longueur_ref_max' => 0,
        'niveau_used'      => FALSE,
        );
      }
      if( (!is_null($DB_ROW['domaine_id'])) && ($DB_ROW['domaine_id']!=$domaine_id) )
      {
        $domaine_id  = $DB_ROW['domaine_id'];
        $domaine_ref = ($DB_ROW['domaine_ref']) ? $DB_ROW['domaine_ref'] : $DB_ROW['niveau_ref'].'.'.$DB_ROW['domaine_code'] ;
        $tab_domaine[$niveau_key][$domaine_id] = array(
          'domaine_ref'       => $domaine_ref,
          'domaine_nom'       => $DB_ROW['domaine_nom'],
          'domaine_nb_lignes' => 2,
          'domaine_used'      => FALSE,
        );
        $tab_niveau_for_domaine[$domaine_id] = $niveau_key;
        $tab_niveau[$niveau_key]['longueur_ref_max'] = max( $tab_niveau[$niveau_key]['longueur_ref_max'] , strlen($domaine_ref) );
        $tab_niveau[$niveau_key]['lignes_nb']++;
      }
      if( (!is_null($DB_ROW['theme_id'])) && ($DB_ROW['theme_id']!=$theme_id) )
      {
        $theme_id  = $DB_ROW['theme_id'];
        $theme_ref = ($DB_ROW['domaine_ref'] || $DB_ROW['theme_ref']) ? $DB_ROW['domaine_ref'].$DB_ROW['theme_ref'] : $DB_ROW['niveau_ref'].'.'.$DB_ROW['domaine_code'].$DB_ROW['theme_ordre'] ;
        $first_theme_of_domaine = isset($tab_theme[$domaine_id]) ? FALSE : TRUE ;
        $tab_theme[$domaine_id][$theme_id] = array(
          'theme_ref'       => $theme_ref,
          'theme_nom'       => $DB_ROW['theme_nom'],
          'theme_nb_lignes' => 1,
          'theme_used'      => FALSE,
        );
        $tab_domaine_for_theme[$theme_id] = $domaine_id;
        $tab_niveau[$niveau_key]['longueur_ref_max'] = max( $tab_niveau[$niveau_key]['longueur_ref_max'] , strlen($theme_ref) );
        $tab_niveau[$niveau_key]['lignes_nb']++;
      }
      if( (!is_null($DB_ROW['item_id'])) && ($DB_ROW['item_id']!=$item_id) )
      {
        $item_id = $DB_ROW['item_id'];
        $item_ref = ($DB_ROW['domaine_ref'] || $DB_ROW['theme_ref'] || $DB_ROW['item_ref']) ? $DB_ROW['domaine_ref'].$DB_ROW['theme_ref'].$DB_ROW['item_ref'] : $DB_ROW['niveau_ref'].'.'.$DB_ROW['domaine_code'].$DB_ROW['theme_ordre'].$DB_ROW['item_ordre'] ;
        $tab_item[$theme_id][$item_id] = array(
          'item_ref'   => $item_ref,
          'item_nom'   => $DB_ROW['item_nom'],
          'item_coef'  => $DB_ROW['item_coef'],
          'item_cart'  => $DB_ROW['item_cart'],
          'item_comm'  => $DB_ROW['item_comm'],
          'item_lien'  => $DB_ROW['item_lien'],
          'item_used'  => FALSE,
        );
        $tab_theme_for_item[$item_id] = $theme_id;
        $tab_item_synthese[$item_id] = array(
          'item_ref'  => $DB_ROW['matiere_ref'].'.'.$item_ref,
          'item_nom'  => $DB_ROW['item_nom'],
          'item_coef' => $DB_ROW['item_coef']
        );
        $tab_theme[$domaine_id][$theme_id]['theme_nb_lignes']++;
        if($first_theme_of_domaine)
        {
          $tab_domaine[$niveau_key][$domaine_id]['domaine_nb_lignes']++;
        }
        $tab_liste_item[$item_id] = $item_id;
        $tab_niveau[$niveau_key]['longueur_ref_max'] = max( $tab_niveau[$niveau_key]['longueur_ref_max'] , strlen($item_ref) );
        $tab_niveau[$niveau_key]['lignes_nb']++;
      }
    }
  }
}
$item_nb = count($tab_liste_item);
if(!$item_nb)
{
  Json::end( FALSE , 'Aucun item référencé pour cette matière et ce niveau !' );
}
$liste_item = implode(',',$tab_liste_item);

// ////////////////////////////////////////////////////////////////////////////////////////////////////
// Récupération de la liste des élèves (si demandé)
// ////////////////////////////////////////////////////////////////////////////////////////////////////

if($_SESSION['USER_PROFIL_TYPE']=='eleve')
{
  $tab_eleve_infos[$_SESSION['USER_ID']] = To::texte_eleve_identite($_SESSION['USER_NOM'],$_SESSION['USER_PRENOM'],$eleves_ordre);
}
elseif(count($tab_eleve_id))
{
  $tab_eleve_infos = DB_STRUCTURE_BILAN::DB_lister_eleves_cibles( $liste_eleve , $groupe_type , $eleves_ordre );
  if(!is_array($tab_eleve_infos))
  {
    Json::end( FALSE , 'Aucun élève trouvé correspondant aux identifiants transmis !' );
  }
  else
  {
    foreach($tab_eleve_infos as $eleve_id => $tab_eleve)
    {
      $tab_eleve_infos[$eleve_id] = To::texte_eleve_identite($tab_eleve['eleve_nom'],$tab_eleve['eleve_prenom'],$eleves_ordre);
    }
  }
}
else
{
  $tab_eleve_infos[0] = '';
}
$eleve_nb = count( $tab_eleve_infos , COUNT_NORMAL );

// ////////////////////////////////////////////////////////////////////////////////////////////////////
// Récupération de la liste des résultats
// ////////////////////////////////////////////////////////////////////////////////////////////////////

if($besoin_notes)
{
  $only_prof_id = ($only_prof) ? $prof_id : FALSE ;
  // Récupération de calcul_methode ; calcul_limite ; calcul_retroactif
  $DB_TAB = DB_STRUCTURE_COMMUN::DB_lister_referentiels_infos_details_matieres_niveaux( $matiere_id , $niveau_id );
  $calcul_methode    = $DB_TAB[0]['referentiel_calcul_methode'];
  $calcul_limite     = $DB_TAB[0]['referentiel_calcul_limite'];
  $calcul_retroactif = $DB_TAB[0]['referentiel_calcul_retroactif'];
  // Détermination de la date de départ
  $retroactif = ($retroactif=='auto') ? $calcul_retroactif : $retroactif ; // Ne peut plus valoir que "oui" | "non" | "annuel" à présent (possible car un unique référentiel est considéré ici)
  $date_sql_debut_annee_scolaire = To::jour_debut_annee_scolaire('sql');
  $date_sql_start = Outil::date_sql_start( $retroactif , $date_sql_debut , $date_sql_debut_annee_scolaire );
  $DB_TAB = DB_STRUCTURE_BILAN::DB_lister_result_eleves_items( $liste_eleve , $liste_item , $matiere_id , $only_diagnostic , $date_sql_start , $date_sql_fin , $_SESSION['USER_PROFIL_TYPE'] , $only_prof_id , $only_valeur , FALSE /*onlynote*/ ) ;
  if( empty($DB_TAB) && ($only_arbo!='tous') )
  {
    Json::end( FALSE , 'Aucune note trouvée alors que votre paramétrage requiert la présence de résultats !'.$texte_precisions_html );
  }
  foreach($DB_TAB as $DB_ROW)
  {
    $user_id = ($_SESSION['USER_PROFIL_TYPE']=='eleve') ? $_SESSION['USER_ID'] : $DB_ROW['eleve_id'] ;
    $item_id = $DB_ROW['item_id'];
    $tab_eval[$user_id][$item_id][] = array(
      'note' => $DB_ROW['note'],
      'date' => $DB_ROW['date'],
      'info' => $DB_ROW['info'],
    );
    $theme_id   = $tab_theme_for_item[$item_id];
    $domaine_id = $tab_domaine_for_theme[$theme_id];
    $niveau_key = $tab_niveau_for_domaine[$domaine_id];
    $tab_item[$theme_id][$item_id]['item_used'] = TRUE;
    $tab_theme[$domaine_id][$theme_id]['theme_used'] = TRUE;
    $tab_domaine[$niveau_key][$domaine_id]['domaine_used'] = TRUE;
    $tab_niveau[$niveau_key]['niveau_used'] = TRUE;
  }
}

// ////////////////////////////////////////////////////////////////////////////////////////////////////
// Restriction de la grille si demandé
// ////////////////////////////////////////////////////////////////////////////////////////////////////

if( $besoin_notes && ($only_arbo!='tous') )
{
  // Pour chaque niveau...
  if(count($tab_niveau))
  {
    foreach($tab_niveau as $niveau_key => $tab)
    {
      $delete_domaine = FALSE;
      extract($tab);  // $niveau_nom $lignes_nb $longueur_ref_max $niveau_used
      if( !$niveau_used && ( ($only_arbo=='niveau') || ($only_arbo=='domaine') || ($only_arbo=='theme') || ($only_arbo=='item') ) )
      {
        $delete_domaine = TRUE;
        unset($tab_niveau[$niveau_key]);
      }
      // Pour chaque domaine...
      if(isset($tab_domaine[$niveau_key]))
      {
        foreach($tab_domaine[$niveau_key] as $domaine_id => $tab)
        {
          $delete_theme = FALSE;
          extract($tab);  // $domaine_ref $domaine_nom $domaine_nb_lignes $domaine_used
          if( !$domaine_used && ( ($only_arbo=='domaine') || ($only_arbo=='theme') || ($only_arbo=='item') ) )
          {
            $delete_theme = TRUE;
            unset($tab_domaine[$niveau_key][$domaine_id]);
            if(!$delete_domaine)
            {
              $tab_niveau[$niveau_key]['lignes_nb']--;
            }
          }
          // Pour chaque thème...
          if(isset($tab_theme[$domaine_id]))
          {
            foreach($tab_theme[$domaine_id] as $theme_id => $tab)
            {
              $delete_item = FALSE;
              extract($tab);  // $theme_ref $theme_nom $theme_nb_lignes $theme_used
              if( $delete_theme || ( !$theme_used && ( ($only_arbo=='theme') || ($only_arbo=='item') ) ) )
              {
                $delete_item = TRUE;
                unset($tab_theme[$domaine_id][$theme_id]);
                if(!$delete_domaine)
                {
                  $tab_niveau[$niveau_key]['lignes_nb']--;
                }
              }
              // Pour chaque item...
              if(isset($tab_item[$theme_id]))
              {
                foreach($tab_item[$theme_id] as $item_id => $tab)
                {
                  extract($tab);  // $item_ref $item_nom $item_coef $item_cart $item_lien $item_used
                  if( $delete_item || ( !$item_used && ($only_arbo=='item') ) )
                  {
                    unset($tab_item[$theme_id][$item_id]);
                    unset($tab_liste_item[$item_id]);
                    if(!$delete_domaine)
                    {
                      $tab_niveau[$niveau_key]['lignes_nb']--;
                    }
                    $item_nb--;
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

// ////////////////////////////////////////////////////////////////////////////////////////////////////
// Vérification quantité de données réaliste
// ////////////////////////////////////////////////////////////////////////////////////////////////////

$synthese_surnombre = ( ($item_nb>100) || ($eleve_nb>100) ) ? TRUE : FALSE ;

if( $type_synthese && $synthese_surnombre && !$synthese_illimite )
{
  $tab_indications = array();
  if( ($item_nb>100) && ($niveau_nb>1) )
  {
    $tab_indications[] = ' sélectionner moins de niveaux à la fois';
  }
  if($eleve_nb>100)
  {
    $tab_indications[] = ' sélectionner moins d’élèves à la fois';
  }
  if( $besoin_notes && ($only_arbo=='tous') )
  {
    $tab_indications[] = ' restreindre aux seuls éléments évalués (dans les options)';
  }
  else if( $besoin_notes && ($only_arbo!='item') )
  {
    $tab_indications[] = ' restreindre davantage les éléments évalués (dans les options)';
  }
  if(!empty($tab_indications))
  {
    Json::end( FALSE , 'Trop de données à afficher ('.$item_nb.' items) pour la synthèse :'.implode(',',$tab_indications).', ou cocher la case pour forcer la génération malgré tout.' );
  }
}

if( $type_individuel && ($eleve_nb>1) && ( $eleve_nb*$item_nb > 5000 ) )
{
  $tab_indications = array();
  if($niveau_nb>1)
  {
    $tab_indications[] = ' sélectionner moins de niveaux à la fois';
  }
  if($eleve_nb>100)
  {
    $tab_indications[] = ' sélectionner moins d’élèves à la fois';
  }
  if( $besoin_notes && ($only_arbo=='tous') )
  {
    $tab_indications[] = ' restreindre aux seuls éléments évalués (dans les options)';
  }
  else if( $besoin_notes && ($only_arbo!='item') )
  {
    $tab_indications[] = ' restreindre davantage les éléments évalués (dans les options)';
  }
  if(!empty($tab_indications))
  {
    Json::end( FALSE , 'Trop de données à afficher ('.($eleve_nb*$item_nb).' lignes) pour le relevé :'.implode(',',$tab_indications).'.' );
  }
}

// Nombre de demandes d’évaluation autorisées pour la matière concernée
$matiere_nb_demandes = DB_STRUCTURE_DEMANDE::DB_recuperer_demandes_autorisees_matiere($matiere_id);

// Liste des matières d’un prof
$listing_prof_matieres_id = ( $type_individuel && ($_SESSION['USER_PROFIL_TYPE']=='professeur') ) ? DB_STRUCTURE_COMMUN::DB_recuperer_matieres_professeur($_SESSION['USER_ID']) : '' ;
$tab_prof_matieres_id = !empty($listing_prof_matieres_id) ? explode(',',$listing_prof_matieres_id) : array() ;

// ////////////////////////////////////////////////////////////////////////////////////////////////////
/* 
 * Libérer de la place mémoire car les scripts de bilans sont assez gourmands.
 * Supprimer $DB_TAB ne fonctionne pas si on ne force pas auparavant la fermeture de la connexion.
 * SebR devrait peut-être envisager d’ajouter une méthode qui libère cette mémoire, si c’est possible...
 */
// ////////////////////////////////////////////////////////////////////////////////////////////////////

DB::close(SACOCHE_STRUCTURE_BD_NAME);
unset($DB_TAB);

// ////////////////////////////////////////////////////////////////////////////////////////////////////
// Tableaux et variables pour mémoriser les infos ; dans cette partie on ne fait que les calculs (aucun affichage)
// ////////////////////////////////////////////////////////////////////////////////////////////////////

$niveau_nom_global = ($niveau_nb==1) ? 'Niveau '.$tab_niveau[$niveau_id]['niveau_nom'] : 'multi-niveaux' ;
$fichier = 'grille_item_'.Clean::fichier($matiere_nom).'_'.Clean::fichier($niveau_nom_global).'_<REPLACE>_'.FileSystem::generer_fin_nom_fichier__date_et_alea();
$fichier_nom_type1 = ($type_generique) ? str_replace( '<REPLACE>' , 'generique' , $fichier ) : str_replace( '<REPLACE>' , Clean::fichier($groupe_nom).'_individuel' , $fichier ) ;
$fichier_nom_type2 = str_replace( '<REPLACE>' , Clean::fichier($groupe_nom).'_synthese' , $fichier ) ;

$tab_score_eleve_item         = array();  // Retenir les scores / élève / item
$tab_score_item_eleve         = array();  // Retenir les scores / item / élève
$tab_moyenne_scores_eleve     = array();  // Retenir la moyenne des scores d’acquisitions / élève
$tab_pourcentage_acquis_eleve = array();  // Retenir le pourcentage d’items acquis / élève
$tab_moyenne_scores_item      = array();  // Retenir la moyenne des scores d’acquisitions / item
$tab_pourcentage_acquis_item  = array();  // Retenir le pourcentage d’items acquis / item
$moyenne_moyenne_scores       = 0;  // moyenne des moyennes des scores d’acquisitions
$moyenne_pourcentage_acquis   = 0;  // moyenne des moyennes des pourcentages d’items acquis

/*
  Calcul des états d’acquisition (si besoin) et des données nécessaires pour le tableau de synthèse (si besoin).
  $tab_score_eleve_item[$eleve_id][$item_id]
  $tab_score_item_eleve[$item_id][$eleve_id]
  $tab_moyenne_scores_eleve[$eleve_id]
  $tab_pourcentage_acquis_eleve[$eleve_id]
*/

if(count($tab_eval))
{
  foreach($tab_eval as $eleve_id => $tab_items) // Ne pas écraser $tab_item déjà utilisé
  {
    foreach($tab_items as $item_id => $tab_devoirs)
    {
      // calcul du bilan de l’item
      $score = OutilBilan::calculer_score( $tab_devoirs , $calcul_methode , $calcul_limite , $date_sql_debut );
      if( ($only_etat=='tous') || ( ($only_etat=='en_baisse') && OutilBilan::tester_en_baisse($tab_devoirs) ) || ( ($only_etat!='en_baisse') && OutilBilan::tester_acquisition( $score , $only_etat ) ) )
      {
        $tab_score_eleve_item[$eleve_id][$item_id] = $score;
        if($type_synthese)
        {
          $tab_score_item_eleve[$item_id][$eleve_id] = $score;
        }
      }
      else
      {
        unset( $tab_eval[$eleve_id][$item_id] );
      }
    }
    if( ($only_etat=='tous') || !empty($tab_score_eleve_item[$eleve_id]) )
    {
      if($type_synthese)
      {
        // calcul des bilans des scores
        $tableau_score_filtre = array_filter($tab_score_eleve_item[$eleve_id],'non_vide');
        $nb_scores = count( $tableau_score_filtre );
        // la moyenne peut être pondérée par des coefficients
        $somme_scores_ponderes = 0;
        $somme_coefs = 0;
        if($nb_scores)
        {
          foreach($tableau_score_filtre as $item_id => $item_score)
          {
            $somme_scores_ponderes += $item_score*$tab_item_synthese[$item_id]['item_coef'];
            $somme_coefs += $tab_item_synthese[$item_id]['item_coef'];
          }
        }
        // ... un pour la moyenne des pourcentages d’acquisition
        if($somme_coefs)
        {
          $tab_moyenne_scores_eleve[$eleve_id] = round($somme_scores_ponderes/$somme_coefs,0);
        }
        else
        {
          $tab_moyenne_scores_eleve[$eleve_id] = FALSE;
        }
        // ... un pour le nombre d’items considérés acquis ou pas
        if($nb_scores)
        {
          $tab_acquisitions = OutilBilan::compter_nombre_acquisitions_par_etat( $tableau_score_filtre , 0 /*aff_prop_sans_score*/ );
          $tab_pourcentage_acquis_eleve[$eleve_id] = OutilBilan::calculer_pourcentage_acquisition_items( $tab_acquisitions , $nb_scores );
        }
        else
        {
          $tab_pourcentage_acquis_eleve[$eleve_id] = FALSE;
        }
      }
    }
    else
    {
      // Cas où, à cause de la restriction à des items échoués ou réussis, on n’a plus d’évaluation pour un élève
      unset( $tab_eval[$eleve_id] );
    }
  }
}

/*
  On renseigne (uniquement utile pour le tableau de synthèse) :
  $tab_moyenne_scores_item[$item_id]
  $tab_pourcentage_acquis_item[$item_id]
*/

if($type_synthese)
{
  // Pour chaque item...
  foreach($tab_liste_item as $item_id)
  {
    $tableau_score_filtre = isset($tab_score_item_eleve[$item_id]) ? array_filter($tab_score_item_eleve[$item_id],'non_vide') : array() ; // Test pour éviter de rares "array_filter() expects parameter 1 to be array, null given"
    $nb_scores = count( $tableau_score_filtre );
    if($nb_scores)
    {
      $somme_scores = array_sum($tableau_score_filtre);
      $tab_acquisitions = OutilBilan::compter_nombre_acquisitions_par_etat( $tableau_score_filtre , 0 /*aff_prop_sans_score*/ );
      $tab_moyenne_scores_item[$item_id]     = round($somme_scores/$nb_scores,0);
      $tab_pourcentage_acquis_item[$item_id] = OutilBilan::calculer_pourcentage_acquisition_items( $tab_acquisitions , $nb_scores );
    }
    else
    {
      $tab_moyenne_scores_item[$item_id]     = FALSE;
      $tab_pourcentage_acquis_item[$item_id] = FALSE;
    }
  }
}

/*
  On renseigne (utile pour le tableau de synthèse et le bulletin) :
  $moyenne_moyenne_scores
  $moyenne_pourcentage_acquis
*/
/*
  on pourrait calculer de 2 façons chacune des deux valeurs...
  pour la moyenne des moyennes obtenues par élève : c’est simple car les coefs ont déjà été pris en compte dans le calcul pour chaque élève
  pour la moyenne des moyennes obtenues par item : c’est compliqué car il faudrait repondérer par les coefs éventuels de chaque item
  donc la 1ère technique a été retenue, à défaut d’essayer de calculer les deux et d’en faire la moyenne ;-)
*/

if( $type_synthese )
{
  // $moyenne_moyenne_scores
  $somme  = array_sum($tab_moyenne_scores_eleve);
  $nombre = count( array_filter($tab_moyenne_scores_eleve,'non_vide') );
  $moyenne_moyenne_scores = ($nombre) ? round($somme/$nombre,0) : FALSE;
  // $moyenne_pourcentage_acquis
  $somme  = array_sum($tab_pourcentage_acquis_eleve);
  $nombre = count( array_filter($tab_pourcentage_acquis_eleve,'non_vide') );
  $moyenne_pourcentage_acquis = ($nombre) ? round($somme/$nombre,0) : FALSE;
}

// ////////////////////////////////////////////////////////////////////////////////////////////////////
// On tronque les notes les plus anciennes s’il y en a trop par rapport au nombre de colonnes affichées.
// On tronque les notes antérieures qui n’auraient été récupérées que pour le calcul du score. => Non, on les affiche aussi
// ////////////////////////////////////////////////////////////////////////////////////////////////////

if( $type_individuel && ($remplissage=='plein') )
{
  if($cases_auto)
  {
    // Déterminer le nombre de colonnes optimal
    $cases_nb = 0;
    foreach($tab_eleve_id as $eleve_id)
    {
      foreach($tab_liste_item as $item_id)
      {
        $eval_nb = (isset($tab_eval[$eleve_id][$item_id])) ? count($tab_eval[$eleve_id][$item_id]) : 0 ;
        $cases_nb = max( $cases_nb , $eval_nb );
      }
    }
    $cases_nb = min( $cases_nb , NB_CASES_MAX );
    $cases_largeur = max( 5 , min( 12-$cases_nb , 8 ) );
  }

  foreach($tab_eleve_id as $eleve_id)
  {
    foreach($tab_liste_item as $item_id)
    {
      $eval_nb = (isset($tab_eval[$eleve_id][$item_id])) ? count($tab_eval[$eleve_id][$item_id]) : 0 ;
      // test si trop de notes par rapport au nb de cases
      if($eval_nb>$cases_nb)
      {
        $tab_eval[$eleve_id][$item_id] = array_slice($tab_eval[$eleve_id][$item_id],$eval_nb-$cases_nb);
      }
    }
  }
}

// ////////////////////////////////////////////////////////////////////////////////////////////////////
// Elaboration de la grille d’items d’un référentiel, en HTML et PDF
// ////////////////////////////////////////////////////////////////////////////////////////////////////

$affichage_direct   = ( ( in_array($_SESSION['USER_PROFIL_TYPE'],array('eleve','parent')) ) && (SACoche!='webservices') ) ? TRUE : FALSE ;
$affichage_checkbox = ( $type_synthese && ($_SESSION['USER_PROFIL_TYPE']=='professeur') && (SACoche!='webservices') )     ? TRUE : FALSE ;

if( $type_generique || $type_individuel )
{
  $precision_vierge = ($besoin_notes) ? '' : ' (vierge)' ;
  $jour_debut_annee_scolaire = To::jour_debut_annee_scolaire('sql'); // Date de fin de l’année scolaire précédente
  // Infos socle
  if($aff_socle)
  {
    $DB_TAB_socle2016 = DB_STRUCTURE_REFERENTIEL::DB_recuperer_socle2016_for_referentiel_matiere_niveau( $matiere_id , $niveau_id , 'ids' /*format*/ );
  }
  // Initialiser au cas où $aff_coef / $aff_socle / $aff_comm / $aff_lien sont à 0
  $texte_coef       = '';
  $texte_socle      = '';
  $texte_s2016      = '';
  $texte_comm       = '';
  $texte_lien_avant = '';
  $texte_lien_apres = '';
  // Les variables $html et $pdf vont contenir les sorties
  $colspan_nb_apres = ($colonne_bilan=='non') ? $cases_nb : $cases_nb+1 ;
  $colspan_th_apres = ($colspan_nb_apres) ? '<th colspan="'.$colspan_nb_apres.'" class="nu"></th>' : '' ;
  Html::$couleur = $couleur ;
  $html  = $affichage_direct ? '' : '<style>'.$_SESSION['CSS'].'</style>'.NL;
  $html .= $make_officiel    ? '' : '<h1>Grille '.$bilan_titre_html.$precision_vierge.'</h1>'.NL;
  $separation = (count($tab_eleve_infos)>1) ? '<hr>'.NL : '' ;
  $ETABLISSEMENT_NOM = $_SESSION['ETABLISSEMENT']['DENOMINATION'];
  $pdf = new PDF_grille_referentiel( FALSE /*officiel*/ , 'A4' /*page_size*/ , $orientation , $marge_min /*marge_gauche*/ , $marge_min /*marge_droite*/ , $marge_min /*marge_haut*/ , $marge_min /*marge_bas*/ , $couleur , $fond , $legende , $ETABLISSEMENT_NOM );
  // Pour chaque élève...
  foreach($tab_eleve_infos as $eleve_id => $eleve_nom_prenom)
  {
    $html .= ($eleve_id) ? $separation.'<h2>'.html($eleve_nom_prenom).'</h2>'.NL : $separation.'<h2>Grille générique</h2>'.NL ;
    // Pour chaque niveau...
    if(count($tab_niveau))
    {
      foreach($tab_niveau as $niveau_key => $tab)
      {
        extract($tab);  // $niveau_nom $lignes_nb $longueur_ref_max $niveau_used
        $longueur_ref_max = $aff_reference ? $longueur_ref_max : 0 ;
        $colspan_th_avant = ($longueur_ref_max) ? ' colspan="2"' : '' ;
        $html .= $make_officiel ? '' : '<h2>'.html($matiere_nom.' - Niveau '.$niveau_nom).$texte_precisions_html.'</h2>'.NL;
        $pdf->initialiser( $cases_nb , $cases_largeur , $lignes_nb , $longueur_ref_max , $colonne_bilan , $colonne_vide , ($retroactif!='non') /*anciennete_notation*/ , ($colonne_bilan=='oui') /*score_bilan*/ , $pages_nb );
        // On met le document au nom de l’élève, ou on établit un document générique
        $pdf->entete( 'Grille '.$bilan_titre_pdf_csv.$precision_vierge , $matiere_nom.' - Niveau '.$niveau_nom.$texte_precisions_pdf_csv , $eleve_id , $eleve_nom_prenom );
        $html .= '<table class="bilan">'.NL;
        // Pour chaque domaine...
        if(isset($tab_domaine[$niveau_key]))
        {
          foreach($tab_domaine[$niveau_key] as $domaine_id => $tab)
          {
            extract($tab);  // $domaine_ref $domaine_nom $domaine_nb_lignes $domaine_used
            $html .= '<tr><th'.$colspan_th_avant.' class="domaine">'.html($domaine_nom).'</th>'.$colspan_th_apres.'<th class="nu"></th></tr>'.NL;
            $pdf->domaine( $domaine_nom , $domaine_nb_lignes );
            // Pour chaque thème...
            if(isset($tab_theme[$domaine_id]))
            {
              foreach($tab_theme[$domaine_id] as $theme_id => $tab)
              {
                extract($tab);  // $theme_ref $theme_nom $theme_nb_lignes $theme_used
                $th_ref = ($longueur_ref_max) ? '<th>'.$theme_ref.'</th>' : '' ;
                $html .= '<tr>'.$th_ref.'<th>'.html($theme_nom).'</th>'.$colspan_th_apres.'</tr>'.NL;
                $pdf->theme( $theme_ref , $theme_nom , $theme_nb_lignes );
                // Pour chaque item...
                if(isset($tab_item[$theme_id]))
                {
                  foreach($tab_item[$theme_id] as $item_id => $tab)
                  {
                    extract($tab);  // $item_ref $item_nom $item_coef $item_cart $item_lien $item_used
                    if($aff_coef)
                    {
                      $texte_coef = '[×'.$item_coef.'] ';
                    }
                    if($aff_socle)
                    {
                      $socle_nb = !isset($DB_TAB_socle2016[$item_id]) ? 0 : count($DB_TAB_socle2016[$item_id]) ;
                      $texte_s2016 = (!$socle_nb) ? '[–] ' : ( ($socle_nb>1) ? '['.$socle_nb.'c.] ' : '['.($DB_TAB_socle2016[$item_id][0]['composante']/10).'] ' ) ;
                    }
                    if($aff_comm)
                    {
                      $image_comm  = ($item_comm) ? 'oui' : 'non' ;
                      $title_comm  = ($item_comm) ? $item_comm : 'Sans commentaire.' ;
                      $texte_comm  = '<img src="./_img/etat/comm_'.$image_comm.'.png"'.infobulle($title_comm).'"> ';
                    }
                    if($aff_lien)
                    {
                      $texte_lien_avant = ($item_lien) ? '<a target="_blank" rel="noopener noreferrer" href="'.html($item_lien).'">' : '';
                      $texte_lien_apres = ($item_lien) ? '</a>' : '';
                    }
                    $score = isset($tab_score_eleve_item[$eleve_id][$item_id]) ? $tab_score_eleve_item[$eleve_id][$item_id] : FALSE ;
                    $icones_action = ( ($_SESSION['USER_PROFIL_TYPE']=='professeur') && in_array($matiere_id,$tab_prof_matieres_id) )
                                   ? '<q class="ajouter_note"'.infobulle('Ajouter une évaluation à la volée.').'></q>'
                                   . '<q class="modifier_note"'.infobulle('Modifier à la volée une saisie d’évaluation.').'></q>'
                                   : '' ;
                    if($aff_panier)
                    {
                      $debut_date = isset($tab_eval[$eleve_id][$item_id][0]) ? $tab_eval[$eleve_id][$item_id][0]['date'] : '' ;
                      if(!$matiere_nb_demandes) { $icones_action .= '<q class="demander_non"'.infobulle('Pas de demande autorisée pour les items de cette matière.').'></q>'; }
                      elseif(!$item_cart)       { $icones_action .= '<q class="demander_non"'.infobulle('Pas de demande autorisée pour cet item précis.').'></q>'; }
                      else                      { $icones_action .= '<q class="demander_add" data-score="'.( $score ? $score : -1 ).'" data-date="'.$debut_date.'"'.infobulle('Ajouter aux demandes d’évaluations.').'></q>'; }
                    }
                    $td_actions = '<td class="nu" data-matiere="'.$matiere_id.'" data-item="'.$item_id.'" data-eleve="'.$eleve_id.'">'.$icones_action.'</td>';
                    $td_ref = ($longueur_ref_max) ? '<td>'.$item_ref.'</td>' : '' ;
                    $html .= '<tr>'.$td_ref.'<td>'.$texte_coef.$texte_s2016.$texte_comm.$texte_lien_avant.html($item_nom).$texte_lien_apres.'</td>';
                    $pdf->item( $item_ref , $texte_coef.$texte_s2016.$item_nom , $colspan_nb_apres );
                    // Pour chaque case...
                    if($colspan_nb_apres)
                    {
                      for($i=0;$i<$cases_nb;$i++)
                      {
                        if($remplissage=='plein')
                        {
                          if(isset($tab_eval[$eleve_id][$item_id][$i]))
                          {
                            extract($tab_eval[$eleve_id][$item_id][$i]);  // $note $date $info
                          }
                          else
                          {
                            $note = '-'; $date = ''; $info = '';
                          }
                          if( $date && ($date<$jour_debut_annee_scolaire) )
                          {
                            $pdf_bg = 'prev_year';
                            $td_class = ' class="prev_year"';
                            $fond_gris = TRUE;
                          }
                          elseif( $date && ($date<$date_sql_debut) )
                          {
                            $pdf_bg = 'prev_date';
                            $td_class = ' class="prev_date"';
                            $fond_gris = TRUE;
                          }
                          else
                          {
                            $pdf_bg = '';
                            $td_class = '';
                            $fond_gris = FALSE;
                          }
                          $html .= '<td'.$td_class.'>'.Html::note_image($note,$date,$info,FALSE,$fond_gris).'</td>';
                          $pdf->afficher_note_lomer( $note , 1 /*border*/ , floor(($i+1)/$colspan_nb_apres) /*br*/ , $pdf_bg );
                        }
                        else
                        {
                          $html .= '<td>&nbsp;</td>';
                          $pdf->Cell( $cases_largeur , $pdf->cases_hauteur , '' , 1 , floor(($i+1)/$colspan_nb_apres) , 'C' , TRUE , '' );
                        }
                      }
                      // Case bilan
                      if($colonne_bilan=='oui')
                      {
                        $html .= Html::td_score($score,'score');
                        $pdf->afficher_score_bilan( $score , 1 /*br*/ );
                      }
                    }
                    $html .= $td_actions.'</tr>'.NL;
                  }
                }
              }
            }
          }
        }
        $html .= '</table>'.NL;
      }
    }
    if($legende=='oui')
    {
      $tab_legende = array(
        'codes_notation'      => TRUE ,
        'anciennete_notation' => ($retroactif!='non') ,
        'score_bilan'         => ($colonne_bilan=='oui') ,
      );
      $pdf->legende();
      $html .= Html::legende($tab_legende);
    }
  }
  if($_SESSION['USER_PROFIL_TYPE']=='professeur')
  {
    $script = 'var CSRF = "'.$CSRF_eval_eclair.'";'; // Pour les évaluations à la volée.
    $html .= '<script>'.$script.'</script>'.NL;
  }
  // On enregistre les sorties HTML et PDF
  FileSystem::ecrire_fichier(   CHEMIN_DOSSIER_EXPORT.$fichier_nom_type1.'.html' , $html );
  FileSystem::ecrire_objet_pdf( CHEMIN_DOSSIER_EXPORT.$fichier_nom_type1.'.pdf'  , $pdf );
}

// ////////////////////////////////////////////////////////////////////////////////////////////////////
// Elaboration de la synthèse collective en HTML et PDF
// ////////////////////////////////////////////////////////////////////////////////////////////////////

if($type_synthese)
{
  $msg_socle = ($only_socle) ? ' - Socle uniquement' : '' ;
  Html::$couleur = $couleur ;
  $html  = $affichage_direct ? '' : '<style>'.$_SESSION['CSS'].'</style>'.NL;
  $html .= $affichage_direct ? '' : '<h1>Bilan '.$bilan_titre_html.'</h1>'.NL;
  $html .= '<h2>'.html($matiere_nom.' - '.$niveau_nom_global).$texte_precisions_html.'</h2>'.NL;
  // Appel de la classe et redéfinition de qqs variables supplémentaires pour la mise en page PDF
  // On définit l’orientation la plus adaptée
  $orientation = ( ( ($eleve_nb>$item_nb) && ($tableau_synthese_format=='eleve') ) || ( ($item_nb>$eleve_nb) && ($tableau_synthese_format=='item') ) ) ? 'portrait' : 'landscape' ;
  $page_size = ($synthese_surnombre) ? 'A3' : 'A4' ;
  $pdf = new PDF_item_tableau_synthese( FALSE /*officiel*/ , $page_size , $orientation , $marge_min /*marge_gauche*/ , $marge_min /*marge_droite*/ , $marge_min /*marge_haut*/ , $marge_min /*marge_bas*/ , $couleur , $fond , $legende );
  $pdf->initialiser( $eleve_nb , $item_nb , $tableau_synthese_format );
  $pdf->entete( 'Bilan '.$bilan_titre_pdf_csv , $matiere_nom.' - '.$niveau_nom_global.$texte_precisions_pdf_csv , '' /*texte_periode*/ );
  // 1ère ligne
  $pdf->ligne_tete_cellule_debut();
  $th = ($tableau_synthese_format=='eleve') ? 'Élève' : 'Item' ;
  $html_table_head = '<thead><tr><th data-sorter="text">'.$th.'</th>';
  if($tableau_synthese_format=='eleve')
  {
    foreach($tab_liste_item as $item_id)  // Pour chaque item...
    {
      $pdf->ligne_tete_cellule_corps( $tab_item_synthese[$item_id]['item_ref'] );
      $html_table_head .= '<th data-sorter="FromData"'.infobulle($tab_item_synthese[$item_id]['item_nom']).'><dfn>'.html($tab_item_synthese[$item_id]['item_ref']).'</dfn></th>';
    }
  }
  else
  {
    foreach($tab_eleve_infos as $eleve_id => $eleve_nom_prenom)  // Pour chaque élève...
    {
      $pdf->ligne_tete_cellule_corps($eleve_nom_prenom);
      $html_table_head .= '<th data-sorter="FromData"><dfn>'.html($eleve_nom_prenom).'</dfn></th>';
    }
  }
  $pdf->ligne_tete_cellules_fin();
  $entete_vide   = ($repeter_entete)     ? '<th data-sorter="false" class="nu">&nbsp;</th>' : '' ;
  $checkbox_vide = ($affichage_checkbox) ? '<th data-sorter="false" class="nu">&nbsp;</th>' : '' ;
  $html_table_head .= '<th data-sorter="false" class="nu">&nbsp;</th><th data-sorter="FromData" data-empty="bottom">[ * ]</th><th data-sorter="FromData" data-empty="bottom">[ ** ]</th>'.$entete_vide.$checkbox_vide.'</tr></thead>'.NL;
  // lignes suivantes
  $html_table_body = '';
  if($tableau_synthese_format=='eleve')
  {
    foreach($tab_eleve_infos as $eleve_id => $eleve_nom_prenom)  // Pour chaque élève...
    {
      $pdf->ligne_corps_cellule_debut($eleve_nom_prenom);
      $entete = '<td>'.html($eleve_nom_prenom).'</td>';
      $html_table_body .= '<tr>'.$entete;
      foreach($tab_liste_item as $item_id)  // Pour chaque item...
      {
        $score = (isset($tab_score_eleve_item[$eleve_id][$item_id])) ? $tab_score_eleve_item[$eleve_id][$item_id] : FALSE ;
        $pdf->afficher_score_bilan( $score , 0 /*br*/ );
        $checkbox_val = ($affichage_checkbox) ? $eleve_id.'x'.$item_id : '' ;
        $html_table_body .= Html::td_score($score,$tableau_tri_etat_mode,'',$checkbox_val);
      }
      $valeur1 = (isset($tab_moyenne_scores_eleve[$eleve_id])) ? $tab_moyenne_scores_eleve[$eleve_id] : FALSE ;
      $valeur2 = (isset($tab_pourcentage_acquis_eleve[$eleve_id])) ? $tab_pourcentage_acquis_eleve[$eleve_id] : FALSE ;
      $pdf->ligne_corps_cellules_fin( $valeur1 , $valeur2 , FALSE , TRUE );
      $col_entete   = ($repeter_entete) ? $entete : '' ;
      $col_checkbox = ($affichage_checkbox) ? '<td class="nu"><input type="checkbox" name="id_user[]" value="'.$eleve_id.'"></td>' : '' ;
      $html_table_body .= '<td class="nu">&nbsp;</td>'.Html::td_score($valeur1,$tableau_tri_etat_mode,'%').Html::td_score($valeur2,$tableau_tri_etat_mode,'%').$col_entete.$col_checkbox.'</tr>'.NL;
    }
  }
  else
  {
    foreach($tab_liste_item as $item_id)  // Pour chaque item...
    {
      $pdf->ligne_corps_cellule_debut( $tab_item_synthese[$item_id]['item_ref'] );
      $entete = '<td'.infobulle($tab_item_synthese[$item_id]['item_nom']).'>'.html($tab_item_synthese[$item_id]['item_ref']).'</td>';
      $html_table_body .= '<tr>'.$entete;
      foreach($tab_eleve_infos as $eleve_id => $eleve_nom_prenom)  // Pour chaque élève...
      {
        $score = (isset($tab_score_eleve_item[$eleve_id][$item_id])) ? $tab_score_eleve_item[$eleve_id][$item_id] : FALSE ;
        $pdf->afficher_score_bilan( $score , 0 /*br*/ );
        $checkbox_val = ($affichage_checkbox) ? $eleve_id.'x'.$item_id : '' ;
        $html_table_body .= Html::td_score($score,$tableau_tri_etat_mode,'',$checkbox_val);
      }
      $valeur1 = $tab_moyenne_scores_item[$item_id];
      $valeur2 = $tab_pourcentage_acquis_item[$item_id];
      $pdf->ligne_corps_cellules_fin( $valeur1 , $valeur2 , FALSE , TRUE );
      $col_entete   = ($repeter_entete) ? $entete : '' ;
      $col_checkbox = ($affichage_checkbox) ? '<td class="nu"><input type="checkbox" name="id_item[]" value="'.$item_id.'"></td>' : '' ;
      $html_table_body .= '<td class="nu">&nbsp;</td>'.Html::td_score($valeur1,$tableau_tri_etat_mode,'%').Html::td_score($valeur2,$tableau_tri_etat_mode,'%').$col_entete.$col_checkbox.'</tr>'.NL;
    }
  }
  $html_table_body = '<tbody>'.NL.$html_table_body.'</tbody>'.NL;
  // dernière ligne (doublée)
  $pdf->lignes_pied_cellules_debut( 'pondérée' );
  $html_table_foot1 = '<tr><th>moyenne scores [*]</th>';
  $html_table_foot2 = '<tr><th>% items acquis [**]</th>';
  $row_entete   = ($repeter_entete)     ? '<tr class="tablesorter-header"><th class="nu">&nbsp;</th>' : '' ;
  $row_checkbox = ($affichage_checkbox) ? '<tr><th class="nu">&nbsp;</th>' : '' ;
  if($tableau_synthese_format=='eleve')
  {
    foreach($tab_liste_item as $item_id)  // Pour chaque item...
    {
      $valeur1 = $tab_moyenne_scores_item[$item_id];
      $valeur2 = $tab_pourcentage_acquis_item[$item_id];
      $pdf->ligne_corps_cellules_fin( $valeur1 , $valeur2 , TRUE , FALSE );
      $html_table_foot1 .= Html::td_score($valeur1,'score','%');
      $html_table_foot2 .= Html::td_score($valeur2,'score','%');
      $row_entete   .= ($repeter_entete) ? '<th class="hc"'.infobulle($tab_item_synthese[$item_id]['item_nom']).'><dfn>'.html($tab_item_synthese[$item_id]['item_ref']).'</dfn></th>' : '' ;
      $row_checkbox .= ($affichage_checkbox) ? '<td class="nu"><input type="checkbox" name="id_item[]" value="'.$item_id.'"></td>' : '' ;
    }
  }
  else
  {
    foreach($tab_eleve_infos as $eleve_id => $eleve_nom_prenom)  // Pour chaque élève...
    {
      $valeur1 = (isset($tab_moyenne_scores_eleve[$eleve_id]))     ? $tab_moyenne_scores_eleve[$eleve_id]     : FALSE ;
      $valeur2 = (isset($tab_pourcentage_acquis_eleve[$eleve_id])) ? $tab_pourcentage_acquis_eleve[$eleve_id] : FALSE ;
      $pdf->ligne_corps_cellules_fin( $valeur1 , $valeur2 , TRUE , FALSE );
      $html_table_foot1 .= Html::td_score($valeur1,'score','%');
      $html_table_foot2 .= Html::td_score($valeur2,'score','%');
      $row_entete   .= ($repeter_entete) ? '<th><dfn>'.html($eleve_nom_prenom).'</dfn></th>' : '' ;
      $row_checkbox .= ($affichage_checkbox) ? '<td class="nu"><input type="checkbox" name="id_user[]" value="'.$eleve_id.'"></td>' : '' ;
    }
  }
  // les deux dernières cases (moyenne des moyennes)
  $colspan  = ($tableau_synthese_format=='eleve') ? $item_nb+1 : $eleve_nb+1 ;
  $pdf->ligne_corps_cellules_fin( $moyenne_moyenne_scores , $moyenne_pourcentage_acquis , TRUE , TRUE );
  $html_table_foot1 .= '<th class="nu">&nbsp;</th>'.Html::td_score($moyenne_moyenne_scores,'score','%').'<th class="nu">&nbsp;</th>'.$entete_vide.$checkbox_vide.'</tr>'.NL;
  $html_table_foot2 .= '<th class="nu">&nbsp;</th><th class="nu">&nbsp;</th>'.Html::td_score($moyenne_pourcentage_acquis,'score','%').$entete_vide.$checkbox_vide.'</tr>'.NL;
  $row_entete   .= ($repeter_entete)     ? '<th class="nu">&nbsp;</th><th class="nu">&nbsp;</th><th class="nu">&nbsp;</th>'.$entete_vide.$checkbox_vide.'</tr>'.NL : '' ;
  $row_checkbox .= ($affichage_checkbox) ? '<th class="nu">&nbsp;</th><th class="nu">&nbsp;</th><th class="nu">&nbsp;</th>'.$entete_vide.$checkbox_vide.'</tr>'.NL : '' ;
  $html_table_foot = '<tfoot>'.NL.'<tr class="vide"><td class="nu" colspan="'.$colspan.'">&nbsp;</td><td class="nu"></td><td class="nu"><td class="nu">'.$entete_vide.$checkbox_vide.'</tr>'.NL.$html_table_foot1.$html_table_foot2.$row_entete.$row_checkbox.'</tfoot>'.NL;
  // sortie HTML
  $html .= '<hr>'.NL.'<h2>Tableau de synthèse (selon l’objet et le mode de tri choisis)</h2>'.NL;
  $html .= ($affichage_checkbox) ? '<form id="form_synthese" action="#" method="post">'.NL : '' ;
  $html .= '<table id="table_s" class="bilan_synthese vsort">'.NL.$html_table_head.$html_table_foot.$html_table_body.'</table>'.NL;
  // Légende
  if($legende=='oui')
  {
    $pdf->legende();
    $html .= Html::legende( array('score_bilan'=>TRUE) );
  }
  $script = $affichage_direct ? '$("#table_s").tablesorter();' : 'function tri(){$("#table_s").tablesorter();}' ;
  $html .= ($affichage_checkbox) ? HtmlForm::afficher_synthese_exploitation('eleves + eleves-items + items').'</form>'.NL : '';
  $html .= '<script>'.$script.'</script>'.NL;
  // On enregistre les sorties HTML et PDF
  FileSystem::ecrire_fichier(   CHEMIN_DOSSIER_EXPORT.$fichier_nom_type2.'.html' , $html );
  FileSystem::ecrire_objet_pdf( CHEMIN_DOSSIER_EXPORT.$fichier_nom_type2.'.pdf'  , $pdf );
}

// ////////////////////////////////////////////////////////////////////////////////////////////////////
// Affichage du résultat
// ////////////////////////////////////////////////////////////////////////////////////////////////////

$retour = '';

if($affichage_direct)
{
  $retour .=
    '<hr>'.NL
  . '<ul class="puce">'.NL
  .   '<li><a target="_blank" rel="noopener noreferrer" href="'.URL_DIR_EXPORT.$fichier_nom_type1.'.pdf"><span class="file file_pdf">Archiver / Imprimer (format <em>pdf</em>).</span></a></li>'.NL
  . '</ul>'.NL
  . $html;
}
else
{
  if($type_synthese)
  {
    $retour .=
      '<h2>Synthèse collective</h2>'.NL
    . '<ul class="puce">'.NL
    .   '<li><a target="_blank" rel="noopener noreferrer" href="./releve_html.php?fichier='.$fichier_nom_type2.'"><span class="file file_htm">Explorer / Manipuler (format <em>html</em>).</span></a></li>'.NL
    .   '<li><a target="_blank" rel="noopener noreferrer" href="'.URL_DIR_EXPORT.$fichier_nom_type2.'.pdf"><span class="file file_pdf">Archiver / Imprimer (format <em>pdf</em>).</span></a></li>'.NL
    . '</ul>'.NL;
  }
  if( $type_generique || $type_individuel )
  {
    $h2 = ($type_individuel) ? 'Relevé individuel' : 'Relevé générique' ;
    $retour .=
      '<h2>'.$h2.'</h2>'.NL
    . '<ul class="puce">'.NL
    .   '<li><a target="_blank" rel="noopener noreferrer" href="./releve_html.php?fichier='.$fichier_nom_type1.'"><span class="file file_htm">Explorer / Manipuler (format <em>html</em>).</span></a></li>'.NL
    .   '<li><a target="_blank" rel="noopener noreferrer" href="'.URL_DIR_EXPORT.$fichier_nom_type1.'.pdf"><span class="file file_pdf">Archiver / Imprimer (format <em>pdf</em>).</span></a></li>'.NL
    . '</ul>'.NL;
  }
}

Json::add_tab( array(
  'direct' => $affichage_direct ,
  'bilan'  => $retour ,
) );
Json::end( TRUE );

?>
