#!/usr/bin/perl -w
use utf8;
binmode STDOUT, ":encoding(UTF-8)";

require "./tables.pl"; our ($annee_scolaire);

# use CGI::Pretty; ## a n'utiliser que pour la mise au point.

%heures = (
	   "08:00" => 0 ,
	   "08:30" => 1 ,
	   "09:00" => 2 ,
	   "09:30" => 3 ,
	   "10:00" => 4 ,
	   "10:30" => 5 ,
	   "11:00" => 6 ,
	   "11:30" => 7 ,
	   "12:00" => 8 ,
	   "12:30" => 9 ,
	   "13:00" => 10,
	   "13:30" => 11,
	   "14:00" => 12,
	   "14:30" => 13,
	   "15:00" => 14,
	   "15:30" => 15,
	   "16:00" => 16,
	   "16:30" => 17,
	   "17:00" => 18,
	   "17:30" => 19,
	   "18:00" => 20,
	   "18:30" => 21,
	   "19:00" => 22,
	   "19:30" => 23,
	   "20:00" => 24,
	   "20:30" => 25,
	   "21:00" => 26,
	   "21:30" => 27,
	   "22:00" => 28,
	  );

@heures = sort keys %heures;

$base->do("set datestyle to 'sql,european'"); ### ATTENTION :: SQL et NON POSTGRES

## On fabrique quelques tables de hachages pour faciliter les requetes ultérieures
$requete="SELECT id, nom FROM salles";
$d_inst = $base->prepare($requete) or die "$DBI::errstr sur requête :\n$requete";
$d_inst->execute() or die "$DBI::errstr sur requête :\n$requete";

my %salles; ## Car salles déjà défini dans tables.pl
while (@data = $d_inst->fetchrow_array) {
  $salles{$data[0]} = $data[1];
}
$d_inst->finish();

$requete="SELECT id, nom || ' ' || prenom FROM equipes_pedagogiques";
$d_inst = $base->prepare($requete) or die "$DBI::errstr sur requête :\n$requete";
$d_inst->execute() or die "$DBI::errstr sur requête :\n$requete";

while (@data = $d_inst->fetchrow_array) {
  $prof{$data[0]} = $data[1];
}
$d_inst->finish();

$requete="SELECT code, couleur FROM ue";
$d_inst = $base->prepare($requete) or die "$DBI::errstr sur requête :\n$requete";
$d_inst->execute() or die "$DBI::errstr sur requête :\n$requete";

while (@data = $d_inst->fetchrow_array) {
  $ue{$data[0]} = $data[1];
}
$d_inst->finish();

($annee) = $annee_scolaire =~ /(20\d\d)-/;
$mois  = param('mois');

## Determinantion des dates du mois à afficher; On affiche du dernier lundi du mois
## précédent au premier samedi du mois suivant.


## Pour afficher tous les derniers lundi du mois et tous les premiers
## samedi du mois

%offset = (
	   '01' => [1,4],
	   '02' => [1,5],
	   '03' => [1,6],
	   '04' => [1,7],
	   '05' => [1,8],
	   '06' => [1,9],
	   '07' => [1,10],
	   '08' => [1,0],
	   '09' => [0,0],
	   '10' => [0,1],
	   '11' => [0,2],
	   '12' => [0,3],
	  );

tie %liste_mois, "Tie::IxHash";
%liste_mois = (
	       '09' => 'septembre',
	       '10' => 'octobre',
	       '11' => 'novembre',
	       '12' => 'décembre',
	       '01' => 'janvier',
	       '02' => 'février',
	       '03' => 'mars',
	       '04' => 'avril',
	       '05' => 'mai',
	       '06' => 'juin',
	       '07' => 'juillet',
	      );

# Suite à des problèmes avec le module Date::Manip et les accents des
# noms de mois en français création d'un hachage pour l'affichage
# correct des accents.
%mois_texte = %liste_mois;
$mois_texte{'08'} = 'août';

@liste_mois = map {a({-href=>"printCal.cgi?mois=$_"},$liste_mois{$_})} keys %liste_mois;

## L'annee est maintenant passée en argument et c'est celle du début de l'année scolaire
## ex : 2005 pour l'année scolaire 2005-2006
## $annee        = &UnixDate("aujourd'hui",'%Y') unless ($annee);

unless ($mois) {
  $mois = $mois_courant   = &UnixDate("aujourd'hui",'%m');
  $annee_courante = &UnixDate("aujourd'hui",'%Y');
  if ($annee == $annee_courante) {
    if ($offset{$mois_courant}->[0]) {
      $mois = '09'; ## Mois de septembre par défaut
    }
  }
}

$annee_deb = $annee;
$annee_fin = $annee + 1;

$last_saturday1   = "$annee_deb-8-1";
$last_saturday2   = "$annee_fin-7-1";

$first_saturday1 = "$annee_deb-10-1";
$first_saturday2 = "$annee_fin-9-1";

## 0:1*-1:2:0:0:0       last saturday of every month
@last_saturdays  = &ParseRecur("0:1*-1:6:0:0:0",$last_saturday1,$last_saturday1,$last_saturday2);

## 0:1*-1:2:0:0:0       first saturday of every month
@first_saturdays = &ParseRecur("0:1*1:6:0:0:0",$first_saturday1,$first_saturday1,$first_saturday2);

$debut_cal = $last_saturdays[$offset{$mois}->[1]];
$fin_cal   = $first_saturdays[$offset{$mois}->[1]];

$debut_cal = &UnixDate($debut_cal,'%d/%m/%Y');
$fin_cal   = &UnixDate($fin_cal,'%d/%m/%Y');

$requete = "SELECT ue.code, c.id, c.prof, p.salle, debut, fin FROM planning p, cours c, cours2ue o, ue
WHERE p.cours = c.id AND o.cours = c.id AND o.ue = ue.id
AND debut BETWEEN '$debut_cal'::timestamp AND '$fin_cal'::timestamp ORDER BY debut";
$d_inst = $base->prepare($requete) or die "$DBI::errstr sur requête :\n$requete";
$d_inst->execute() or die "$DBI::errstr sur requête :\n$requete";

while (@data = $d_inst->fetchrow_array) {
  my ($ue,$cours_id,$prof,$salle,$debut,$fin) = @data;
  my ($couleur)  = $ue{$ue};
  my ($duree)    = &DateCalc($debut,$fin);
  $duree         = &Delta_Format($duree,2,'%hd');
  my ($date)     = &UnixDate($debut,'%d/%m/%Y');
  $debut         = &UnixDate($debut,'%R');
  $fin           = &UnixDate($fin,'%R');
#  print "$ue $date $debut $fin $duree\n";
  $planning{$date}{$debut}{$salle}{ue}      =
    a({href=>"detailsCal.cgi?cours_id=$cours_id&salle_id=$salle"},
      "<font size=2>$ue<br>$prof{$prof}<br>$salles{$salle}</font>");
  $planning{$date}{$debut}{$salle}{debut}   = $debut;
  $planning{$date}{$debut}{$salle}{fin}     = $fin;
  $planning{$date}{$debut}{$salle}{duree}   = $duree;
  $planning{$date}{$debut}{$salle}{couleur} = $couleur;
}
$d_inst->finish();

#exit;

## determination des chevauchements horaires et definitition
## d'une table de hachage $nb_cols{$date} comportant le nombre
## de colonnes qu'utilisent les infos horaires du jour et d'une
## entree num_com dans planning qui est le numero de colonne
## ou doit s'afficher l'info correspondante.

foreach my $date (sort keys %planning) {
  my @horaires = ();
    foreach my $debut (sort keys %{$planning{$date}}) {
      foreach my $salle (keys %{$planning{$date}{$debut}}) {
	push @horaires, $planning{$date}{$debut}{$salle};
      }
    }
  $nb_cols{$date} = 0;
  my @collisions;
  do {
    @collisions = ();
    $nb_cols{$date}++;
    while (@horaires) {
      my $data1 = shift @horaires;
      $data1->{num_col} = $nb_cols{$date}-1;
      last unless (@horaires);
      my $data2 = shift @horaires;
      if (&recouvrement($data1->{debut},$data1->{fin},$data2->{debut},$data2->{fin})) {
	push @collisions, $data2;
	unshift @horaires, $data1;
      } else {
	unshift @horaires, $data2;
      }
    }
    @horaires = @collisions;
  } while (@collisions);
}

# foreach my $date (sort keys %planning) {
#      foreach my $debut (sort keys %{$planning{$date}}) {
#       foreach my $salle (keys %{$planning{$date}{$debut}}) {
# 	print "$date $debut $salle $nb_cols{$date} $planning{$date}{$debut}{$salle}{num_col}\n";
#       }
#     }
# }

@format = (
	   '%Y/%m/%d', ## 2004/12/20 date pour sorting
	   '%A',       ## jour de la semaine
	   '%m',       ## numero du mois, car problème avec les noms de mois (%B) 
	   '%d/%m/%Y', ## 20/12/2004 date pour comparaison avec sgbd
	   '%d/%m/%y', ## 20/12/04   date pour affichage
	   '%Y'        ## 2004 année
	  );

#$space1 = '&nbsp;' x 15; ## pour largeur colonne
$space2 = '&nbsp;' x 8; ## pour largeur colonne


$debut = &ParseDate($debut_cal);
$fin   = &ParseDate($fin_cal);
$date  = $debut;
$tableau = -1; ## Indice des tableaux à afficher
$nb_dimanche = -1;
$last_jour = "";
#$jours_de_semaine[$tableau][0] = th($space1);
#$jours[$tableau][0] = td($space1);
($blanc, $gris) = ('#FFFFFF','#EDEDED');
while (&Date_Cmp($fin,$date) > 0) {
  $date  = &DateCalc($date,"+ 1 jour");
  @dates = &UnixDate($date,@format);
  next if ($last_jour eq $dates[1]);  ## Pour les passages aux heures d'hiver
  $last_jour = $dates[1];
  $dates[2] = $mois_texte{$dates[2]};
  if ($dates[1] eq 'dimanche') {
    $nb_dimanche++;
    unless ($nb_dimanche % 1) { ## On fait un nouveau tableau tous les 15 jours
      $tableau++;
      $last_mois = $dates[2];
      $num_mois = 0; ## reset
    }
  }
  if ($last_mois ne $dates[2]) {
    $num_mois++;
    $last_mois = $dates[2];
  }
  $nb_cols{$dates[3]} = 1 unless defined($nb_cols{$dates[3]});
  $nb_cols{$dates[3]} = 1 if ($dates[1] eq 'dimanche'); ## Pas de cours le dimanche
  $printMois[$tableau][$num_mois]{'mois'} = "<b>$dates[2] $dates[5]</b>";
  $printMois[$tableau][$num_mois]{'span'} += $nb_cols{$dates[3]};

  if ($nb_cols{$dates[3]} != 1) {
    push @{$jours_de_semaine[$tableau]}, th({-colspan=>$nb_cols{$dates[3]}},$dates[1]);
    push @{$jours[$tableau]}, td({-align=>"center",-colspan=>$nb_cols{$dates[3]}},$dates[4]);
  } else {
    push @{$jours_de_semaine[$tableau]}, th($dates[1]);
    push @{$jours[$tableau]}, td({-align=>"center"},$dates[4]);
  }
  my $couleur = $blanc;
  for ($i=0;$i<@heures;$i++) {
    $couleur = ($couleur eq $blanc) ? $gris : $blanc;
    if ($dates[1] eq 'dimanche') {  ## Pas de cours le dimanche
      $valeur = "<b>$heures[$i]</b>";
      $cellule[$tableau]{$heures[$i]}{$dates[0]}[0] = {valeur=>$valeur,duree=>.5,couleur=>$couleur};
      next;
    } else {
      $valeur = $space2;
    }
    for ($col=0; $col < $nb_cols{$dates[3]}; $col++) {
      $cellule[$tableau]{$heures[$i]}{$dates[0]}[$col] = {valeur=>$valeur,duree=>.5,couleur=>$couleur}
	unless (defined($cellule[$tableau]{$heures[$i]}{$dates[0]}[$col])); ## initialisation
      if (defined($planning{$dates[3]}{$heures[$i]})) {
	foreach my $salle (keys %{$planning{$dates[3]}{$heures[$i]}}) {
	  $planning{$dates[3]}{$heures[$i]}{$salle}{duree} *= 2; ## Pour unité la demi-heure
	  $cellule[$tableau]{$heures[$i]}{$dates[0]}[$planning{$dates[3]}{$heures[$i]}{$salle}{num_col}] =
	    {
	     valeur  => $planning{$dates[3]}{$heures[$i]}{$salle}{ue},
	     duree   => $planning{$dates[3]}{$heures[$i]}{$salle}{duree},
	     couleur => $planning{$dates[3]}{$heures[$i]}{$salle}{couleur},
	    };
	  for ($j=1;$j<$planning{$dates[3]}{$heures[$i]}{$salle}{duree};$j++) {
	    $cellule[$tableau]{$heures[$i+$j]}{$dates[0]}[$planning{$dates[3]}{$heures[$i]}{$salle}{num_col}]{saute} = 1;
	  }
	  delete $planning{$dates[3]}{$heures[$i]}{$salle};
	}
      }
    }
  }
}
# foreach $heure (@heures) {
#   foreach $date (sort keys %{$cellule[1]{$heure}}) {
#     print "**** $heure **** $date *****\n";
#     foreach (@{$cellule[1]{$heure}{$date}}) {
#       print "------------------------------\n";
#       if (defined($_->{saute})) {
#       print "Saute : $_->{saute}\n" ;
#       } else {
#       print "Valeur  : $_->{valeur}\n";
#       print "Couleur : $_->{couleur}\n";
#       }
#     }
#   }
# }
# exit;

## On cree la page HTML

$style = "<!-- table {border: 4;} a {color: black} -->";

print header(-type => 'text/html', -charset => 'utf-8'),
  start_html(
	     -title => "Calendrier",
	     -style => {-code => $style},
	     -head  => Link({-rel => 'shortcut icon', -href => '../../www/doc/favicon.ico'}),
	    ),
  h1({-align => "center"}, "Les Horaires de cours $annee_scolaire"),
  p("Sur chaque case horaire figurent :"),
  ul(
     li({-type=>'disc'},[
			 "le code de l'UE à laquelle est rattaché le cours",
			 "le nom du professeur en charge du cours",
			 "la salle où il se déroule"
			]
       ),
     p("Activez le LIEN pour avoir accès aux
           INFORMATIONS DÉTAILLÉES SUR LE COURS
           (intitulé complet, emplacement de la salle, etc.)."),
    );

## Affichage d'une liste pour navigation à travers l'année
print  start_form(-method=>"post", -action=>"printCal.cgi"), hidden('annee');
print table({-border=>1,-cellpadding=>9,-align=>'center'},
	    Tr(
	       td([@liste_mois]),
	      ),
	   );
print   end_form();

## On cree les tableaux de 15 jours chacun
for ($tableau=0; $tableau < @jours_de_semaine; $tableau++) {
  $html .= "<table border=1 align='center'>\n";
  $html .= "<tr align='center'>\n";
  foreach (@{$printMois[$tableau]}) {
    $html .= "<td colspan=$_->{'span'}>$_->{'mois'}</td>\n";
  }
  $html .= "</tr>\n<tr align='center'>\n";
  $html .= join (" ",@{$jours_de_semaine[$tableau]});
  $html .= "  </tr>\n";
  $html .= "  <tr align='center'>\n";
  $html .= join (" ",@{$jours[$tableau]});
  $html .= "  </tr>\n";
  
  foreach $heure (@heures) {
    $html .= "<tr align='center'>";
    foreach $date (sort keys %{$cellule[$tableau]{$heure}}) {
      foreach $cel (@{$cellule[$tableau]{$heure}{$date}}) {
	next if (defined($cel->{saute}));
	if ($cel->{duree} > 1) {
	  $html .= "<td bgcolor=$cel->{couleur} rowspan=$cel->{duree}>
$cel->{valeur}</td>"
	} else {
	  $html .= "<td bgcolor=$cel->{couleur}>$cel->{valeur}</td>"
	}
      }
    }
    $html .= "</tr>\n"
  }
  $html .= "</table><hr>\n";
}
print "$html\n";

## Affichage d'une liste pour navigation à travers l'année
print  start_form(-method=>"post", -action=>"printCal.cgi"), hidden('annee');
print table({-border=>1,-cellpadding=>9,-align=>'center'},
	    Tr(
	       td([@liste_mois]),
	      ),
	   );
print   end_form();

print <<'STATCOUNTER';
<!-- Start of StatCounter Code -->
<script type="text/javascript" language="javascript">
var sc_project=1944179;
var sc_invisible=1;
var sc_partition=17;
var sc_security="d6eaa7d4";
</script>

<script type="text/javascript" language="javascript"
src="http://www.statcounter.com/counter/counter.js"></script><noscript><a
href="http://www.statcounter.com/" target="_blank"><img src="http://c18.statcounter.com/counter.php?sc_project=1944179&java=0&security=d6eaa7d4&invisible=1"
alt="counter customizable free hit" border="0"></a> </noscript>
<!-- End of StatCounter Code -->
STATCOUNTER

print end_html();


sub recouvrement {
  ## retourne 0 si pas de recouvrement de plage horaire
  ## d1 à f1 --> plage horaire N°1
  ## d2 à f2 --> plage horaire N°2 
  my ($d1, $f1, $d2, $f2) = @_;
  not ($heures{$d1}>=$heures{$f2} or $heures{$f1}<=$heures{$d2});
}
