# fonction de calcul de la frame BESOIN de la longueur de la sequence
function frameCompute(strand,begin,end,Lseq)
{

	if ( strand ~ /D/ )
	{
		frame = "+"  (((begin -1) % 3 ) + 1 );
	}
	else 
	{
		frame = "-" (((Lseq - end) % 3 ) + 1 );
	}
	return(frame) ;
}



# fonction qui teste si les begin et end sont bien des caracteres numeriques
function testCds(cds)
{
	if ( cds["begin"] !~ /[0-9]+/ || cds["end"] !~ /[0-9]+/ )
	{
		return(0) ;
	} 
	else
	{
		return(1);
	}
	
}
# fonction qui imprime a l'ecran une CDS simple (sans fragments, sans frameshits)
function printCds(cds)
{
	if ( testCds(cds) != 1 )
	{
		print "!error with " cds["label"] " cds " ;
	}
	else 
	{ 
			if (Lseq) 
			{
				frame = 0 ;
				frame = frameCompute(cds["strand"],cds["begin"],cds["end"],Lseq);
			}
		gsub("$","",cds["product"]);
		gsub(" ","_",cds["label"]);
		gsub(/_\{.*\}/,"",cds["label"]);
		print cds["begin"] " " cds["label"] SEP cds["begin"] SEP cds["begin"] SEP cds["end"] SEP (cds["end"] - cds["begin"]) SEP (cds["end"] - cds["begin"]) SEP "NULL" SEP "NULL" SEP frame SEP cds["strand"] SEP "NULL" SEP cds["product"] ;
	}
	return(1) ;
}

# fonction qui imprime a l'ecran les cds contenant des frameshits
function printFsCds(cds)
{
	if ( testCds(cds) != 1 )
	{
		print "!error with " cds["label"] " cds " ;
	}
	else 
	{ 
			if (Lseq) 
			{
				frame = 0 ;
				frame = frameCompute(cds["strand"],cds["begin"],cds["end"],Lseq);
			}
		gsub("$","",cds["product"]);
		gsub(" ","_",cds["label"]);
		gsub(/_\{.*\}/,"",cds["label"]);
		print cds["begin"] " FRAG" cds["label"] SEP cds["begin"] SEP cds["begin"] SEP cds["end"] SEP (cds["end"] - cds["begin"]) SEP (cds["end"] - cds["begin"]) SEP "NULL" SEP "NULL" SEP frame SEP cds["strand"] SEP "NULL" SEP cds["product"] ;
	}
	return(1) ;
}

# fonction qui imprime a l'ecran les gene contenant des frameshifts
function printFsGene(gene)
{
	i=0;
	while (tab[i])
	{
		if (Lseq) 
		{
			frame = 0 ;
			frame = frameCompute(tab["strand"],tab["begin"],tab["end"],Lseq);
		}
		gsub("$","",gene["product"]);
		gsub(" ","_",gene["label"]);
		gsub(/_\{.*\}/,"",gene["label"]);
	
		
		print  tab[i] " FRAG" gene["label"] SEP tab[i] SEP tab[i] SEP tab[i+1] SEP (tab[i+1] - tab[i]) SEP (tab[i+1] - tab[i]) SEP "NULL" SEP "NULL" SEP frame SEP gene["strand"] SEP "NULL" SEP gene["product"] ;
		i +=2;
	}
	return(1);
}
# fonction qui imprime les gene simples
function printGene(gene)
{
	if (Lseq) 
	{
		frame = 0 ;
		frame = frameCompute(gene["strand"],gene["begin"],gene["end"],Lseq);
	}
	gsub("$","",gene["product"]);
	gsub(" ","_",gene["label"]);
	gsub(/_\{.*\}/,"",gene["label"]);
	print gene["begin"] " " gene["label"] SEP gene["begin"] SEP gene["begin"] SEP gene["end"] SEP (gene["end"] - gene["begin"]) SEP (gene["end"] - gene["begin"]) SEP "NULL" SEP "NULL" SEP frame SEP gene["strand"] SEP "NULL" SEP gene["product"] ;
	return(1) ;
}

# fonction qui imprime a l'ecran les cds fragmentees
function printFcds(tab,cds)
{	
	i = 0 ;
	gsub("$","",cds["product"]);
	while (tab[i])
	{	
		if (Lseq)
		{
			frame = frameCompute(cds["strand"],tab[i],tab[i+1],Lseq);
		}
		gsub(" ","_",cds["label"]);
		gsub(/_\{.*\}/,"",cds["label"]);
		print	tab[i] " " "FRAG" cds["label"] SEP tab[i] SEP tab[i] SEP tab[i+1] SEP (tab[i+1] - tab[i] ) SEP (tab[i+1] - tab[i] ) SEP "NULL" SEP "NULL" SEP frame SEP cds["strand"] SEP "NULL" SEP cds["product"] ;
		i += 2 ;
	}
	return(1) ;
}

# fonction d'initialisation du tableau tab (qui contient les bornes des cds fragmentees)
function initTab(tab)
{
	i = 0 ;
	while (tab[i])
	{
		tab[i] = "" ;
		i++ ;
	}
#	return(tab)  ;
}

# fonction qui initialise le tableau cds (qui contient les infos pour une cds)
function initCds(cds) 
{
	cds["label"] = "NULL" ;
	cds["begin"]  = "NULL" ;
	cds["end"] = "NULL" ;
	cds["strand"] = "NULL" ;
	cds["frame"] = "NULL" ;
	cds["product"] = "NULL" ;
	cds["table_codon"] = "NULL" ;
	cds["type"] = "NULL";

	#return(cds) ;
}

# fonction qui initialise le tableau gene (qui contient les infos pour un gene)
function initGene(gene)
{
	gene["label"] = "NULL" ;
	gene["begin"]  = "NULL" ;
	gene["end"] = "NULL" ;
	gene["strand"] = "NULL" ;
	gene["frame"] = "NULL" ;
	gene["product"] = "NULL" ;
	gene["table_codon"] = "NULL" ;
	gene["type"] = "NULL";
	gene["frag"] = "NULL";
	
}


# initialisation des variables du script
BEGIN {
	SEP ="$" ; # separateur finale
	nbcds = 0 ; # nombre de cds
	isCds = 0 ; # booleen de presence oui ou non d'une cds
	isGene = 0 ; # booleen de presence oui ou non d'un gene
	isProduct = 0; # booleen de presence oui ou non d'une feature product
	initGene(gene); # initialise le tableau gene
	initCds(cds) ; # initialise le tableau cds
	nbCdsFollowed = 0 ; # variable qui comptabilise le nombre de cds consecutives
	nbGeneFollowed = 0 ; # variable qui comptabilise le nombre de gene consecutifs
	lastGene = "" ;
	lastCds = "" ;
}

{
	
	if (($0 ~ /^FT   [a-zA-Z]/ || $0 ~ /^SQ/) ) # condition d'arret (nouvelle feature ou arrive a la sequence 
	{ 
		if (cds["label"] ~ /NULL/  && isCds == 1 ) # dans le cas ou une cds n'a pas de label
		{
			 cds["label"] = sprintf("%04d",nbcds) ; # on donne comme label le numero de cds
		}
		if (isCds == 1 && isGene == 0 && cds["label"] ~ lastCds)
		{
			gsub("$"," ",cds["product"]);
			if ( cds["type"] ~ /frag/ ) # cas d'une cds de type fragmentee
			{
				printFcds(tab,cds) ;
				initCds(cds) ;
				initGene(gene);
				initTab(tab);
			}
			else
			{      
				if ( cds["type"] ~ /fs/ ) # cas d'une cds contenant un frameshift (/pseudo)
				{
					printFsCds(cds) ;
				}
				else
				{
					printCds(cds) ;
				}
				# vu que cds et gene sont les memes objets genomiques, initialisation des 2 objets
				initCds(cds) ;
			}
			isCds = 0 ;
			nbCdsFollowed = 0 ;
		}
		if ( isCds == 1 && isGene == 1 ) # cas ou on a une cds et un gene consecutifs
		{
				if ( cds["label"] ~ /^[0-9]*$/ )
                                {
                                        cds["label"] = gene["label"];
                                }
				lastGene = gene["label"] ;
				lastCds = cds["label"] ;
				#print "LABEL: " cds["label"] " : " cds["begin"] " ; " gene["label"] " : " gene["begin"] ;
				#print "CONSECUTIFS : " nbCdsFollowed " : " nbGeneFollowed ;
			# comparaison des stops biologiques
			if ( ( (cds["strand"] == "R" &&  cds["begin"] == gene["begin"] ) || (cds["strand"] == "R" && tab[0] == gene["begin"] ) ) || ( (cds["strand"] == "D" && cds["end"] == gene["end"] ) || ( cds["strand"] == "D" && tab[j] == gene["end"] ) ))
			{
				gsub("$"," ",cds["product"]);
				if ( cds["type"] ~ /frag/ ) # cas d'une cds de type fragmentee 
				{
					printFcds(tab,cds) ;
					initCds(cds) ;
					initGene(gene);
					initTab(tab);
				}
				else 
				{	
					if ( cds["type"] ~ /fs/ ) # cas d'une cds contenant un frameshift (/pseudo)
					{
						printFsCds(cds) ;
					}
					else 
					{
						printCds(cds) ;
					}
					# vu que cds et gene sont les memes objets genomiques, initialisation des 2 objets
					initCds(cds) ;
					initGene(gene);
				}
			}
			else 
			{
				# cas ou les gene et cds ne sont pas les memes objets genomiques
				if (gene["label"] !~ /tRNA|23S|5S|16S/) # test pour voir si gene n'est pas un rRNA ou tRNA
				{
					if ( gene["frag"] ~ /fs/) # cas d'une cds contenant un frameshift (/pseudo)
					{
						 printFsGene(gene);
					}
					else 
					{
						printGene(gene);
					}
				}
				if ( cds["type"] ~ /frag/ ) # cas d'une cds de type fragmentee
	                        {
                	                printFcds(tab,cds) ;
        	                        initCds(cds) ;
                      	       		initGene(gene);
                       	        	initTab(tab);
                       		 }
                    	 	 else
                      		{   
                            		if ( cds["type"] ~ /fs/ ) # cas d'une cds contenant un frameshift (/pseudo)
                               		{
                                        	printFsCds(cds) ;
                                	}
                                	else
                                	{
                                      	  printCds(cds) ;
                                	}
                        	}

			}
                        initCds(cds) ;
                        initGene(gene);
			isCds = 0 ;
			isGene = 0 ;
			nbGeneFollowed = 0 ;
			nbCdsFollowed = 0 ;
		}
	}
	if ($0 ~ /^FT   gene/) 
	{
		if ( nbGeneFollowed == 1 ) # cas ou l'on a deux genes consecutifs donc differents objets genomiques
		{
			if (gene["label"] !~ /tRNA|23S|5S|16S/)
			{
				if ( gene["frag"] ~ /fs/)
				{
					 printFsGene(gene);
				}
				else 
				{
					printGene(gene);
				}
			}
                        initGene(gene);
			isGene = 0 ;
			nbGeneFollowed = 0 ;
				
		}
		if ( isCds==1)
		{
			gsub("$"," ",cds["product"]);
                        gsub(" ","_",cds["label"]);
                        if ( cds["type"] ~ /frag/ )
                        {
                                printFcds(tab,cds) ;
                                initCds(cds) ;
                                initTab(tab);
                        }
                        else
                        {
                                if ( cds["type"] ~ /fs/ )
                                {
                                        printFsCds(cds) ;
                                }
                                else
                                {
                                        printCds(cds) ;
                                }
                                initCds(cds) ;
                        }
                        nbCdsFollowed = 0 ;
                        isCds = 0 ;	
		}
		#print "GENELOCATION  : " $0 ;
		isGene = 1 ;
		if ($0 ~ /complement/ )
		{
			gene["strand"] = "R" ;
		}
		else 
		{
			gene["strand"] = "D" ;
		}
		if ($0 ~ /join/ || $0 ~ /\.\..*\.\./ )
		{
			gene["frag"] = "fs" ;
			location = $0 ;
			gsub("[a-zA-Z() ><]","",location) ;
			gsub(/(\.\.|,)/,"$",location); 
			i = 1 ;
			j = 0 ;
			split(location,a,"$") ;
			while (a[i])
			{
				tab[j] = a[i] ;
				tab[j+1] = a[i+1] ;
				i += 2  ;  j += 2 ; 
			}
		}
		else 
		{
			location = $0 ;
			gsub("[a-zA-Z() ><]","",location) ;
			split(location,a,".") ;
			gene["begin"] = a[1] ;	
			gene["end"] = a[3] ;
		}
		#print "begin:" gene["begin"] "|end:" gene["end"] ;
		gene["type"] = "gene";
		nbGeneFollowed ++ ;

	}
	if ($0 ~ /^FT   CDS/) 
	{
		if ( nbCdsFollowed == 1 ) # cas ou l'on a deux cds consecutives donc differents objets genomiques
		{
			gsub("$"," ",cds["product"]);
			if ( cds["type"] ~ /frag/ )
			{
				printFcds(tab,cds) ;
				initCds(cds) ;
				initTab(tab);
			}
			else 
			{	
				if ( cds["type"] ~ /fs/ )
				{
					printFsCds(cds) ;
				}
				else 
				{
					printCds(cds) ;
				}
				initCds(cds) ;
			}
			nbCdsFollowed = 0 ;
			isCds = 0 ;
			
		}
		#print "CDSLOCATION: " $0 ;
		nbcds++; 	
		isCds = 1 ;
		if ($0 ~ /complement/ ) 
		{
			cds["strand"] = "R" ;
		}
		else 
		{
			cds["strand"] = "D" ;
		}
		if ($0 ~ /join/ || $0 ~ /\.\..*\.\./ ) 
		{
			cds["type"] = "frag" ;
			location = $0 ;
			gsub("[a-zA-Z() ><]","",location) ;
			gsub(/(\.\.|,)/,"$",location);
			i = 1 ;
			j = 0 ;
			split(location,a,"$") ;
			while (a[i]) 
			{
				tab[j] = a[i] ;
				tab[j+1] = a[i+1] ; 
				i += 2  ;
				j += 2 ;
			}	
			while ( getline && $0 !~ /^FT                   \//)
                        {
                                location = $0 ;
                                gsub("[a-zA-Z() ><]","",location) ;
                                gsub(/(\.\.|,)/,"$",location);
                                i = 1 ;
                                split(location,a,"$") ;
                                while (a[i])
                                {
                                        tab[j] = a[i] ;
                                        tab[j+1] = a[i+1] ;
                                        i += 2  ;
                                        j += 2 ;
                                }
				cds["type"] = "frag" ;
                        }
		}
		else 
		{
			cds["type"] = "cds" ;
			location = $0 ;
			gsub("[a-zA-Z() ><]","",location) ;
			split(location,a,".") ;
			cds["begin"] = a[1] ;	
			cds["end"] = a[3] ;
		}
		nbCdsFollowed++;
	}
	if ($0 ~ /\/product=\"/ && ( isCds == 1  || isGene == 1) )
	{
		if ( isCds == 1 )
		{
			split($0,a,"\"");
			if ( cds["product"] ~ /NULL/ ) # ce test pour gerer les exceptions de mots dans le /note
			{	
				cds["product"] = a[2] ;
			}
			else 	
			{
				cds["product"] =  cds["product"] ", "  a[2] ;
			}
			isProduct  = 1 ;
			if ( cds["product"] ~ /pseudogene/ )
                        {
                                if (cds["type"] !~ /frag/ )
                                {
                                        cds["type"] = "fs";
                                }
                        }
		}
		else
		{
			split($0,a,"\"");
			if ( gene["product"] ~ /NULL/ )
			{
				gene["product"] = a[2] ;
			}	
			else 
			{
				gene["product"] =  gene["product"] ", "  a[2] ;
			}
			isProduct  = 1 ;
			if ( gene["product"] ~ /pseudogene/ )
                        {
                                gene["frag"] = "fs" ;
                        }
		}
	} 
	if ( isProduct == 1 )
	{
		if ($0 !~ /\/product/)
		{
			if ($0 !~ /^FT                   \// && $0 !~ /^FT   [a-zA-Z]/) 
			{
				split($0,a,"\"");
				gsub(/FT                   /,"",a[1]) ;
				if ( isCds == 1) 
				{
					cds["product"] = cds["product"] " "  a[1] ;
					if ( cds["product"] ~ /pseudogene/ )
                       			{
                            			if (cds["type"] !~ /frag/ )
                                		{
                                        		cds["type"] = "fs";
                                		}
                        		}
				}
				else {
					gene["product"] = gene["product"] " "  a[1] ;
					if ( gene["product"] ~ /pseudogene/ )
                       			{
                            		    gene["frag"] = "fs" ;
                        		}
				}
			}
			else 
			{
				isProduct = 0 ;
			}
		}
	}
	if ( $0 ~ /\/pseudo/ && ( isCds == 1 || isGene == 1) )
	{
		if ( isCds == 1 )
		{
			if (cds["type"] !~ /frag/ )
			{
				cds["type"] = "fs"; 
			}
		}
		else
		{
			gene["frag"] = "fs";
		}
	}
	
	if ( $0 ~ /\/note/ && ( isCds == 1 || isGene == 1) )
	{
		
		if ( $0 ~ /\"$/ ) # cas ou le note tient sur une seule ligne 
		{
			
			if ( $0 ~ /frame shift|frameshift|internal stop|sequencing artifact|pseudogene/)
			{
				if ( isCds == 1 )
				{
					if (cds["type"] !~ /frag/ )
					{
						cds["type"] = "fs";
					}
				}
				else
				{
					 gene["frag"] = "fs";
				}
			}
		}
		else 
		{	
			while ( $0 !~ /\"|^FT                     \/|^FT     [a-zA-Z]|\"$/)
			{
				# mots qui predisent un  frameshift
				if ( $0 ~ /frame shift|frameshift|internal stop|sequencing artifact|pseudogene/)
				{
					if ( isCds == 1 )
					{
						if (cds["type"] !~ /frag/ )
						{
							cds["type"] = "fs";
						}
					}
					else
					{
						 gene["frag"] = "fs";
					}
				}
				if ( tolower($0) ~ /selenoprotein|selenocysteine/ )
				{
					if (isCds == 1 ) 	
					{
						if ( cds["product"] !~ /NULL|selenocysteine/ )
						{
							cds["product"] = cds["product"] " (selenocysteine)" ;
							cds["type"] = "fs";
						}	
						else 
						{
							cds["product"] = "(selenocysteine)" ;
							cds["type"] = "fs";
						}
						
					}
					else 
					{
						if ( gene["product"] !~ /NULL|selenocysteine/ )
						{
							gene["product"] = gene["product"] " (selenocysteine)" ;
						 	gene["frag"] = "fs";
						}
						else 
						{
							gene["product"] = "(selenocysteine)" ;
						 	gene["frag"] = "fs";
						}
					}
				}
				getline;
			}
		}
	}
	
	if ($0 ~ /\/transl_table/ )
	{
		
		tmp = $0;
		split(tmp,t,"/transl_table=");
		translateCode = t[2] ;
		if ( translateCode != 11 )
		{
			if ( codonUsage == 0 )
			{
				print translateCode > "translTable.txt";
				codonUsage = 1 ;
			}
		}	
	}

	if ($0 ~ /\/locus_tag=\"/ && ( isCds == 1 || isGene == 1) )
	{
		tmp = $0 ;
		gsub(/\(|\)/,"",tmp);
		split(tmp,a,"\"");
		if ( cds["label"] ~ /NULL/ && isCds == 1 )
		{
			cds["label"] =  a[2] ;
		}
		else
		{
			gene["label"] =  a[2] ;
		}
	}
	else 
	{
		if ($0 ~ /\/label=\"/ && ( isCds == 1  || isGene == 1) )
		{
			tmp = $0 ;
			gsub(/\(|\)/,"",tmp);
			split(tmp,a,"\"");
			if ( cds["label"] ~ /NULL/ && isCds == 1 )
			{
				cds["label"] =  a[2] ;
			}
			else 
			{
				gene["label"] =  a[2] ;
			}
		}
		else
		{
			if ($0 ~ /\/gene=\"/&& ( isCds == 1 || isGene == 1) )
			{
			#	print "GENE: " $0 ;
				tmp = $0 ;
				gsub(/\(|\)/,"",tmp);
			#	print "TMP :" tmp ;
				split(tmp,a,"\"");
				if (  cds["label"] ~ /NULL/ && isCds == 1 )
                        	{
					cds["label"] =  a[2] ;
		#			print "CDSLABEL  = "  cds["label"] ;
				}		
				else 
				{
					gene["label"] =  a[2] ;
		#			print "GENELABEL = " gene["label"] ; 
				}
			}
		}
		gsub("'","",cds["label"]) ;
		gsub("'","",gene["label"]) ;
	}
}

END {
	#print "nombre de cds : " nbcds ;
}

