#!/usr/bin/perl
#==========================================================================
# Auteur : djibril
# Date   : 03/07/2011 20:35:16
# But    : Script Perl/Tk utilisant des threads pour rechercher nos fichiers
#==========================================================================
use warnings;
use strict;

use Tk;                         # Pour créer notre GUI
use Tk::LabFrame;
use File::Find;
use threads;                    # Pour créer nos threads
use threads::shared;            # Pour partager nos données entre threads
use Time::HiRes qw( sleep );    # Pour faire des sleeps < à une seconde

# Contient les fonctions à appeler dans le thread si besoin
my %fonctions_a_lancer_dans_thread = ( 
  'recherchez_fichier' => \&recherchez_fichier, 
);

#===================================
# Threads et variables partagées
#==================================
my $tuer_thread : shared;          # Permet de tuer le thread proprement
my $nom_fonction : shared;         # Contient le nom de la fonction à appeler
my $thread_travail : shared;       # Contient la valeur permettant au thread de lancer une procédure
my @arguments_thread : shared;     # Contient les arguments à passer à une éventuelle procédure
my @resultat_fonction : shared;    # Contient le résultat des fonctions lancées dans le thread

$thread_travail = 0;               # 0 : thread ne fait rien, 1 : il bosse
$tuer_thread    = 0;               # 0 : thread en vie, 1 : thread se termine

# Création du thread
my $thread = threads->create( \&notre_processus_leger );

#===================================
# Début du code principal Perl Tk
#==================================
my $fenetre = new MainWindow(
  -title      => 'Recherche de fichiers',
  -background => 'white',
);
$fenetre->protocol( "WM_DELETE_WINDOW", \&fermer_application );

# Affichage de l'heure
my $date_heure = date();
my $label_date = $fenetre->Label(
  -textvariable => \$date_heure,
  -background   => 'white',
  -font         => '{Arial} 16 {bold}',
)->pack(qw/ -pady 20 /);

# État de la recherche du fichier
my $etat_recherche = 'Aucune recherche en cours';
my $label_etat     = $fenetre->Label(
  -textvariable => \$etat_recherche,
  -background   => 'white',
  -foreground   => 'blue',
  -font         => '{Arial} 12 {bold}',
)->pack(qw/ -pady 20 /);

# Cadre de recherche
my $cadre = $fenetre->LabFrame(
  -label      => 'Cadre de recherche',
  -background => 'white',
)->pack(qw/ -pady 20 -padx 20 /);

my ( $motif_recherche, $repertoire_emplacement );
my $label1 = $cadre->Label( -text => 'Nom du fichier à trouver : ', -background => 'white' );
my $entry_nom_fichier = $cadre->Entry( -textvariable => \$motif_recherche );
my $label2 = $cadre->Label( -text => 'Emplacement : ', -background => 'white' );
my $entry_emplacement = $cadre->Entry( -textvariable => \$repertoire_emplacement );

my $bouton_emplacement = $cadre->Button(
  -text    => '...',
  -command => sub {
    $repertoire_emplacement = $cadre->chooseDirectory(
      -title     => 'Sélectionner un emplacement',
      -mustexist => 1,
    );
  },
);

# Affichage d'un bouton pour rechercher un fichier
my $bouton = $cadre->Button(
  -text    => 'Recherchez un fichier',
  -command => [ \&recherchez_fichier_tk ],
  -font    => '{Arial} 14 {bold}',
);

$label1->grid( $entry_nom_fichier, '-',                 -sticky => 'nw' );
$label2->grid( $entry_emplacement, $bouton_emplacement, -sticky => 'nw' );
$bouton->grid( '-',                '-',                 qw/ -padx 10 -pady 10 / );

# Centrer ma fenêtre
centrer_widget($fenetre);

# Toutes les secondes, la date et l'heure évoluent
$fenetre->repeat( 1000, sub { $date_heure = date(); } );

MainLoop;

#================================================
# notre_processus_leger
#================================================
sub notre_processus_leger {

  # Tourne en rond
  while (1) {

    # demande au thread de travailler
    if ( $thread_travail == 1 ) {

      # Lance la procédure
      $fonctions_a_lancer_dans_thread{$nom_fonction}->(@arguments_thread);

      # demande au thread de dormir
      $thread_travail = 0;
    }

    # Terminer le thread
    last if ( $tuer_thread == 1 );
    sleep 0.5;
  }
  return;
}

sub fermer_application {
  
  # Demande au thread de se terminer
  $tuer_thread = 1;
  
  # On attend que le thread se termine proprement
  $thread->detach();
  
  exit;
}

sub recherchez_fichier_tk {
    if ( not defined $motif_recherche or not defined $repertoire_emplacement or ! -d $repertoire_emplacement ) {
      return;
    }
    $etat_recherche = "Liste des fichiers en cours";
    
    # On lui indique la procédure à appeler
    $nom_fonction = "recherchez_fichier";  
    
    # On lui donne les arguments
    @arguments_thread = ($motif_recherche, $repertoire_emplacement);  
    
    # On va demander au thread de bosser
    $thread_travail   = 1;             

  return;
}

sub recherchez_fichier {
  my ($motif_recherche, $repertoire_emplacement) = @_;
  
  # Recherchons le fichier
  my $fichier_trouve = 0;
  find(
    { wanted => sub {
        if ( $_ =~ m{$motif_recherche}i ) { 
          $fichier_trouve++; 
          print "$fichier_trouve- $File::Find::name\n";
        }
      }
    },
    $repertoire_emplacement
  );

  return $fichier_trouve;
}

#================================================
# But : Obtenir la date et l'heure
#================================================
sub date {
  my $time = shift || time;    #$time par defaut vaut le time actuel
  my ( $seconde, $minute, $heure, $jour, $mois, $annee, $jour_semaine, $jour_annee, $heure_hiver_ou_ete )
    = localtime($time);
  $mois  += 1;
  $annee += 1900;

  # On rajoute 0 si le chiffre est compris entre 1 et 9
  foreach ( $seconde, $minute, $heure, $jour, $mois, $annee ) { s/^(\d)$/0$1/; }
  return "$jour/$mois/$annee - $heure:$minute:$seconde";
}

#================================================
# But : Centrer un widget automatiquement
#================================================
sub centrer_widget {
  my ($widget) = @_;

  # Height and width of the screen
  my $largeur_ecran = $widget->screenwidth();
  my $hauteur_ecran = $widget->screenheight();

  # update le widget pour récupérer les vraies dimensions
  $widget->update;
  my $largeur_widget = $widget->width;
  my $hauteur_widget = $widget->height;

  # On centre le widget en fonction de la taille de l'écran
  my $nouvelle_largeur = int( ( $largeur_ecran - $largeur_widget ) / 2 );
  my $nouvelle_hauteur = int( ( $hauteur_ecran - $hauteur_widget ) / 2 );
  $widget->geometry( $largeur_widget . "x" . $hauteur_widget . "+$nouvelle_largeur+$nouvelle_hauteur" );

  $widget->update;

  return;
}