#! /usr/bin/perl -w
# ce script a pour but de comparer les  CDS issues des banques avec celles predites par AMIGA
# Si les CDS des banques et les CDS predites par AMIGA ont le meme STOP BIOLOGIQUES 
# , elles sont mises dans un fichier commun, apres comparaison des Starts.
# Elles seront alors separees en quatres categories :
# => IDENTICAL_START, si Amiga_Start == Begin_bank
# => START_IN_RANGE, si Most_left_start <= Begin_bank < Amiga_Start
# => OUT_OF_RANGE_FARTHER, Begin_bank < Most_left_start
# => OUT_OF_RANGE_CLOSER, si Amiga_Start < Begin_bank <= Stop_Amiga



#-- Declaration des variables qui vont etre utilisees --#
my $AmigaFile; #-- nom du fichier --#
my $BankFile;	
my @AmigaStruct;
my @BankStruct;
#-- END --#


#-- Gestion des arguments --#
#print "nombre d'argument = ".$#ARGV."\n";
if ( $#ARGV > 2 || $#ARGV < 1)  {
	print "Current Number of args : ".$#ARGV."\n";
	print "\nUsage:\t $0 <file_Amiga_results> <bank_file>\n";
	exit 1;
}
else {
	$AmigaFile = $ARGV[0];
	$BankFile = $ARGV[1] ;
}
#-- END --#


#-- chargement des valeurs du fichier de sortie d'Amiga dans la structure @AmigaStruct --#
print STDERR "... Loading data from Amiga file : ".$AmigaFile."\n";
@AmigaStruct = getInfoFromAmigaFile(\$AmigaFile);
#-- END --#
print STDERR "... Loading data from the Bank file : ".$BankFile."\n";
@BankStruct = getInfoFromBankFile(\$BankFile);

#-- creation du filtre pour les frameshifts des annotations (cad avec un FRAG dans le label) --#
print STDERR "... Annotated FS creation\n";
@fs= getFs(\@BankStruct);
#&printStruct(\@fs);





#-- debbugage --#
#print "AMIGA STRUCT\n";
#&printStruct (\@AmigaStruct);
#print "BANK STRUCT\n";
#&printStruct (\@BankStruct);




#&printStruct(\@caCds;
print STDERR "... Comparison between AMIGA and BANK structures\n";
if (compaStruct(\@AmigaStruct,\@BankStruct,\@fs) == 0) {
	printf STDERR "erreur dans la comparaison des structures\n";
	exit(0);
}













#-- FONCTIONS DU PROGRAMME --#
sub uniqBank {
	local (*Bank) = @_;
	my $f;
	my $status = "UNIQUE_USER";
	for $f (@Bank) 
	{
	 if ($f->{"status"} eq "NULL" ) 
	 {
		if ($f->{"label"} =~ /^FRAG/)
		{
			$f->{"status"} = "NO STATUS" ;
			if (printResults(\%$f) == 0)
                        {
                                printf STDERR "erreur dans l'ecriture des resultats de la structure\n";
                                exit(0);
                        }
		}
		elsif ($f->{"label"} =~ /trna|rrna|tRNA|rRNA/ || $f->{"product"} =~ /putative/  ) 
		{
				$f->{"status"} = "NO STATUS" ;
				if (printResults(\%$f) == 0) 
				{
					printf STDERR "erreur dans l'ecriture des resultats de la structure\n";
					exit(0);
				}	
			}
		elsif ($f->{"Lpcod"} && $f->{"Lpcod"} <= 0.2  && $f->{"product"} =~ /hypothetical|predicted/ ) 
		{
				$f->{"status"} = $status ;
				if (printResults(\%$f) == 0) 
				{
					printf STDERR "erreur dans l'ecriture des resultats de la structure\n";
					exit(0);
				}	
			}
		elsif ($f->{"Lpcod"} && $f->{"Lpcod"} <= 0.2 && $f->{"product"} =~ /NULL/)
		{
			$f->{"status"} = $status ;
                        if (printResults(\%$f) == 0)
                        {
                                printf STDERR "erreur dans l'ecriture des resultats de la structure\n";
                                exit(0);
                        }

		}
		else 
		{
			$f->{"status"} = "NO STATUS" ;
			if (printResults(\%$f) == 0) 
			{	
				printf STDERR "erreur dans l'ecriture des resultats de la structure\n";
				exit(0);
			}
		}
	 }
	}	
	return 1;
}	


sub printResults {
	local (*s) = @_;
	
	if ($s{"frame"} ne "NULL" &&  $s{"frame"} > 0 )
	{
		print $s{"begin"}." ".$s{"label"}."\$".$s{"begin"}."\$".$s{"start"}."\$".$s{"end"}."\$".($s{"end"} - $s{"begin"}+1)."\$".($s{"end"} - $s{"start"}+1)."\$".$s{"Lpcod"}."\$".$s{"Apcod"}."\$".$s{"frame"}."\$".$s{"strand"}."\$".$s{"CUmatrix"}."\$".$s{"product"}."\$".$s{"status"}."\n"; 	
	}
	else 
	{
		print $s{"begin"}." ".$s{"label"}."\$".$s{"begin"}."\$".$s{"start"}."\$".$s{"end"}."\$".($s{"start"} - $s{"begin"}+1)."\$".($s{"end"} - $s{"begin"} +1)."\$".$s{"Apcod"}."\$".$s{"Lpcod"}."\$".$s{"frame"}."\$".$s{"strand"}."\$".$s{"CUmatrix"}."\$".$s{"product"}."\$".$s{"status"}."\n"; 	
	}
	
	return 1;
	
}

sub compaStruct {
	local (*am,*bank,*fs) = @_;
	my $Am;
	my $Bank;
	my $find = 0;
	my $status;
	my $BankStatus;

	for $Am (@am) {
		STOP: for $Bank (@bank) {
			if (!$Am->{"frame"} || !$Bank->{"frame"})
			{
				print STDERR "Error : Missing strand \n";
			}
			if ( bondariesTest(\%$Am,\%$Bank) == 1 && inFsAnnotated(\%$Am,\@fs) != 1 ) {
			#-- si les ends sont egaux et que meme strand alors update de la table CA du champs AM_id --#
				$find = 1;
				#-- cad que AM et CA sont communs -> update status a COMMON --#
				#-- cette ligne nous permettra de reperer les entrees uniques a compare_annot --#
				$Bank->{"amiga"} = $Am->{"label"} ;
				$Bank->{"status"} ="COMMON";
				$Bank->{"start"} = $Am->{"start"} ; # recuperation du start d'amigene
				if (printResults(\%$Bank) == 0) {
					printf STDERR "erreur dans l'ecriture des resultats de la structure\n";
					exit(0);
				}	
				last STOP;
			}	
				#-- END --#
		}
		#-- si $find ==0 alors c'est une entree unique a amiga --#
		if ( $find == 0 )  {
			#print "-- ".$Am->{"frame"}." ".$Am->{"begin"}." ".($Am->{"start"} - $Am->{"begin"} )." ".$Am->{"Apcod"}."\n";
			#print "-- ".$Am->{"frame"}." ".$Am->{"begin"}." ".($Am->{"end"} - $Am->{"start"} )." ".$Am->{"Apcod"}."\n";
			if (inFsAnnotated(\%$Am,\@fs) == 1) 
			{
				$Am->{"status"} ="NO STATUS AMIGene";
				if (printResults(\%$Am) == 0) {
                                        printf STDERR "erreur dans l'ecriture des resultats de la structure\n";
                                        exit(0);
                                }
			}
			elsif ( ($Am->{"frame"} > 0 && ($Am->{"end"} - $Am->{"start"} ) >= 300 && $Am->{"Apcod"} >= 0.5)  || ($Am->{"frame"} < 0 && ( $Am->{"start"} - $Am->{"begin"} ) >= 300 && $Am->{"Apcod"} >= 0.5) ) {
				$Am->{"status"} ="UNIQUE_AMIGene";
				#-- creation d'une nouvelle entree dans compare_annotation --#
				#-- update de CA status a UNIQUE_AMIGA --#
				#-- PRINT NOUVELLE ENTREE UNIQUE A AMIGENE --#
				if (printResults(\%$Am) == 0) {
					printf STDERR "erreur dans l'ecriture des resultats de la structure\n";
					exit(0);
				}	
			}
			else {
				$Am->{"status"} ="NO STATUS AMIGene";
				#-- creation d'une nouvelle entree dans compare_annotation --#
				#-- update de CA status a NO STATUS filtre sur la longueur --#
				#-- PRINT NOUVELLE ENTREE UNIQUE A AMIGENE --#
				if (printResults(\%$Am) == 0) {
					printf STDERR "erreur dans l'ecriture des resultats de la structure\n";
					exit(0);
				}
			}
		}
		#-- END --#
		else {
			$find = 0;
		}	
		$find = 0 ;
	}

	if (uniqBank(\@bank) == 0 ) {
		printf STDERR "erreur dans la recherche des uniques a COMPARE_ANNOT\n";
		exit(0);
	}	
	return 1;
}	

sub inFsAnnotated
{
	local (*am,*fs) = @_;
	my $element ;
	
	for $element (@fs)
	{
#		print $element->{"begin"}."..".$element->{"end"}."  ".$am{"label"}.":".$am{"begin"}."..".$am{"end"}."\n";
		if ( ($am{"end"} >= $element->{"begin"} && $am{"end"} < $element->{"end"}) || ($am{"begin"} >= $element->{"begin"} && $am{"begin"} < $element->{"end"}) || ($am{"begin"} < $element->{"begin"} &&  $am{"end"} >= $element->{"end"}) )
		{
			return 1;
		}
	}
	return 0;
}
sub bondariesTest 
{
	local (*am,*bnk) = @_ ;
	#print "BOUNDARIES AMIGA:".$am{"end"}." ".$am{"begin"}." ".$am{"strand"}." "." BANK:".$bnk{"end"}." ".$bnk{"begin"}." ".$bnk{"strand"}."\n";
	if ($am{"frame"} >0 && $bnk{"frame"} > 0  )
	{
		#print "BOUNDARIES  D AMIGA:".$am{"end"}." BANK:".$bnk{"end"}."\n";
		if (  ($am{"end"} == $bnk{"end"}) || (($am{"end"} + 12) > $bnk{"end"}  && ($am{"end"} - 12) < $bnk{"end"}) )
		{
		#		print "ok\n";
			return 1 ;
		}	
		else
		{
		#		print "NO\n";
			return 0 ; 
		}
	}
	elsif  ($am{"frame"} < 0 && $bnk{"frame"} < 0 )
	{
		#print "BOUNDARIES ".$am{"strand"}." ".$bnk{"strand"}."  AMIGA:".$am{"begin"}." BANK:".$bnk{"begin"}."\n";
		if ( ($am{"begin"} == $bnk{"begin"}) || (($am{"begin"} + 12) > $bnk{"begin"}  && ($am{"begin"} - 12) < $bnk{"begin"}))
		{
		#print "BOUNDARIES  R AMIGA:".$am{"begin"}." BANK:".$bnk{"begin"}."\n";
		#	print "ok\n";
			return 1 ;
		}	
		else
		{
		#	print "NO\n";
			return 0 ; 
		}
	}
	else
	{
		return 0;
	}
}
		


sub getInfoFromBankFile {
	local (*file) = @_;
	my @struct;
	my %hash;
	my @t;
	open(F,$file) or die "error : $!\n";
	while (<F>) {
		if (m/(.*)\n$/) {
			$line = $1;
			@t = split /\$/,$line;
			%hash = initBank(%hash) ;
			$hash{"label"} = $t[0] ;
			$hash{"begin"} = $t[1];
			$hash{"start"} = $t[2];
			$hash{"end"} = $t[3];
			$hash{"Lpcod"} = $t[6];
			$hash{"Apcod"} =$t[7] ;
			$hash{"strand"} = $t[9];
			$hash{"frame"} = $t[8];
			$hash{"CUmatrix"} = $t[10] ;
			$hash{"product"} = $t[11] ;
			#print $hash{"label"}." ".$hash{"begin"}." ".$hash{"end"}." ".$hash{"strand"}." ".$hash{"frame"}." ".$hash{"product"}. "\n";    
			push (@struct, {%hash});
		}	
	}
	close F;
	return (@struct);
}
#-- END --#


#-- fonction pour imprimer a l'ecran le contenu de structure de hashage --#
sub printStruct {
	local (*struct) = @_;
	my $i;
	my $field;
	for $i (@struct) {
		for $field (keys %$i) {
			if ($i->{$field})  {
				print "field:".$field.",value:".$i->{$field}."\n";
			}	
		}
		print "------------\n";
	}
}	
#-- END --#



#-- parsing du fichier file_amiga_results --#
sub getInfoFromAmigaFile {
	local (*file)  = @_;
	my %AmiTable ; #-- table de hash contenant les valeurs pour une table Amiga --#
	my @structAmi; #-- structure contenant les Valeurs pour la table Amiga --#
	my %amiga; #-- tableau de hash qui va contenir les informations sur chaque resultat d'amiga --#
	my $line;
	my @tab;
	my $i =0;
	my @amigaSeq;
	my %entrie;
	my $label = 0;
	my $query ;

	
	#$query = "SELECT "."O_species_code"." FROM Organism O, Replicon R, Sequence S WHERE S.".&getFn("S_id")." = ".$S_id." AND S.".&getFn("R_id")." = R.".&getFn("R_id")." AND R.".&getFn("O_id")." = O.".&getFn("O_id");
	#$r = &myQuery($DB,$query;
	#$Ocode = $r->fetchrow ;
	
	open (F,$file) or die "Error : $!\n";
	while (<F>) {
		if ( m/^>(.*)\n/ ) {
			#$label ++;
			
			$line = $1;
			@tab = split (/\s/,$line);
			
			%AmiTable = initAmiga(%AmiTable);
			
			#-- ici tab[0] est le label 
			#-- tab[1] est le Most_Left_start
			#-- tab[2] est le start amiga
			#-- tab[3] est le stop bio
			#-- tab[4] est 
			#-- tab[9] est le strand 
			
			#-- affectation des valeurs pour une table Amiga --#
			*AmiTable = setValuesAmiga (\%AmiTable,\@tab,\$i);
			#-- END --#
			#-- creation du label amiga avec le O_species_code + %04d forme --#
			#$AmiTable{"AM_label"} = $Ocode.sprintf("%04d",$label);
			#-- END --#
			#-- aJOut d'une nouvelle entree dans la table Amiga --#
			push (@structAmi , { %AmiTable});
			#-- END --#
			$i++;
		}
	}	
	close F;

	return (@structAmi);
	
}	
sub initAmiga {
	my (%amiTable) = @_ ;
	$amiTable{"label"} = "NULL";
	$amiTable{"begin"} = "NULL";
	$amiTable{"start"} = "NULL";
	$amiTable{"end"} = "NULL";
	$amiTable{"frame"} = "NULL";
	$amiTable{"strand"} =  "NULL";
	$amiTable{"CUmatrix"} = "NULL";
	$amiTable{"Lpcod"} =  "NULL";
	$amiTable{"Apcod"} = "NULL";
	$amiTable{"product"} = "NULL";
	$amiTable{"status"} = "NULL";
	
	return %amiTable;
}

sub initBank {
	my (%bankTable) = @_ ;
	$bankTable{"label"} = "NULL";
	$bankTable{"begin"} = "NULL";
	$bankTable{"start"} = "NULL";
	$bankTable{"end"} = "NULL";
	$bankTable{"frame"} = "NULL";
	$bankTable{"strand"} =  "NULL";
	$bankTable{"CUmatrix"} = "NULL";
	$bankTable{"Lpcod"} =  "NULL";
	$bankTable{"Apcod"} = "NULL";
	$bankTable{"product"} = "NULL";
	$bankTable{"amiga"} = "NULL"; # ligne permettant de connaitre le correspondant dans la table amiga #
	$bankTable{"status"} = "NULL";
	return %bankTable ;
}


sub setValuesAmiga {
	local (*AmiTable,*tab,*i) = @_;
	my $label ;

	$label = sprintf("%04d",$i);

	$AmiTable{"label"} = $tab[0];
	$AmiTable{"begin"} = $tab[1];
	$AmiTable{"start"} = $tab[2];
	$AmiTable{"end"} = $tab[3];
	$AmiTable{"frame"} = $tab[8];
	$AmiTable{"strand"} = $tab[9] ;
	$AmiTable{"CUmatrix"} = $tab[10];

	if ($AmiTable{"frame"} > 0 ) {
		$AmiTable{"Lpcod"} = $tab[6] ;
		$AmiTable{"Apcod"} = $tab[7];
	}
	else {
		$AmiTable{"Lpcod"} = $tab[7];
		$AmiTable{"Apcod"} = $tab[6];
	}
	
	return \%AmiTable;

}	
#-- END --#


sub getFs 
{
        local (*b) = @_ ;
        my @fs ; #-- tableau contenant les zones ou se trouvent les frameshifts --#
        my $lastFs = "" ;
        my $element;
        my $f ;
        my %h  ; 

        for $element (@b) 
        {
                if ($element->{"label"} =~ /^FRAG/) # reconnaissance du flag qui permet de reconnaitre les fs #
                {       
                        if ( $element->{"begin"} ne $lastFs || $element->{"product"} =~ /selenocysteine/ ) # si le fs en cours n'est pas deja dans le filtre #
                        { # on affecte toutes les valeurs utiles pour determiner les limites des fs
                                $h{"begin"} = $element->{"begin"};
                                $h{"end"} = $element->{"end"} ;
                                $h{"label"} =  $element->{"label"} ;
                                $lastFs = $element->{"begin"} ;
                                push(@fs,{%h}); 
                        }
                        else
                        {
                                # sinon on parcourt la structure contenant les infos sur les fs des annotations
                                # jusqu'a tomber sur la zone incriminee
                                for $f (@fs)
                                {
                                        if ($f->{"begin"} == $lastFs)
                                        {
                                                $f->{"end"} = $element->{"end"};
                                                last ;
                                        }
                                }
                        }
			
                }
        }
	#for $f (@fs) { for $k (keys %$f) { print $k .":". $f->{$k} ."\n"; } } 
        return (@fs);   
}
