<?php
#=
define('PREFSELECT','sel');                 //préfixe des noms des champs <select>
define('REP_RELATIF_IMAGES','../images/');  //par rapport au répertoire de ce fichier
                                            //terminé par un antislash
class triFiltre {


//il touche un tri : inutile de recalculer les filtres
//il touche un filtre : inutile de recalculer les autres sauf si on peut cumuler les changements de filtres

var  $ident,          //identificateur pour signaler, via l'URL, que l'objet est en session
                      //sert aussi pour stocker/récupérer l'objet dans $_SESSION[$this->ident]
     $existait,       //booléen. Vrai si l'objet était déjà en session (à utiliser pour le 2e passage et suivants)
     $nbcols;         //nombre de colonnes du tableau affiché
     //$nomform;      //nom du tag form dans la page affichée (utile si plusieurs instances)

var  $Thinttri,       //si tri, partie du hint affiché par les flèches (tri croissant des xxx)
     $Tlibcol,        //libellé affiché en tête de colonne
     $Tcolwidth,      //largeur de chaque colonne (<colgroup>...<col width="30%">... ici, la valeur est 30
     $Tvaleurselect,  //$Tvaleurselect[$icol] = valeur de 0 à n correspondant à la "value" de l'<option> choisie dans la combo
     $Tfiltrage,      //$Tfiltrage[$icol] = true si la colonne possède un filtre (statique ou dynamique)
     $Tcondstafiltre, //Tcondstafiltre[$icol] = tableau des conditions (associé à Tvalcombo[$icol])

     $Tconddynfiltre, //chaîne ! Condition permettant de filtrer la colonne (par ex. "etab.cp")
                      //Le filtre sera alors "etab.cp='33000'")
     $Tvalcombo,      //Tvalcombo[icol] est le tableau contenant la liste des libellés apparaissant dans la combo
     $Tnbcarscombo,   //Tnbcarscombo[icol] est le nb de car de chaque élém que l'on garde pour remplir la combo de la colonne icol

     $Torderby,       //condition d'ordre à mettre dans ORDER BY si l'user demande d'ordonner la colonne. Ex. : etab.ville
     $Tordre,         //n° des colonnes ordonnées ; l'ordre principal porte sur la colonne Tordre[0],
                      //le suivant sur Tordre[1]... Les n° des col ordonnées sont empilées dans ce tableau
     $Tsens,          //sens associés aux ordres indiqués dans Tordre
     $Tcallback       //fonction callback pour le texte de chaque colonne
     =array();

var  $get_ordre,      //récupération de $_GET['ordre'] et $_GET['sens'] si passage 2 avec clic sur une flèche
     $get_sens;

var  $sqlbase,        //requête de base fournie par le programmeur
     $sql,            //requête améliorée avec des WHERE (filtres) et ORDER BY (tris)
     $whereFiltres;   //la partie derrière le WHERE permettant l'affichage et la suppression filtrés

     //attributs des balises duleau et du formulaire
var  $attrtable,
     $attrtrentete,$attrthentete,
     $attrtrcombo,$attrtdcombo,
     $attrtrpair,$attrtrimpair,
     $attrtbody,$attrtr,
     $attrth,$attrtd,
     $attrselect,$attroption;

var  $margefleche;    //marge de position de la flèche dans la colonne
                      // exemple : 10 (signifiant 10%) maximum 50
var  $repCEfichier;
var  $PHP_SELF;


function triFiltre($ident,$init=false) {
//on récupère les éventuelles données en session sauf si $ident est connu en session
@session_start();
$this->ident=$ident;
//on considère que l'objet a déjà été créé dans un passage précédent s'il est en session
$this->existait=isset($_SESSION[$ident]);

if ($init && $this->existait) {
    $this->existait=false;
    unset($_SESSION[$ident]);
    }
if ($this->existait) {
    $otemp=unserialize($_SESSION[$ident]); //on ne peut pas affecter directement $this
    foreach(get_object_vars($otemp) as $champ => $valeur) {
		$this->$champ = $valeur;
		} 
    if (isset($_GET['ordre'])) {
        $this->get_ordre=$_GET['ordre'];  //n° de colonne à ordonner
        $this->get_sens=$_GET['sens'];    //'asc' ou 'desc'
        }
    else {
        $this->get_ordre=-1;
        $this->get_sens='';
        }
    $this->existait=true; //car le unserialize l'a écrasé avec une valeur fausse au passage 2
    }
else {
    $this->nbcols=0;
    $this->get_ordre=-1; $this->get_sens=''; //pourra être modifié par le programmeur pour démarrer ordonné
    $this->Tlibcol=$this->Tcondstafiltre=$this->Tconddynfiltre=
        $this->Tordre=$this->Tsens=$this->Torderby=$this->Tvalcombo=
        $this->Tfiltrage=$this->Tcallback=array();
    $this->attrtable=$this->attrtr=$this->attrth=$this->attrtd=
        $this->attrselect=$this->attroption=$this->attrtrentete=
        $this->attrthentete=$this->attrtrcombo=$this->attrtdcombo=
        $this->attrtrpair=$this->attrtrimpair=$this->attrtbody='';
    $this->margefleche=30;
    //recherche du chemin relatif de CE fichier par rapport au script "de base"
    //ou "de plus haut niveau" (le fichier .php appelé par le navigateur client).
    $repinc=str_replace('\\','/',realpath(dirname(__FILE__)));
    $reppoint=str_replace('\\','/',realpath(dirname('.')));
    $trepinc=explode("/",$repinc);
    $treppoint=explode("/",$reppoint);
    $plusbas=array_diff($trepinc,$treppoint);
    $plushaut=array_diff($treppoint,$trepinc);
    $descente=implode("/",$plusbas).'/';
    $montee=str_repeat('../',count($plushaut));
    $this->repCEfichier=$montee.$descente;
    }
$this->PHP_SELF=basename($_SERVER['PHP_SELF']); //recalculé chaque fois (chgt page possible)
}

function creerCol($numcol,$libelle='',$width=0) {
if ($numcol<0) return false;
if ($numcol>=$this->nbcols) $this->nbcols=$numcol+1;
$this->Tlibcol[$numcol]=$libelle;
$this->clearFiltre($numcol);
$this->Tfiltrage[$numcol]=false;
$this->Tsens[$numcol]="";
$this->Torderby[$numcol]="";
$this->Tcolwidth[$numcol]=$width;
$this->Tcallback[$numcol]='';
return $numcol;
}
function setLibCol($numcol,$libelle)  {
if ($numcol<$this->nbcols) $this->Tlibcol[$numcol]=$libelle;
}
function setHintArrow($numcol,$msg) {
$this->$Thinttri[$numcol]=$msg;
}
function setOrdre($numcol,$sens='asc') {
if ($numcol>=0 && $numcol<$this->nbcols) {
    $this->ordre=$numcol;
    if (in_array($sens,array('desc',-1,'-'))) $this->get_sens='desc';
    else $this->get_sens='asc';
    }
}

function appendFiltreSta($numcol,$libelle,$condition)  {
//le programmeur doit fournir toutes les valeurs dans l'ordre, même ('tout' , 1)
//(sauf s'il ne le veut pas !). Ces valeurs seront affichées telles quelles.
$this->Tvalcombo[$numcol][]=$libelle;
$this->Tcondstafiltre[$numcol][]=$condition;
}

function clearFiltre($numcol) {
$this->Tvalcombo[$numcol]=array();
$this->Tcondstafiltre[$numcol]=array();
$this->Tconddynfiltre[$numcol]='';
$this->Tvaleurselect[$numcol]=0;  //valeur sélectionnée dans la combo
$this->Tfiltrage[$numcol]=true;
$this->Tnbcarscombo[$numcol]=0;   //on conserve "tous" les caractères
}

function setFiltreSta($numcol,$nbcars=0) {
$this->clearFiltre($numcol);
if ($nbcars && is_numeric($nbcars) && $nbcars>0) $this->Tnbcarscombo[$numcol]=$nbcars;
else $this->Tnbcarscombo[$numcol]=0;
}

function setFiltreDyn($numcol,$condition,$nbcars=0)  {
$this->clearFiltre($numcol);
$this->Tconddynfiltre[$numcol]=$condition;
if ($nbcars && is_numeric($nbcars) && $nbcars>0) $this->Tnbcarscombo[$numcol]=$nbcars;
else $this->Tnbcarscombo[$numcol]=0;
}

function setTri($numcol,$orderby="",$sens="") {
$this->Torderby[$numcol]=$orderby;
$this->Tsens[$numcol]=$sens;
}

function setRequete($sql) {
//SELECT quelconque mais sans GROUP BY ni ORDER BY ni LIMIT
$this->sqlbase=$sql;
}

function setCallback($numcol,$fonction) {
$this->Tcallback[$numcol]=$fonction;
}

function genererRequete() {
/*Le POST permet de récupérer l'état de tous les filtres alors que le GET ne permet de récupérer
que le dernier tri demandé, d'où la nécessité d'une pile pour les tris demandés successivement
*/
$where='';
for($icol=0; $icol<$this->nbcols; $icol++) {
    //faire intervenir les filtres (partie WHERE).
    //-------------------------------------------
    if ($this->Tfiltrage[$icol]) {
        $cselect=$this->ident.PREFSELECT.$icol;                     //nom du tag <select> de la colonne $icol
        if (isset($_POST[$cselect]))  {                             //l'user a changé une combo
            $this->Tvaleurselect[$icol]=$_POST[$cselect];            //nlle valeur de la combo                               include('../tests/checkbox2.php');
            }
        $valsel=$this->Tvaleurselect[$icol];                         //pour alléger le code...


        if ($valsel) {                                              //si c'est 0, il n'y a pas de condition de filtre pour cette colonne
            //dbgv($this->Tvalcombo,'TValcombo');
            //dbgv($this->Tvaleurselect,'Tvaleurselect');

            if (count($this->Tcondstafiltre[$icol]))                //table des couples (libellé,condition)
                $condition=$this->Tcondstafiltre[$icol][$valsel];   //(tous => 1) par exemple
            elseif ($this->Tconddynfiltre[$icol]) {
                $mgauche=$this->Tconddynfiltre[$icol];              //etablissements.cp par exemple)
                $mdroit="'".mysql_escape_string($this->Tvalcombo[$icol][$valsel])."'";   //'33000'
                if ($this->Tnbcarscombo[$icol]) {
                    $mgauche="LEFT($mgauche,".$this->Tnbcarscombo[$icol].")";
                    $mdroit="LEFT($mdroit,".$this->Tnbcarscombo[$icol].")";
                    }
                $condition=" $mgauche = $mdroit ";
                }
            else $condition=1;
            if ($condition!=1) $where.=" AND $condition ";
            }
        }

    //faire intervenir les tris (partie ORDER)
    //----------------------------------------
    //on n'en trouvera qu'un seul dans ce for car il n'y a qu'un seul paramètre 'Tordre' passé par GET (un seul clic !)
    if ($this->get_ordre==$icol) {
        //vérifier que ce tri n'est pas déjà empilé antérieurement
        $ix=array_search($icol,$this->Tordre);                  //contient par ex. 2,1,6 (ordonné
                                                                //par la colonne 2 puis 1 puis 6
        if ($ix!==false) {
            array_splice($this->Tordre,$ix,1);
            array_splice($this->Tsens,$ix,1);
            }
        //empiler le dernier critère de tri dans le tableau $_SESSION['ordre']
        array_unshift($this->Tordre,$this->get_ordre);            //empile par le haut
        array_unshift($this->Tsens,$this->get_sens);
        }
    }

//calculer la partie ORDER BY en prenant la pile dans l'ordre mais sans dépiler
$orderby='';
for ($i=0; $i<count($this->Tordre); $i++)
    $orderby.=", ".$this->Torderby[$this->Tordre[$i]]." ".$this->Tsens[$i];
if ($orderby) $orderby=substr($orderby,2);                      //enlever la virgule

//créer la requête
if ($where) {   //il n'y a rien à rajouter à la requête de base
        $this->whereFiltres=substr($where,4);
    if (strpos($this->sqlbase,' WHERE ')===false) {
        //pas de WHERE dans la requête : on le rajoute et on supprime le premier AND
        $this->sql=$this->sqlbase.' WHERE '.$this->whereFiltres;
        }
    else {
        //il y a déjà un WHERE : on ajoute alors $where qui commence bien par " AND ..."
        $this->sql=$this->sqlbase.$where;
        }
    }
else {
    $this->sql=$this->sqlbase;
    $this->whereFiltres=" 1 ";
    }
if ($orderby) $this->sql.=' ORDER BY '.$orderby;
}

function afficherTri($icol) {
//affiche une <table> avec les flèches de tri
//le tri est choisi uniquement par GET
$chemin=$this->repCEfichier.'images/';
if ($this->Thinttri[$icol])
    $hint=$this->Thinttri[$icol];
else $hint="éléments de la colonne";
//inversion vidéo pour l'image sélectionnée

print "<table>\n";
/* print "<colgroup >\n";
print '   <col width="'.$this->margefleche."%\">\n";
print '   <col width="'.(100-2*$this->margefleche)."%\">\n";
print '   <col width="'.$this->margefleche."%\">\n";
print "</colgroup>\n"; */
print "<tr>\n";

//flèche ascendante
if ($this->get_ordre==$icol && $this->get_sens=="asc") $img='hautiv.png';
else $img='haut.png';

print "<td style=\"width: 17px\"><a href=\"$this->PHP_SELF?ordre=$icol&sens=asc\">\n";
print "<img src=\"$chemin$img\" width=\"17\" height=\"17\" alt=\"tri croissant des $hint\" />";
print "</a></td>\n";

// séparateur de flèches
print "<td>&nbsp</td>\n";

//flèche descendante
if ($this->get_ordre==$icol && $this->get_sens=="desc") $img='basiv.png';
else $img='bas.png';

print "<td style=\"width: 17px\"><a href=\"$this->PHP_SELF?ordre=$icol&sens=desc\">\n";
print "<img src=\"$chemin$img\" width=\"17\" height=\"17\" alt=\"tri décroissant des $hint\" />\n";
print "</a></td></tr></table>\n";
}

function afficherCombo($icol) {
//fabriquer le contenu des combos dynamiques et statiques
if (!$this->existait && $this->Tconddynfiltre[$icol]) {
    sort($this->Tvalcombo[$icol]);
    array_unshift($this->Tvalcombo[$icol],' tout '); //en position 0
    //la combo contient donc les valeurs tout,24,33,40,47,64 par exemple
    }
if (isset($this->Tvalcombo[$icol]) && count($this->Tvalcombo[$icol])) {
    print "<select name=\"".$this->ident.PREFSELECT.$icol."\" size=\"1\" onchange=\"submit();\" $this->attrselect />\n";
    for ($ic=0; $ic<count($this->Tvalcombo[$icol]); $ic++) {
        if ($ic==$this->Tvaleurselect[$icol]) $selected='selected="selected"';
        else $selected='';
        print "\t<option value=\"$ic\" $selected $this->attroption>".$this->Tvalcombo[$icol][$ic]."</option>\n";
        }
    print "</select>\n";
    }
}

function afficherentete() {
print "<thead>\n";

//1ère ligne : les libellés des colonnes
print "<tr $this->attrtrentete>\n";
for ($icol=0 ; $icol<$this->nbcols ; $icol++) {
    print "<th $this->attrthentete>\n";
    print $this->Tlibcol[$icol];
    print "</th>\n";
    }
print "</tr>\n";

//2e ligne : les filtres éventuels
print "<tr $this->attrtrentete>\n";
for($icol=0; $icol<$this->nbcols; $icol++) {
    print "<th $this->attrthentete>\n";
    if ($this->Tfiltrage[$icol]) $this->afficherCombo($icol);    // boîte combo
    else print "&nbsp;";
    print "</th>\n";
    }
print "</tr>\n";

//3e ligne : les tris éventuels
print "<tr $this->attrtrentete>\n";
for($icol=0; $icol<$this->nbcols; $icol++) {
    print "<th $this->attrthentete>\n";
    if ($this->Torderby[$icol]) $this->afficherTri($icol);       // flèches de tri
    else print "&nbsp;";
    print "</th>\n";
    }
print "</tr>\n";
print "</thead>\n";
}


function afficherCorpsTableau() {
print "<tbody $this->attrtbody>";
if ($this->attrtrpair) {
    //le programmeur-utilisateur a choisi ses propres attributs
    $attr[0]=$this->attrtrpair;
    $attr[1]=$this->attrtrimpair;
    }
else {
    //prendre les noms de la feuille de style par défaut
    $attr[0]=" class=\"pair\" ";
    $attr[1]=" class=\"impair\" ";
    }
for ($icol=0; $icol<$this->nbcols; $icol++) {
    //cette col est à remplir lorsque elle a un filtre dynamique et...
    //qu'elle n'était pas déjà remplie : l'objet (donc sa combo)
    //n'était pas déjà en session OU le programmeur vient d'ajouter cette combo
    $aremplir[$icol]=$this->Tconddynfiltre[$icol] && !$this->existait;
    }
$ligne=0;
// pour la bulle jmt
$code_erreurs=array(
    'ETB' => "Etablissement inconnu",
    'LOG' => "Login inconnu dans l'établissement",
    'GDS' => "Session perdue (temps épuisé)",
    'MDP' => "Mauvais mdp",
    'PAG' => "Accès anormal à cette page (pas de session) ou n°étab incorrect",
    'PER' => "Session détruite par PHP (durée limite dépassée) ou cookie périmé",
    'XSS' => "Problème d'en-tête du navigateur ou tentative de XSS",
    'TMO' => "Durée accordée par GiSCCo dépassée ",
    'STA' => "Statut incorrect",
    'EXP' => "Session expirée ou invalide");
//
$res=mysql_query($this->sql);
while ($row=mysql_fetch_row($res)) {
    print "<tr ".$attr[$ligne % 2].">\n";
    $ligne++;
    for($icol=0; $icol<$this->nbcols; $icol++) {
        $affiche=stripslashes($row[$icol]);
        if ($aremplir[$icol]) {
            if ($this->Tnbcarscombo[$icol]>0)
                $nouvelle=substr($affiche,0,$this->Tnbcarscombo[$icol]);
            else $nouvelle=$affiche;
            if (!in_array($nouvelle,$this->Tvalcombo[$icol]))
                //la veleur n'est pas déjà dans la combo : on l'ajoute
                $this->Tvalcombo[$icol][]=$nouvelle;
            }
        if ($this->Tcallback[$icol])
                $affiche=$this->Tcallback[$icol]($affiche);
        if (!$affiche) $affiche="&nbsp;";           //judicieux ?
		  // si colonne de code erreur, bulle d'explication jmt
          if ($icol!=4) print "<td $this->attrtd> $affiche</td>\n";
          else print"<td class='centre'><a class='bulle taillebullegde decalbullec' href=#>"
          	        .$affiche
          	        ."<span>$code_erreurs[$affiche]</span></a></td>";
        }
    print "</tr>\n";
    }
mysql_free_result($res);
print "</tbody>\n";
}

function afficherTableau() {
//tout est prêt : requête, filtres et tris
//initialiser les combos dynamiques au premier passage
if (!$this->existait)
    for ($icol=0; $icol<$this->nbcols; $icol++)
        if ($this->Tconddynfiltre[$icol]) $this->Tvalcombo[$icol]=array();
$this->genererRequete();

ob_start();
$this->afficherCorpsTableau(); //on bufferise
$corps=ob_get_contents();
ob_end_clean();

print "<div class=\"tf\">\n";
print "<form name=\"$this->ident\" method=\"POST\" action=\"$this->PHP_SELF\">\n";
print "<table $this->attrtable rules=\"groups\">\n";
print "<colgroup>\n";
for ($icol=0 ; $icol<$this->nbcols ; $icol++)
    if ($this->Tcolwidth[$icol]) print '<col width="'.$this->Tcolwidth[$icol].'%">';
    else print "<col>";
print "</colgroup>\n";
$this->afficherentete();
print $corps;
print "</table>\n";
print "</form>\n";
print "</div>\n";

unset($this->get_ordre,$this->get_sens); //il doit y avoir d'autres variables unset-ables ; à vérifier
$_SESSION[$this->ident]=serialize($this);
}

} //class
?>