#!/usr/bin/perl -w

use strict;
use Data::Dumper;
use warnings;
use Class::Struct;

#génère un ctm avec les informations suivantes :
#
#mot	NbNode MinNode MaxNode MeanNode VarNode SVarNode Posterior  AcousticLogLikelihood AcousticLogLikelihood/Frame AcousticConfidenceLikelihood AcousticConstraintLikeLihood AcousticNoConstraint Likelihood ClasseRepliLinguistique RepliLinguistique LogLinguistique LogUnigramme NbMotsFenetre NbNulNode NbTrame

#fasctnc :
#ok      aussi   1 ( time=748 nodes=2 min=3.57628e-07 max=1 mean=0.5 var=0.499999 svar=0.707106 )

#gvalign :
#"Decoding 19990628_1900_1920_inter_21339:1371_S19_S_18 [414,71](19) --> [Gauss Ratio : 6.35 % of 235777]
#	LogLikelihood: 9.0206e+01	LogLikelihood/Frame: 1.5034e+01	 CONF  [0.459433] (15.03,20.42)


#ctm :
#19990628_1900_1920_inter 1 213.40 0.05 au
#


my $TailleFenetreAvt=50;
my $TailleFenetreAp=50;

struct CTM =>
{
	Divers => '$',
	Debut => '$',
	Duree => '$',
	Mot => '$',
	ProbUnig => '$',
	NbWordWindow => '$',
	PPLWindow => '$',
	Genre => '$',
	Type => '$',
};


struct GVALIGN =>
{
	Debut => '$',
	GaussRatio => '$',
	LogVrais => '$',
	LogVraisTrame => '$',
	Confiance => '$',
	DAPcontraint => '$',
	DAPnoncontraint => '$',
};

sub PrintGVALIGN
{
	my ($gvalign)=@_;

	foreach (@$gvalign)
	{
		my $Debut = $_->Debut;
		my $GaussRatio = $_->GaussRatio;
		my $LogVrais = $_->LogVrais;
		my $LogVraisTrame = $_->LogVraisTrame;
		my $Confiance = $_->Confiance;
		my $DAPcontraint = $_->DAPcontraint;
		my $DAPnoncontraint = $_->DAPnoncontraint;

		print "$Debut	$GaussRatio	$LogVrais	$LogVraisTrame	$Confiance	$DAPcontraint	$DAPnoncontraint\n";
	}
}

struct MLCLASS =>
{
	MotP => '$',
	Mot => '$',
	MotS => '$',
	LMLogProbP => '$',
	LMLogProb => '$',
	LMLogProbS => '$',
	TypeNgramP0 => '$',
	TypeNgramP => '$',
	TypeNgram => '$',
	TypeNgramS => '$',
	TypeNgramS2 => '$',
};

struct FastNC =>
{
	Etat => '$',
	Mot => '$',
	Debut => '$',
	NbNoeuds => '$',
	Posterior => '$',
	MinPos => '$',
	MaxPos => '$',
	MoyPos => '$',
	VarPos => '$',
	SVarPos => '$',
	DelAvt => '$',
	DelAp => '$',
};


#my $LM_SERVER;
my $TypeML;
my $pathLM;
my $nameLM;

if (@ARGV < 7)
{
	print "ExtractData.pl <i: path ML speeral> <i: name ML speeral>  <i: FichierFastNC> <i: FichierCTM> <i: SortieGVALIGN> <i: mlclass> <i: type ML>\n";
}
else
{
	my @DonneesFastNC;
	my @DonneesCTM;
	my @DonneesGVALIGN;
	my @DonneesMLCLASS;
	$pathLM = $ARGV[0];
	$nameLM = $ARGV[1];
	my $NomFichierFastNC = $ARGV[2];
	my $NomFichierCTM = $ARGV[3];
	my $NomFichierGVALIGN = $ARGV[4];
	my $NomFichierMLCLASS = $ARGV[5];
	$TypeML = $ARGV[6];
	

	my %ReverseCTM;
	my %ReverseGVALIGN;
	my %ReverseFastNC;

	ChargerFichierFastNC( $NomFichierFastNC,\@DonneesFastNC);
	ChargerFichierCTM ($NomFichierCTM, \@DonneesCTM);
	FindUnigram (\@DonneesCTM);
	AddPplAndNbWord(\@DonneesCTM, $TailleFenetreAvt, $TailleFenetreAp);
	ChargerSortieGVAlign ($NomFichierGVALIGN, \@DonneesGVALIGN);

	ChargerMLCLASS ($NomFichierMLCLASS, \@DonneesMLCLASS);	

	map($ReverseCTM{$_->Debut}=$_, @DonneesCTM);
	map($ReverseGVALIGN{$_->Debut}=$_, @DonneesGVALIGN);
	map($ReverseFastNC{$_->Debut}=$_, @DonneesFastNC);

	GoPrint(\%ReverseCTM,\%ReverseGVALIGN,\%ReverseFastNC, \@DonneesMLCLASS);
}



sub FindPPL
{
	my ($Mots, $StrCTM)=@_;
	
	##print `echo "$Mots" | ngram -order 4 -use-server $LM_SERVER -ppl - -debug 2 -no-eos -no-sos 2>/dev/null`;
	#my $Resultat = my $Resultat = `echo "$Mots" | ngram -order 4 -use-server $LM_SERVER -ppl - -debug 2 -no-eos -no-sos 2>/dev/null`;

	#print "--> ppl pour mots : $Mots";

	my $cmd = "$ENV{\"OTMEDIA_HOME\"}/tools/PACKAGE_MESURES_V1.0/bin/getprob $pathLM $nameLM $Mots";
	my $Resultat = `$cmd`;

	$Resultat=~/.*?ppl=(.*?)\s+.*/;

	#print "---> ppl $1 \n";

	$StrCTM->PPLWindow($1);
}


sub FindWordsInWindow
{
	my ($Cur, $Deb, $Fin, $DataCTM, $WindowSizeB, $WindowSizeA)=@_;

	$$Deb=$Cur;
	$$Fin=$Cur;

	while ($$Deb > 0 &&   (@$DataCTM[$Cur]->Debut - @$DataCTM[$$Deb]->Debut) < $WindowSizeB)
	{
		$$Deb--;
	}

	while ($$Fin < @$DataCTM && (@$DataCTM[$$Fin]->Debut - @$DataCTM[$Cur]->Debut) < $WindowSizeA)
	{
		$$Fin++;
	}

	@$DataCTM[$Cur]->NbWordWindow($$Fin-$$Deb);
}


sub AddPplAndNbWord
{
	my ($DataCTM, $WindowSizeB,  $WindowSizeA)=@_;

	my $i;
	my $IndiceDeb;
	my $IndiceFin;

	for ($i=0; $i < @$DataCTM; $i++)
	{
		FindWordsInWindow($i, \$IndiceDeb, \$IndiceFin, $DataCTM, $WindowSizeB, $WindowSizeA);

		my $Suite="";

		for (my $j = $IndiceDeb; $j < $IndiceFin; $j++)
		{
			my $Mot = @$DataCTM[$j]->Mot;
			$Suite.="\"$Mot\" ";
		}
		
		if ($IndiceDeb == $IndiceFin)	
		{
			$Suite.="\"@$DataCTM[$i]->Mot\"";
		}

		FindPPL($Suite, @$DataCTM[$i]);

	}

}


sub par_num { return $a <=> $b }

sub GoPrint
{
	my ($ReverseCTM,$ReverseGVALIGN,$ReverseFastNC,$DonneesMLCLASS)=@_;

	my $NbMot=0;
	my $RealNb=0;

	#print "Go print !!\n";

	foreach my $cle (sort par_num keys %$ReverseCTM)
	{
		my $mot =  $ReverseCTM->{$cle}->Mot;

		if ($mot ne "<s>" && $mot ne "</s>")
		{
			while ( @$DonneesMLCLASS[$NbMot]->Mot ne $ReverseCTM->{$cle}->Mot)
			{
				$NbMot++;
			}	

			if (@$DonneesMLCLASS[$NbMot]->Mot ne $ReverseCTM->{$cle}->Mot)
			{
				PrintALL($ReverseCTM->{$cle}, $ReverseGVALIGN->{$cle}, $ReverseFastNC->{$cle}, 0);
				print "Attention ; risque d'erreur !\n";
				$NbMot=$RealNb;
			}
			else
			{
				PrintALL($ReverseCTM->{$cle}, $ReverseGVALIGN->{$cle}, $ReverseFastNC->{$cle}, @$DonneesMLCLASS[$NbMot]);
			}
		}

		$RealNb++;
	}
}


#NbWordWindow => '$',
#149 #PPLWindow => '$',


sub PrintALL
{
	my ($StrCTM, $StrGVALIGN, $StrFastNC, $StrML)=@_;


	if ($StrCTM)
	{
		my $Divers = $StrCTM->Divers;
		my $Debut = $StrCTM->Debut;
		my $Duree = $StrCTM->Duree;
		my $Mot = $StrCTM->Mot;
		my $ProbUnig=$StrCTM->ProbUnig;
		my $WindowSize=$StrCTM->NbWordWindow;
		my $PPLWindow=$StrCTM->PPLWindow;
		my $Type=$StrCTM->Type;
		my $Genre=$StrCTM->Genre;


		$ProbUnig = "" if(!$ProbUnig);
		$PPLWindow = "" if(!$PPLWindow);
		
		print "$Divers	$Debut	$Duree	$Mot	Mot=$Mot	Genre=$Genre	Type=$Type	LogProbUni=$ProbUnig	Dur=$Duree	win=$WindowSize	ppl=$PPLWindow	ML=$TypeML	";



		if ($StrML)
		{
			my $MotP=$StrML->MotP;
			my $Mot=$StrML->Mot;
			my $MotS=$StrML->MotS;
			my $LMLogProbP=$StrML->LMLogProbP;
			my $LMLogProb=$StrML->LMLogProb;
			my $LMLogProbS=$StrML->LMLogProbS;
			my $TypeNgramP0=$StrML->TypeNgramP0;
			my $TypeNgramP=$StrML->TypeNgramP;
			my $TypeNgram=$StrML->TypeNgram;
			my $TypeNgramS=$StrML->TypeNgramS;
			my $TypeNgramS2=$StrML->TypeNgramS2;

			print "LMProb=$LMLogProb	NgramP0=$TypeNgramP0	NgramP=$TypeNgramP	Ngram=$TypeNgram	NgramS=$TypeNgramS	NgramS2=$TypeNgramS2	";
		}
		else
		{
			print "Mot=	Genre=	Type=	LMProb=	NgramP0=	NgramP=	Ngram=	NgramS=	NgramS2=	";
		}


		if ($StrGVALIGN)
		{
			#my $Debut = $StrGVALIGN->Debut;
			my $GaussRatio = $StrGVALIGN->GaussRatio;
			my $LogVrais = $StrGVALIGN->LogVrais;
			my $LogVraisTrame = $StrGVALIGN->LogVraisTrame;
			my $Confiance = $StrGVALIGN->Confiance;
			my $DAPcontraint = $StrGVALIGN->DAPcontraint;
			my $DAPnoncontraint = $StrGVALIGN->DAPnoncontraint;

			print "GaussRatio=$GaussRatio	LogVrais=$LogVrais	LogVraisFrame=$LogVraisTrame	Conf=$Confiance	DAP1=$DAPcontraint	DAP2=$DAPnoncontraint	";
		}
		else
		{
			print "GaussRatio=	LogVrais=	LogVraisFrame=	Conf=	DAP1=	DAP2=	";
		}

		if ($StrFastNC)
		{
			#my $Mot = $StrFastNC->Mot;
			#my $Deb = $StrFastNC->Debut;
			my $NbNoeuds = $StrFastNC->NbNoeuds;
			my $pos = $StrFastNC->Posterior;
			my $Min = $StrFastNC->MinPos;
			my $Max = $StrFastNC->MaxPos;
			my $Moy = $StrFastNC->MoyPos;
			my $Var = $StrFastNC->VarPos;
			my $SVar = $StrFastNC->SVarPos;
			my $Avt = $StrFastNC->DelAvt;
			my $Ap = $StrFastNC->DelAp;

			print "nodes=$NbNoeuds	posterior=$pos	min=$Min	max=$Max	mean=$Moy	var=$Var	svar=$SVar	nullBef=$Avt	nullAf=$Ap\n";
		}
		else
		{
			print "nodes=	posterior=	min=	max=	mean=	var=	svar=	nullBef=	nullAf=\n";
		}
	}
}


sub FindUnigram
{
	my ($Data)=@_;


	foreach (@$Data)
	{
		my $Mot=$_->Mot;

		$Mot =~ s/'/\\'/g; #E.F sinon fait planter getprob !!!
		my $cmd = "$ENV{\"OTMEDIA_HOME\"}/tools/PACKAGE_MESURES_V1.0/bin/getprob $pathLM $nameLM $Mot";
		my $Resultat = `$cmd`;

		$Resultat=~/.*?logprob=(.+?)\s+.*/;

		$_->ProbUnig($1);

	}	
}



sub ChargerFichierFastNC
{
	my ($NomFichier, $Donnees)=@_;

	open (FICHIER, $NomFichier) or die "Impossible d'ouvrir $NomFichier !\n";

	my $DelAvt=0;
	my $NbMots=0;

	foreach my $Ligne (<FICHIER>)
	{
		if ($Ligne=~/(.*?)\t(.*?)\t(.*?) \( time=(.*?) nodes=(.*?) min=(.*?) max=(.*?) mean=(.*?) var=(.*?) svar=(.*?) \)/)
		{
			my $FastNCStruct = FastNC->new();
			$FastNCStruct->Etat($1);
			$FastNCStruct->Mot($2);
			$FastNCStruct->Posterior($3);
			$FastNCStruct->Debut($4);
			$FastNCStruct->NbNoeuds($5);
			$FastNCStruct->MinPos($6);
			$FastNCStruct->MaxPos($7);



			$FastNCStruct->MoyPos($8);
			$FastNCStruct->VarPos($9);
			$FastNCStruct->SVarPos($10);
			$FastNCStruct->DelAvt($DelAvt);
			$FastNCStruct->DelAp(0);

			$DelAvt=0;

			@$Donnees[$NbMots++]=$FastNCStruct;
		}
		else
		{
			if ($Ligne=~/^del/)
			{
				if ($NbMots > 0)
				{
					@$Donnees[$NbMots-1]->DelAp(@$Donnees[$NbMots-1]->DelAp+1);
				}
				$DelAvt++;
			}
			if ($Ligne=~/^ins/ || $Ligne=~/^sub/)
			{
				$Ligne=~/(.*?)\t(.*?)\t.*\)/;
				
				my $FastNCStruct = FastNC->new();
				$FastNCStruct->Etat($1);
				$FastNCStruct->Mot($2);
				$FastNCStruct->Posterior(0.5);
				$FastNCStruct->Debut(-1);
				$FastNCStruct->NbNoeuds(2);
				$FastNCStruct->MinPos(0.5);
				$FastNCStruct->MaxPos(0.5);



				$FastNCStruct->MoyPos(0.5);
				$FastNCStruct->VarPos(0.5);
				$FastNCStruct->SVarPos(0.25);
				$FastNCStruct->DelAvt($DelAvt);
				$FastNCStruct->DelAp(0);

				$DelAvt=0;

				@$Donnees[$NbMots++]=$FastNCStruct;
			}
		}
	}
}

sub ChargerFichierCTM
{
	my ($NomFichier, $Donnees)=@_;

	my $First=-1;
	my $NbLignes=0;

	open (FICHIER, $NomFichier) or die "Impossible d'ouvrir $NomFichier !\n";


	$NomFichier=~/(.*)([0-9]+):([0-9]+).*?([MF]+)#([ST]+).*/;
	my $Genre=$4;
	my $Type=$5;
	
	foreach my $Ligne (<FICHIER>)
	{
		chomp $Ligne;
		if ($Ligne=~/(.*? .*?) (.*?) (.*?) (.*)/)
		{
			if ($First == -1)
			{
				$First=$2;
				$First*=100;
				$First=int($First+.5);
			}


			my $CTMStruct = CTM->new();

			my $Deb = $2*100;
			$Deb=int($Deb+.5);
			my $Dur = $3*100;
			$Dur=int($Dur+.5);


			$CTMStruct->Divers($1);
			$CTMStruct->Debut($Deb-$First);
			$CTMStruct->Duree($Dur);
			my $mot = $4;
			$mot =~ s/ $//g;
			$CTMStruct->Mot($mot);
			$CTMStruct->Type($Type);
			$CTMStruct->Genre($Genre);

			@$Donnees[$NbLignes++]=$CTMStruct;
		}
	}
}


#struct GVALIGN =>
#{
#	Debut => '$',
#	GaussRatio => '$',
#	LogVrais => '$',
#	LogVraisTrame => '$',
#	Confiance => '$',
#	DAPcontraint => '$',
#	DAPnoncontraint => '$',
#};



sub ChargerSortieGVAlign
{
	my ($NomFichier, $Donnees)=@_;

	open (FICHIER, $NomFichier) or die "Impossible d'ouvrir $NomFichier !\n";

	my $CurrentCTM=0;
	my $NbMots=0;

	foreach my $Ligne (<FICHIER>)
	{

		if ($Ligne=~/Decoding .*? \[(.*?),.*?\].*?\[Gauss Ratio : (.*?) .*/)
		{
			$CurrentCTM=GVALIGN->new();
			$CurrentCTM->Debut($1);
			$CurrentCTM->GaussRatio($2);
		}
		elsif ($CurrentCTM != 0 && $Ligne=~/\tLogLikelihood: (.*?)\tLogLikelihood\/Frame: (.*?) .*?\[(.*?)\] \((.*?),(.*?)\)/)
		{
			$CurrentCTM->LogVrais($1);
			$CurrentCTM->LogVraisTrame($2);
			$CurrentCTM->Confiance($3);
			$CurrentCTM->DAPcontraint($4);
			$CurrentCTM->DAPnoncontraint($5);

			@$Donnees[$NbMots++]=$CurrentCTM;

			$CurrentCTM=0;
		}
	}
}

sub ChargerMLCLASS
{
	my ($NomFichier, $Donnees)=@_;

	open (FICHIER, $NomFichier) or die "Impossible d'ouvrir $NomFichier !\n";

	my $NbMots=0;

	foreach my $Ligne (<FICHIER>)
	{
		if ($Ligne=~/p\( (.*?) \| (.*?) .*?\).*?=.*?\[(.*?)\] .*? \[ (.*?) \]/)
		{
			my $MLStruct = MLCLASS->new();
			my $Mot=$1;
			my $Prob=$4;
			my $MotP=$2;
			my $ngram=$3;

			$ngram=~s/gram//g;

			#print "$Mot $Prob $ngram \n";

			$MLStruct->Mot($Mot);
			$MLStruct->LMLogProb($Prob);
			$MLStruct->TypeNgram($ngram);

			$MLStruct->TypeNgramS(0);
			$MLStruct->TypeNgramS2(0);
			$MLStruct->LMLogProbS(0);
			$MLStruct->MotS(0);

			if ($NbMots > 1)
			{
				@$Donnees[$NbMots-2]->TypeNgramS2($ngram);
				$MLStruct->TypeNgramP0(@$Donnees[$NbMots-2]->TypeNgram);
			}
			else
			{
				 $MLStruct->TypeNgramP0(0);
			}	

			if ($NbMots > 0)
			{
				@$Donnees[$NbMots-1]->TypeNgramS($ngram);
				@$Donnees[$NbMots-1]->LMLogProbS($Prob);
				@$Donnees[$NbMots-1]->MotS($Mot);

				$MLStruct->TypeNgramP(@$Donnees[$NbMots-1]->TypeNgram);
				$MLStruct->LMLogProbP(@$Donnees[$NbMots-1]->LMLogProb);
				$MLStruct->MotP(@$Donnees[$NbMots-1]->Mot);
			}
			else
			{
				$MLStruct->TypeNgramP(0);
				$MLStruct->LMLogProbP(0);
				$MLStruct->MotP(0);
			}
			@$Donnees[$NbMots++]=$MLStruct;
		}
	}
}

