<?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) {}

$indicateur          = Clean::post('f_indicateur'       , 'texte');
$conversion_sur_20   = Clean::post('f_conversion_sur_20', 'bool');
$groupe_id           = Clean::post('f_groupe'           , 'entier');
$groupe_type         = Clean::post('f_groupe_type'      , 'lettres'); // En vérité, ne sert pas ici.
$eleve_id            = Clean::post('f_eleve'            , 'entier');
$nom_prenom          = Clean::post('f_nom_prenom'       , 'texte');
$eleves_ordre        = Clean::post('f_eleves_ordre'     , 'eleves_ordre', 'nom'); // En vérité, ne sert pas ici. Non transmis par Safari si dans le <span> avec la classe "hide".
$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');
$aff_prop_sans_score = Clean::post('f_prop_sans_score'  , 'bool');
$only_socle          = Clean::post('f_only_socle'       , 'bool');
$only_diagnostic     = Clean::post('f_only_diagnostic'  , 'texte');
$only_prof           = Clean::post('f_only_prof'        , 'bool');
$prof_id             = Clean::post('f_prof'             , 'entier');
$prof_texte          = Clean::post('f_prof_texte'       , 'texte');
$with_coef           = 1;

// 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')))
{
  if( !Outil::test_user_droit_specifique($_SESSION['DROIT_RELEVE_MOYENNE_SCORE']) && !Outil::test_user_droit_specifique($_SESSION['DROIT_RELEVE_POURCENTAGE_ACQUIS']) ) { $indicateur = 'aucun'; }
  else if(!Outil::test_user_droit_specifique($_SESSION['DROIT_RELEVE_MOYENNE_SCORE']))      { $indicateur = 'pourcentage_acquis'; }
  else if(!Outil::test_user_droit_specifique($_SESSION['DROIT_RELEVE_POURCENTAGE_ACQUIS'])) { $indicateur = 'moyenne_scores'; }
  $conversion_sur_20 = Outil::test_user_droit_specifique($_SESSION['DROIT_RELEVE_CONVERSION_SUR_20']) ? $conversion_sur_20 : 0 ;
}

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

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

// Pour un professeur on vérifie que c’est bien un de ses élèves
if( ($_SESSION['USER_PROFIL_TYPE']=='professeur') && ($_SESSION['USER_JOIN_GROUPES']=='config') )
{
  Outil::verif_eleve_prof( $eleve_id );
}

$tab_indicateur = array(
  'moyenne_scores'     => 'Moyenne des scores',
  'pourcentage_acquis' => 'Pourcentage d’items acquis',
  'aucun'              => 'Sans indicateur',
);

if(
    !isset($tab_indicateur[$indicateur]) ||
    !$groupe_id || !$groupe_type ||
    !$eleve_id || !$nom_prenom || !$eleves_ordre ||
    ( !$periode_id && (!$date_debut || !$date_fin) ) ||
    !$retroactif || !$only_diagnostic || ( $only_prof && !$prof_id )
  )
{
  Json::end( FALSE , 'Erreur avec les données transmises !<br>'.pathinfo(__FILE__,PATHINFO_FILENAME).':'.__LINE__ );
}

Form::save_choix('releve_graphique');

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

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

// Initialisation de tableaux

$tab_item          = array();  // [item_id] => array(item_ref,item_nom,item_coef,item_cart,item_s2016,item_lien,matiere_id,calcul_methode,calcul_limite,calcul_retroactif,synthese_ref);
$tab_liste_item    = array();  // [i] => item_id
$tab_matiere       = array();  // [matiere_id] => array(matiere_nom,matiere_nb_demandes)
$tab_eval          = array();  // [item_id][devoir] => array(note,date) On utilise un tableau multidimensionnel vu qu’on ne sait pas à l’avance combien il y a d’évaluations pour un élève et un item donnés.
$tab_remove_strong = array('<strong>','</strong>');

$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],
);

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

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

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 !' );
}

// ////////////////////////////////////////////////////////////////////////////////////////////////////
// Récupération de la liste des items travaillés durant la période choisie, pour les élèves selectionnés, toutes matières confondues
// Récupération de la liste des matières concernées
// ////////////////////////////////////////////////////////////////////////////////////////////////////

$only_prof_id = ($only_prof) ? $prof_id : FALSE ;
$without_matiere_experimentale = in_array($_SESSION['USER_PROFIL_TYPE'],array('eleve','parent')) ? TRUE : FALSE ;
// mode_synthese pas sur "predefini" afin de pouvoir récupérer les items de référentiels sans mode de synthèse
list($tab_item,/*tab_synthese*/,$tab_matiere) = DB_STRUCTURE_BILAN::DB_recuperer_arborescence_synthese( $eleve_id , 0 /*matiere_id*/ , $only_socle , $only_diagnostic , $only_prof_id , 0 /*only_niveau*/ , $without_matiere_experimentale , 'domaine' /*mode_synthese*/ , 1 /*fusion_niveaux*/ , $date_sql_debut , $date_sql_fin , 0 /*aff_socle*/ , FALSE /*$order_synthese*/ );

$item_nb = count($tab_item);
if( !$item_nb && (in_array($_SESSION['USER_PROFIL_TYPE'],array('parent','eleve'))) ) // Dans le cas d’un professeur / directeur, où l’on regarde les élèves d’un groupe un à un, ce ne doit pas être bloquant.
{
  Json::end( FALSE , 'Aucun item évalué sur la période '.$date_debut.' ~ '.$date_fin.$precision_socle.$precision_diagnostic.$precision_prof.'.' );
}
$tab_liste_item = array_keys($tab_item);
$liste_item = implode(',',$tab_liste_item);

// ////////////////////////////////////////////////////////////////////////////////////////////////////
// Récupération de la liste des résultats des évaluations associées à ces items donnés, pour les élèves selectionnés, sur la période sélectionnée
// ////////////////////////////////////////////////////////////////////////////////////////////////////

if($item_nb) // Peut valoir 0 (on regarde les élèves un par un, il ne faut pas qu’un élève sans rien soit bloquant).
{
  $annee_decalage = empty($_SESSION['NB_DEVOIRS_ANTERIEURS']) ? 0 : -1 ;
  $date_sql_debut_annee_scolaire = To::jour_debut_annee_scolaire('sql',$annee_decalage);
  $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($eleve_id , $liste_item , 0 /*matiere_id*/ , $only_diagnostic , $date_sql_start , $date_sql_fin , $_SESSION['USER_PROFIL_TYPE'] , $only_prof_id , FALSE /*only_valeur*/ , FALSE /*onlynote*/ );
  foreach($DB_TAB as $DB_ROW)
  {
    if( Outil::is_note_a_garder( $retroactif , $tab_item[$DB_ROW['item_id']][0]['calcul_retroactif'] , $DB_ROW['date'] , $date_sql_debut , $date_sql_debut_annee_scolaire ) )
    {
      $tab_eval[$DB_ROW['item_id']][] = array(
        'note' => $DB_ROW['note'],
        'date' => $DB_ROW['date'],
      );
    }
  }
}

// ////////////////////////////////////////////////////////////////////////////////////////////////////
/* 
 * 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)
// ////////////////////////////////////////////////////////////////////////////////////////////////////

$tab_score_eleve_item      = array(); // Retenir les scores / élève / matière / synthese / item
$tab_infos_acquis_eleve    = array(); // Retenir les infos (nb acquis) / élève / matière / synthèse + total

/*
  On renseigne :
  $tab_score_eleve_item[$matiere_id][$item_id]
  $tab_infos_acquis_eleve[$matiere_id]
*/

// Si l’élève a été évalué...
if(!empty($tab_eval))
{
  // Pour chaque item on calcule son score bilan, et on mémorise les infos pour le détail HTML
  foreach($tab_eval as $item_id => $tab_devoirs)
  {
    // le score bilan
    extract($tab_item[$item_id][0]);  // $item_ref $item_nom $item_coef $item_cart $item_s2016 $item_lien $matiere_id $calcul_methode $calcul_limite $calcul_retroactif $synthese_ref
    $score = OutilBilan::calculer_score( $tab_devoirs , $calcul_methode , $calcul_limite , $date_sql_debut ) ;
    $tab_score_eleve_item[$matiere_id][$item_id] = $score;
  }
  // Pour chaque matière on recense le nombre d’items considérés acquis ou pas
  foreach($tab_score_eleve_item as $matiere_id => $tab_matiere_scores)
  {
    $tableau_score_filtre = ($aff_prop_sans_score) ? $tab_matiere_scores : array_filter($tab_matiere_scores,'non_vide');
    $nb_scores = count( $tableau_score_filtre );
    if(!isset($tab_infos_acquis_eleve[$matiere_id]))
    {
      // Le mettre avant le test sur $nb_scores permet d’avoir au moins le titre des matières où il y a des saisies mais seulement AB NN etc. (et donc d’avoir la rubrique sur le bulletin).
      $tab_infos_acquis_eleve[$matiere_id]['total'] = array_fill_keys( array_keys($_SESSION['ACQUIS']) , 0 );
      if($aff_prop_sans_score)
      {
        $tab_infos_acquis_eleve[$matiere_id]['total'][0] = 0;
      }
    }
    if($nb_scores)
    {
      $tab_acquisitions = OutilBilan::compter_nombre_acquisitions_par_etat( $tableau_score_filtre , $aff_prop_sans_score );
      foreach( $tab_acquisitions as $acquis_id => $acquis_nb )
      {
        $tab_infos_acquis_eleve[$matiere_id]['total'][$acquis_id] += $acquis_nb;
      }
    }
  }
}

// ////////////////////////////////////////////////////////////////////////////////////////////////////
// C’est parti !
// ////////////////////////////////////////////////////////////////////////////////////////////////////

$max_value = ($conversion_sur_20) ? 20 : 100 ;
$tab_graph_data = array();

$texte_periode = 'Du '.$date_debut.' au '.$date_fin;

$precision_socle      = $only_socle ? ', '.$tab_remove_strong[0].'restreint au socle'.$tab_remove_strong[1] : '' ;
$precision_diagnostic = ($only_diagnostic=='oui') ? ', '.$tab_remove_strong[0].'restreint aux évaluations diagnostiques'.$tab_remove_strong[1] : '' ;
$precision_prof       = $only_prof ? ', '.$tab_remove_strong[0].'restreint à '.$prof_texte.$tab_remove_strong[1] : '' ;
$texte_precision      = $tab_precision_retroactif[$retroactif].$precision_socle.$precision_diagnostic.$precision_prof;

$texte_indicateur_js   = ($indicateur != 'aucun') ? ( ($conversion_sur_20) ? $tab_indicateur[$indicateur].' (sur 20)' : $tab_indicateur[$indicateur].' (sur 100)' ) : $tab_indicateur[$indicateur] ;
$texte_indicateur_html = $tab_remove_strong[0].$texte_indicateur_js.$tab_remove_strong[1];

Json::add_row( 'titre' , $texte_indicateur_html.' - '.$texte_periode.' - '.$texte_precision );

if(!empty($tab_infos_acquis_eleve))
{
  // On passe en revue les matières...
  foreach($tab_infos_acquis_eleve as $matiere_id => $tab_infos_matiere)
  {
    $matiere_nom = $tab_matiere[$matiere_id]['matiere_nom'];
    $tab_graph_data['categories'][$matiere_id] = '"'.addcslashes($matiere_nom,'"').'"';
    foreach( $_SESSION['ACQUIS'] as $acquis_id => $tab_acquis_info )
    {
      $tab_graph_data['series_data_'.$acquis_id][$matiere_id] = $tab_infos_matiere['total'][$acquis_id];
    }
    if($aff_prop_sans_score)
    {
      $tab_graph_data['series_data_0'][$matiere_id] = $tab_infos_matiere['total'][0];
    }
    if($indicateur != 'aucun')
    {
      // calcul des bilans des scores
      $tableau_score_filtre = array_filter($tab_score_eleve_item[$matiere_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[$item_id][0]['item_coef'];
          $somme_coefs += $tab_item[$item_id][0]['item_coef'];
        }
        $somme_scores_simples = array_sum($tableau_score_filtre);
      }
      // Soit la moyenne des pourcentages d’acquisition
      if($indicateur=='moyenne_scores')
      {


        if($with_coef) { $moyenne = ($somme_coefs) ? round($somme_scores_ponderes/$somme_coefs,0) : FALSE ; }
        else           { $moyenne = ($nb_scores)   ? round($somme_scores_simples/$nb_scores,0)    : FALSE ; }
      }
      // Soit le nombre d’items considérés acquis ou pas
      elseif($indicateur=='pourcentage_acquis')
      {
        if($nb_scores)
        {

          $tab_acquisitions = OutilBilan::compter_nombre_acquisitions_par_etat( $tableau_score_filtre , 0 /*aff_prop_sans_score*/ );
          $moyenne = OutilBilan::calculer_pourcentage_acquisition_items( $tab_acquisitions , $nb_scores );
        }
        else
        {
          $moyenne = FALSE;
        }
      }
      $tab_graph_data['series_data_MoyEleve'][$matiere_id] = ($moyenne!==FALSE) ? ( ($conversion_sur_20) ? $moyenne/5 : $moyenne ) : 'null' ;
    }
    $tab_infos_matiere['total'] = array_filter($tab_infos_matiere['total'],'non_zero'); // Retirer les valeurs nulles
    $total = array_sum($tab_infos_matiere['total']) ; // La somme ne peut être nulle, sinon la matière ne se serait pas affichée
  }
}

// ////////////////////////////////////////////////////////////////////////////////////////////////////
// On fabrique les options js pour le diagramme graphique
// ////////////////////////////////////////////////////////////////////////////////////////////////////

// Nom du fichier d’export
$fichier_nom = 'graphique_'.Clean::fichier($nom_prenom.'_'.$date_sql_debut.'_'.$date_sql_fin.'_'.$indicateur);
Json::add_row( 'script' , 'ChartOptions.exporting.filename = "'.html($fichier_nom).'";' );

// Matières sur l’axe des abscisses
Json::add_row( 'script' , 'ChartOptions.title.text = null;' );
if(!empty($tab_graph_data))
{
  Json::add_row( 'script' , 'ChartOptions.xAxis.categories = ['.implode(',',$tab_graph_data['categories']).'];' );
}

// Second axe des ordonnés pour les moyennes
if($indicateur == 'aucun')
{
  Json::add_row( 'script' , 'delete ChartOptions.yAxis[1];' );
}
else
{
  Json::add_row( 'script' , 'ChartOptions.yAxis[1] = { min: 0, max: '.$max_value.', tickInterval: '.($max_value/4).', gridLineColor: "#C0D0E0", title: { style: { color: "#333" } , text: "'.html($texte_indicateur_js).'" }, opposite: true };' );
}

// Séries de valeurs
$tab_graph_series = array();
if(!empty($tab_graph_data))
{
  foreach( $_SESSION['ACQUIS'] as $acquis_id => $tab_acquis_info )
  {
      $tab_graph_series['A'.$acquis_id] = '{ name: "'.addcslashes($tab_acquis_info['LEGENDE'],'"').'", data: ['.implode(',',$tab_graph_data['series_data_'.$acquis_id]).'] }';
  }
  if($aff_prop_sans_score)
  {
    $tab_graph_series['A0'] = '{ name: "'.addcslashes($_SESSION['ETAT_ACQUISITION_NEUTRE_LEGENDE'],'"').'", data: ['.implode(',',$tab_graph_data['series_data_0']).'] }';
  }
}
if(isset($tab_graph_data['series_data_MoyEleve']))
{
  $tab_graph_series['MoyEleve']  = '{ type: "line", name: "'.html($tab_indicateur[$indicateur]).'", data: ['.implode(',',$tab_graph_data['series_data_MoyEleve']).'], marker: {symbol: "circle"}, color: "#139", yAxis: 1 }';
}
Json::add_row( 'script' , 'ChartOptions.series = ['.implode(',',$tab_graph_series).'];' );

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

Json::end( TRUE );

?>
