#/usr/bin/perl
#--------------------------------------------------------------------------------------------
# --- BAO 3 --- Version: Listes -------------------------------------------------------------
#--------------------------------------------------------------------------------------------
# Entrée: Le programme construit en entrée:
#			-- Un texte étiqueté et lemmatisé par Talismane + un fichier de patrons syntaxiques 
#			   avec un patron par ligne (ex: NC ADJ).
# Sortie: Le programme construit en sortie:
#			Un fichier avec pour chaque patron sa liste de termes triés par fréquence
# Mode de lancement:
# 		perl5.28.1.exe perl_version_listes.pl FICHIER_TALISMANE.txt FICHIER_PATRONS.txt
#--------------------------------------------------------------------------------------------

# On met explicitement utf8 comme encodage, de façon à qu'on s'assure que la sortie soit écrite en UTF-8:
use utf8;

# On appelle module perl qui gére le temps qui nous aide à afficher le temps de début et fin de traitement:
use Time::HiRes qw(gettimeofday tv_interval);
my $timepg = [gettimeofday];

# On initialise la variable où on va garder la liste de patrons du fichier passé comme argument au programme:
my $listePatron;

# On ouvre le fichier des patrons avec l'encodage UTF-8:
open my $fileTer,"<:encoding(UTF-8)",$ARGV[1];

# On fait une boucle while:
while (my $patron=<$fileTer>) {
	# On fait le chomp de chaque ligne:
	chomp($patron);
	# La fonction push ajoute à la variable ListePatron les patrons qu'on a repris de notre fichier:
    push(@{$listePatron},[split(/ +/,$patron)])
}
# Fermture du fichier de patrons:
close($fileTer);

# Initialisation d'un tableau hashage(dictionnaire) de patrons vides:
my %dicoPatron=();

# Initialisation du compteur:
my $nbTerme=0;

# Initialisation d'une liste vide pour nos tokens:
my @WORDS;

# Initialisation d'une liste vide pour nos POS:
my @POS;	

# On ouvre le fichier étiqueté par Talismane, passé comme premier argument au programme avec encodage UTF-8:
open my $fileT,"<:encoding(UTF-8)",$ARGV[0];

# On lit le fichier ligne par ligne:
while (my $ligne=<$fileT>) {
	# En utilisant des expressions régulières, on saute de ligne si elle contient les caractères suivants: £, #, $
	if (($ligne!~/^1\t££/) and ($ligne!~/^\#\#/) and ($ligne!~/^$/)){
		# S'il n y a pas ces caractèrs on rajoute la ligne à une liste temporaire:
		my @TMPLIGNE=split(/\t/,$ligne);
		# On rajoute à notre liste de tokens l'élément de la liste temporaire à l'index 1 qui correspond au token.
		push(@WORDS,$TMPLIGNE[1]);
		# On ajoute à notre liste de POS-tags l'élément de la liste temporaire à l'index 3 qui correspond au POS-tag réspectivement.
		push(@POS,$TMPLIGNE[3]);
	}
}
# Fermeture du fichier Talismane:
close($fileT);

# Initialisation du compteur de la longueur:
my $lg=0;

# Avec une boucle while on associe à une variable qui va contenir les POS-tags d'un liste, son index dans l'autre:
while (my $pos=$POS[$lg]) {
	# À l'aide d'une boucle for-each, on associe le patron à son valeur:
	foreach my $patron (@{$listePatron}) {
		# Si le POS-tag est identique à celui du patron on lui met en position de l'index 0:
		if ($pos eq $patron->[0] ) {
			# De plus on va lui associer l'index, la longueur et stop:
			my $indice=1;
			my $longueur=1;
			my $stop=1;
			# Avec une boucle while on dit que lorsque l'indice est moins ou égal à celui du patron et stop est égal à zéro on applique la condition suivante:
			while (($indice <= scalar @$patron) and ($stop == 1)) {
				# Si le POS avec l'indice (qui est égal à la addition des compteurs indice+longueur) est égal au patron et son indice on augmente les compteurs longueur et indice.
				# NB! "->" est un opérateur infixe de déréférence, tout comme en C et C ++. Si le côté droit est un [...], {...} ou un (...) indice, le côté gauche doit être une référence dure ou symbolique à un tableau, un hachage ou un sous-programme respectivement. (Ou techniquement, un emplacement capable de contenir une référence dure, s'il s'agit d'une référence de tableau ou de hachage utilisée pour l'affectation.) Sinon, le côté droit est un nom de méthode ou une simple variable scalaire contenant le nom de la méthode ou une référence à un sous-programme, et le côté gauche doit être un objet (une référence privilégiée) ou un nom de classe (c'est-à-dire un nom de package). .
				if ($POS[$indice+$lg] eq $patron->[$indice]) {
					$longueur++;
					$indice++;
				}
				# Sinon le compteur stop sera égal à zéro:
				else {
					$stop=0;
				}
			}
			# Avec la boucle conditionnelle on dit que si le compteur longueur et égal au patron converti en liste de scalaire:
			if ($longueur == scalar @$patron) {
				# On ajoute au diccionaire de patrons ce patron, le token associé:
				$dicoPatron{join(" ",@{$patron})}->{join(" ",@WORDS[$indice+$lg-scalar @$patron..$indice+$lg-1])}++;
				# On augmente compteur qui indique combien de fois on a repéré ce patron:
				$nbTerme++;
			}
		}
	}
	# On incrémente le compteur de la longueur:
	$lg++;
}

# On ouvre un fichier de sortie, avec encodage utf8:
open my $fileResu,">:encoding(UTF-8)","BAO3-TALISMANE-PERL-V2.txt";
# On écrit dans le fichier: 
print "$nbTerme éléments trouvés\n";
print $fileResu "$nbTerme éléments trouvés\n";

# Avec une boucle foreach on associe le patron (clé de diccionaire) à son valeur dans le diccionaire dicoPatron
foreach my $patron (keys %dicoPatron) {
	# On met le patron dans le fichier:
	print "\nType de pattern: ".$patron." \n\n";
	print $fileResu "\nType de pattern: ".$patron." \n\n";
	
	# Avec une boucle foreach on associe à la variable terme la suite de tokens repérée du diccionaire via les patrons:
	foreach my $terme (sort {$dicoPatron{$patron}->{$b} <=> $dicoPatron{$patron}->{$a} } keys %{$dicoPatron{$patron}}) {
		# On écrit les patrons dans la même ligne que son patron:
		print $dicoPatron{$patron}->{$terme}."\t".$terme."\n";
		print $fileResu $dicoPatron{$patron}->{$terme}."\t".$terme."\n";
	}
}

# On affiche le temps de l'exécution:
print "\nScript execution time: " . tv_interval($timepg) . " seconds.";
print $fileResu "\nScript execution time: " . tv_interval($timepg) . " seconds.";

# Fermeture du fichier de sortie:
close($fileResu);

# On sort:
exit;
