#/usr/bin/perl
<<DOC; 
Votre Nom : Santiago HY
Usage exemple : perl BaO2-regexp.pl 2020-5j 3208
Le programme prend en entrée le nom du répertoire-racine contenant les fichiers
à traiter et le nom de la rubrique à traiter parmi ces fichiers. 
DOC
#-----------------------------------------------------------
#$ARGV[0] = répertoire à parcourir
#$ARGV[1] = nom de la rubrique
#-----------------------------------------------------------
use strict;
use utf8;
#use warnings;
use Timer::Simple;
binmode(STDOUT,":utf8");
# on instancie un timer commencant à 0.0s par défaut
my $t = Timer::Simple->new();
# Démarrage du timer
$t->start;
#-----------------------------------------------------------
# Récuperation des arguments à partir de la liste @ARGV avec laquelle le programme a été exécuté 
my $repertoire="$ARGV[0]";
my $rubrique ="$ARGV[1]";
# On évite que le chemin du répertoire finisse par "/"
$repertoire=~ s/[\/]$//;
# Création de deux fichiers de sortie
open my $OUT,">:encoding(utf8)","sortie_$rubrique.txt";
open my $OUTXML,">:encoding(utf8)","sortie_$rubrique.xml";
# Ecriture de l'entête du fichier xml
print $OUTXML "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
print $OUTXML "<corpus2020>\n";
my %dico_titres=(); # Hash pour éviter les doublons 
# Deux variables destinées au bon affichage dans le terminal 
my $nbItem=0;
my $i=0;
print "\n--->Extraction de la rubrique $rubrique<---\n\n";

#----------------------------------------
&parcoursarborescencefichiers($repertoire); # Procédure récursive pour récuperer le contenu textuel 
#----------------------------------------
# Fermeture de la balise racine et des fichiers output
print $OUTXML "</corpus2020>\n";
close $OUT;
close $OUTXML;
#----------------------------------------
# Lancement des procédure qui étiquettent de façon globale, une fois que le corpus est constitué et tokenisé, d'une seul fois.
&etiquetageTT;
&etiquetageUD;
#----------------------------------------
system("rm f_intermediere.txt f_intermediere.txt.pos");
print "Nb item : $nbItem \n";
# temps écoulé depuis le lancement du programme
print "Temps écoulé... : ", $t->elapsed, " seconds\n";
exit;
#----------------------------------------------
sub parcoursarborescencefichiers {
	# Récuperation de l'argument utilisé, càd du chemin du répertoire
    my $path = shift(@_);
	# Exploration de répertoire. L'erreur est signalée s'il y en a une 
    opendir(DIR, $path) or die "Impossible d'ouvrir $path: $!\n";
	# Stokage dans un liste les fichiers du répertoire
    my @files = readdir(DIR);
    closedir(DIR);
	# On parcours la liste de fichier en ignorant les fichiers cachés. On traite chaque fichier
    # On ajoute la fonction sort pour mantenir l'ordre chronologique
    foreach my $file (sort @files) {
		# Si c'est vrai, on ignore les fichiers cachés
		next if $file =~ /^\.\.?$/;
		# Reconstruction du chemin
		$file = $path."/".$file;
		# Avec -d, on verifie si le fichier est un dossier. Si c'est le cas, on relance la procédure
		if (-d $file) {
			&parcoursarborescencefichiers($file);
		}
		# S'il s'agit d'un fichier, on le traite
		if (-f $file) {
			# Si c'est un fichier xml de notre rubrique ...
			if ($file =~/$rubrique.+xml$/) {
				print $i++," Traitement de : ",$file,"\n"; # Affichage du nb et du nom du fichier traité
				&traitements($file) # Procédure pour traiter le fils RSS
			}
		}
    }
}
#----------------------------------------------
sub traitements {
	my $file = shift(@_);
	open my $fichier_RSS,"<:encoding(utf8)", $file; # Ouverture du fichier xml
	# Par défaut cette variable contient \n. On efface le contenu pour pouvoir traite le texte de façon globale
	$/=undef;
	my $texte=<$fichier_RSS>; # Lecture globale
	close $fichier_RSS;
	# Si nous trouvons du contenu textuel.. (s = reconnaisance des spaces, g = global)

	while ($texte=~/<item><title>(.+?)<\/title>.+?<description>(.+?)<\/description><guid.+?\/(\d{4}\/\d{2}\/\d{2}).+?<\/item>/sg) {
		# Récuperation du contenu textuel des titres, leur dates et leur description. 
		# Voici une autre regexp pour récupérer les dates avec le mois en lettres. Nous préférons les chiffres, car c'est plus facile à gérer. 
		# <item>.*?<title>(.+?)<\/title><pubDate>.+?(\d{2}\s\w{3}\s\d{4}).+?<\/pubDate><description>(.+?)<\/description>
		my $titre=$1;
		my $description=$2;
		my $date= $3;
		# Si le titre n'a pas été déjà stocké dans %dico_titres, on traite le contenu. On évite des doublons.
		if (!(exists $dico_titres{$titre})) { 
			$nbItem++;
			$dico_titres{$titre}=$description;
			# Appel du sous-programme de nettoyage 
			($titre,$description)=&nettoyage($titre,$description);
			# Ecriture des résultats en sorties
			print $OUT $titre,"\n";
			print $OUT $description,"\n";
            print $OUT "\n";
			# On réalise un pre-traitement avec Tree-tagger pour tokenizer le contenu textuel. Lancement d'une nouvelle procédure
			my ($titre_tokenise, $description_tokenise)=&tokenization($titre,$description);
			#--------------------------------------
			#Écriture des résultats dans le fichier xml de façon que chaque token et balise occupent une ligne
			#-----
			print $OUTXML "<item date=\"$date\">\n<titre>\n$titre_tokenise</titre>\n<description>\n$description_tokenise</description>\n</item>\n";
		}
	}
}
#----------------------------------------------
sub nettoyage {
    # Récuperation des arguments de la procédure
	# Égal à my $titre=shift(@_); my $description=shift(@_);
	# Néttoyage de contenu non textuel.
    my $titre = $_[0];
    my $description = $_[1];
	$titre=~s/^<!\[CDATA\[//;
	$titre=~s/\]\]>$//;
    $titre=~s/&lt;.+?&gt;//g;
    $titre=~s/&#38;#39;/'/g;
    $titre=~s/&#38;#34;/"/g;
    $titre=~s/$/\./g;
	$titre=~s/\.+$/\./g;
	$titre=~s/\?\.$/\?/g;
	$titre=~s/&nbsp;//g;
	$titre=~s/&amp;/&/g;
	$description=~s/^<!\[CDATA\[//;
	$description=~s/\]\]>$//;
	$description=~s/$/\./g;
	$description=~s/\.+$/\./g;
	$description=~s/\?\.$/\?/g;
    $description=~s/&lt;.+?&gt;//g;
    $description=~s/&#38;#39;/'/g;
    $description=~s/&#38;#34;/"/g;
	$description=~s/&nbsp;//g;
	$description=~s/&amp;/&/g;
    return $titre, $description;
}
#----------------------------------------------
sub tokenization {
	# Récuperation des arguments de la procédure
    my $titre = $_[0];
    my $description = $_[1];
	#-----------------tokenisation titre-----------------------------
	# Création d'un fichier intermédiere avec le titre pour tokenisé le contenu
	&ecrire_fichier("f_intermediere.txt", $titre);
	# Lancement du tokenisateur de tree-tagger
    system ("perl -f ./tree-tagger-linux-3.2.3/tokenise-utf8.pl f_intermediere.txt > f_intermediere.txt.pos");
    my $titre_tokenise_xml = &lire_fichier("f_intermediere.txt.pos");
	#-----------------tokenisation description-----------------------------
	&ecrire_fichier("f_intermediere.txt", $description);
    system ("perl -f ./tree-tagger-linux-3.2.3/tokenise-utf8.pl f_intermediere.txt > f_intermediere.txt.pos");
	my $description_tokenise_xml = &lire_fichier("f_intermediere.txt.pos");
	# On revoie les deux variables contenant le titre et la description tokenisés.
    return $titre_tokenise_xml, $description_tokenise_xml;
}

#----------------------------------------------
sub etiquetageTT {
	# Étiquetage des POS et lemmas du français avec TreeTagger depuis le répertoire ./treetagger-3.2
	# -f pour le français. Le modéle utilisé est destiné au français
    print "Tagging...\n";
    system("perl -f ./tree-tagger-linux-3.2.3/tokenise-utf8.pl sortie_$rubrique.xml | ./tree-tagger-linux-3.2.3/bin/tree-tagger ./tree-tagger-linux-3.2.3/french-utf8.par -token -lemma -no-unknown -sgml > sortie-TT_$rubrique");
    # Lancement de duexième programme pour baliser chaque nouvelle étiquette ou élément.
    # Ce programme a été légèrement modifié pour l'adapter à ce travail
    print "Création d'un fichier XML étiqueté...\n";
    system("perl ./tree-tagger-linux-3.2.3/treetagger2xml-utf8.pl sortie-TT_$rubrique utf8");
    # Nous changeons le html entities..
    my $text = &lire_fichier("sortie-TT_$rubrique.xml");
    $text =~ s/&/&amp;/g;
    &ecrire_fichier("sortie-TT_$rubrique.xml", $text);
    system("rm sortie_$rubrique.xml sortie-TT_$rubrique"); 
}
#-----------------------------------------------
sub etiquetageUD {
	# Étiquetage en dépendance avec UDpipe depuis le programme situé dans le répertoire ./udpipe-1.2.0-bin
	# Sortie : un fichier txt format CONLL. 
	# Utilisation de l'option --tokenizer=presegmented pour eviter la sur-segmentation
	system("./udpipe-1.2.0-bin/bin-linux64/udpipe --tokenize --tokenizer=presegmented --tag --parse ./udpipe-1.2.0-bin/modeles/french-gsd-ud-2.5-191206.udpipe sortie_$rubrique.txt > sortie-udpipe_$rubrique.txt");
}
#--------------------------------------------------
sub lire_fichier {
    my ($filename) = @_;
    open my $in, '<:encoding(UTF-8)', $filename or die "Impossible d'ouvrir '$filename'$!";
    local $/ = undef;
    my $texte = <$in>;
    close $in;
    return $texte;
}
#--------------------------------------------------
sub ecrire_fichier {
    my ($filename, $texte) = @_;
    open my $out, '>:encoding(UTF-8)', $filename or die "Impossible d'ouvrir '$filename'$!";
    print $out $texte;
    close $out;
    return;
}