#!/usr/bin/perl -w

use strict;

################################################
####                                        ####
####              EXON-fishing              ####
####                                        ####
#### AUTORES: Alba Diz i Anna Morancho      ####
####                                        ####
#### 17/03/2006   Universitat Pompeu Fabra  ####
################################################



# Variables que entrem: #
# ARGV 0. nom del fitxer fasta
# ARGV 1. matriu dels llocs d'splicing donadors
# ARGV 2. matriu dels llocs d'splicing acceptors
# ARGV 3. valor llindar pels llocs d'splicing
# ARGV 4. taula d'us de codons
# ARGV 5. llindar de puntuacio pels exons

# comprovem que s'han introduït tots els parametres

if (scalar(@ARGV) != 6) {
    print "Error en l'entrada de dades. Introdueixi: \n\tSequencia en format FASTA \n\tMatriu dels llocs d'splicing donador \n\tMatriu dels llocs d'splicing acceptors \n\tValor llindar pels llocs d'splicing \n\tTaula d'ús de codons \n\tLlindar de puntuació pels exons \n";
    exit;
}


####################################
###  Declaracio de les variables:###
####################################

my $nomfitxer = $ARGV[0];		 
my $acceptor = $ARGV[1];		
my $donor = $ARGV[2];		
my $llindar_sp = $ARGV[3];			 
my $codons = $ARGV[4];				
my $llindar_ex = $ARGV[5];


my $id;               # identificador de la seq
my $seq;              # conte tota la seq seguida
my @seqfa;            # vector de la seq (a cada component un nt)
my %matriu_acceptor;  #conte la matriu de puntuacions pels llocs acceptors d'splicing
my %matriu_donor;     #conte la matriu de puntuacions pels llocs donadors d'splicing
my %us_codons;        #conte la taula d'us de codons	


#############################################
### Enregistrament dels fitxers d'entrada ###
#############################################

# FITXER FASTA #

if (!open(FASTA,"<$nomfitxer")) {	# Comprovem que el fitxer FASTA es pot obrir
    print "Error: No es pot obrir el fitxer FASTA $nomfitxer";
    exit;
}

$id = ;  # llegim primera linia del format FASTA ">XXXX"

if ($id =~ m/\>(\w+)/){
    $id = $1;
}

else {
    print "cal que el fitxer estigui en format FASTA\n";
}


my @seql = ;  # llegim les linies de la sequencia
$seq  = "";          # declarem una variable on anira a para tota la sequencia seguida, i la inicialitzem amb la paraula buida


my $i = 0;
while ($i < scalar(@seql)) {
    chomp($seql[$i]);
    $seql[$i] =~ s/\W//;
    $seq = $seq . $seql[$i];
    $i = $i + 1;
}

$seq = uc($seq);     # passem totes les bases a majuscules

@seqfa = split(//,$seq); # posem la sequencia en un vector



# MATRIU D'ACCEPTORS I DONADORS #

%matriu_acceptor = HASH($acceptor);
%matriu_donor = HASH($donor);


# TAULA D'US DELS CODONS #


if (!open(PROPCODONS,"< $codons")) {
    print "Error: No es pot obrir el fitxer de la taula d'ús de codons $codons\n";
    exit(1);
}

# llegim les proporcions de codons del fitxer i les enregistrem al hash %us_codons;

while () {

    # a la variable anonima tenim la linia llegida i l'encaixem amb la seguent expressio regular

    m/(\w+) (\d+\.\d+)/;

    # l'expressio regular anterior encaixa amb dues paraules la primera de les quals es alfabetica i la segona un numero amb decimals.
    # les dues paraules estan agrupades amb parentesis el que significa que ens podem referir a la primera com $1 i a la segona com $2

    $us_codons{$1}=$2;

}

close(PROPCODONS);


###################################################
### Creem un vector per a cada pauta de lectura ###
###################################################

# declarem les variables

my $seq0 = $seq;
my $seq1 = substr ($seq, 1);  # contindra la seq a partir del segon nt
my $seq2 = substr ($seq, 2);  # contindra la seq a partir del tercer nt


# creem un vector que contrindra la seq en codons

my @seqco0 = ($seq0 =~ m/.../g); # pauta 0
my @seqco1 = ($seq1 =~ m/.../g); # pauta 1
my @seqco2 = ($seq2 =~ m/.../g); # pauta 2


############################################################
### Identificar codons d'stop i crear matriu amb els ORF ###
############################################################

my @ORFvec0 = ORFVEC(\@seqco0,0);
my @ORFvec1 = ORFVEC(\@seqco1,1);
my @ORFvec2 = ORFVEC(\@seqco2,2);


my @stop0 = STOP_CODONSvec(\@seqco0,0);
my @stop1 = STOP_CODONSvec(\@seqco1,1);
my @stop2 = STOP_CODONSvec(\@seqco2,2);
 

#################################################
### Trobar els possibles senyals d'splicing i ###
### seleccionar  els que superin el llindar   ###
#################################################

my @taula_acceptors = SPLICING(\%matriu_acceptor, \@seqfa, $llindar_sp);

my @taula_donors = SPLICING(\%matriu_donor, \@seqfa, $llindar_sp);


##################################################################
### Identificar codons ATG i crear un vector amb les posicions ###
##################################################################

my @ATG0 = ATG_CODONS(\@seqco0,0);
my @ATG1 = ATG_CODONS(\@seqco1,1);
my @ATG2 = ATG_CODONS(\@seqco2,2);

##################################################################
### Combinar les dades per a buscar els diferents exons ##########
##################################################################

### Combinarem les dades per als 3 frames

## 0 

my @exons_interns0 = FISHING(\@ORFvec0, \@taula_acceptors, \@taula_donors, "internal");
my @exons_inici0 =  FISHING(\@ORFvec0, \@ATG0, \@taula_donors, "firstATG");
my @exons_terminals0 = FISHING(\@ORFvec0, \@taula_acceptors, \@stop0, "terminal");
my @exons_individuals0 = FISHING(\@ORFvec0, \@ATG0, \@stop0, "_single_");

## 1 

my @exons_interns1 = FISHING(\@ORFvec1, \@taula_acceptors, \@taula_donors, "internal");
my @exons_inici1 =  FISHING(\@ORFvec1, \@ATG1, \@taula_donors, "firstATG");
my @exons_terminals1 = FISHING(\@ORFvec1, \@taula_acceptors, \@stop1, "terminal");
my @exons_individuals1 = FISHING(\@ORFvec1, \@ATG1, \@stop1, "_single_");

## 2 

my @exons_interns2 = FISHING(\@ORFvec2, \@taula_acceptors, \@taula_donors, "internal");
my @exons_inici2 =  FISHING(\@ORFvec2, \@ATG2, \@taula_donors, "firstATG");
my @exons_terminals2 = FISHING(\@ORFvec2, \@taula_acceptors, \@stop2, "terminal");
my @exons_individuals2 = FISHING(\@ORFvec2, \@ATG2, \@stop2, "_single_");


######################################################################
### Calculem el codon bias per tots els exons putatius i nomes ens ###
### quedem amb aquells la puntuació del quals supera el llindar    ###
###        establert a la entrada de dades del programa            ###
######################################################################

## 0 

my @defex_interns0 = CODON_BIAS(\@exons_interns0, 0, \%us_codons, $llindar_ex, \@seqfa);
my @defex_inici0 =  CODON_BIAS(\@exons_inici0, 0, \%us_codons, $llindar_ex,\@seqfa);
my @defex_terminals0 =  CODON_BIAS(\@exons_terminals0, 0, \%us_codons, $llindar_ex, \@seqfa);
my @defex_individuals0 =  CODON_BIAS(\@exons_individuals0, 0, \%us_codons, $llindar_ex, \@seqfa);

## 1 

my @defex_interns1 = CODON_BIAS(\@exons_interns1, 1, \%us_codons, $llindar_ex,\@seqfa);
my @defex_inici1 =  CODON_BIAS(\@exons_inici1,  1, \%us_codons, $llindar_ex,\@seqfa);
my @defex_terminals1 =  CODON_BIAS(\@exons_terminals1,  1, \%us_codons, $llindar_ex,\@seqfa);
my @defex_individuals1 =  CODON_BIAS(\@exons_individuals1,  1, \%us_codons, $llindar_ex,\@seqfa);

## 2 

my @defex_interns2 = CODON_BIAS(\@exons_interns2, 2, \%us_codons, $llindar_ex,\@seqfa);
my @defex_inici2 = CODON_BIAS(\@exons_inici2, 2, \%us_codons, $llindar_ex,\@seqfa);
my @defex_terminals2 =  CODON_BIAS(\@exons_terminals2,  2, \%us_codons, $llindar_ex,\@seqfa);
my @defex_individuals2 = CODON_BIAS(\@exons_individuals2, 2, \%us_codons, $llindar_ex,\@seqfa);


##########################################
###   Unim les matrius de cada pauta   ###
##########################################

## pauta 0
my @unit0  = UNIR_MATRIU(\@defex_inici0,\@defex_interns0, \@defex_terminals0, \@defex_individuals0);

## pauta 1
my @unit1  = UNIR_MATRIU(\@defex_inici1,\@defex_interns1, \@defex_terminals1, \@defex_individuals1);
 
## pauta 2
my @unit2  = UNIR_MATRIU(\@defex_inici2,\@defex_interns2, \@defex_terminals2, \@defex_individuals2);

##############################
### Unim totes les matrius ###
##############################

my @resultat  = UNIR_MATRIU2(\@unit0,\@unit1, \@unit2);


##################################
### Creem la matriu definitiva ###
##################################

my @matriu_def = MATRIU_DEF (\@resultat, $id, "exon_fishing","+");


################################################################
### Ordenem per POSICIO D'INICI i en canviem el formta a GFF ###
################################################################

my @fi = FORMAT_GFF (\@matriu_def);




##########################################################
###################FUNCIONS###############################
##########################################################


#### Funcio HASH ####
# nom: HASH
# finalitat: convertir les matrius de pesos en hashes
# entrada: $acceptor / $donor (les matrius de pesos)
# sortida: hash
#####################

sub HASH {
    
    if (!open(MATRIU,"< $_[0]")){	  # Comprovem que podem obrir el fitxer
    	print "Error: No es pot obrir el fitxer de la matriu de pesos $_[0]";
	exit;
    }

    my %matpesos;             # hash on enregistrarem la matriu de pesos
    my @nucleotids;           # vector on enregistrarem els nucleotids
    my $llegint_matriu=0;     # variable indicadora de quan llegim la matriu
    my $posicio=0;            # posicio de la matriu que s'esta llegint

    while () {

	if ($llegint_matriu == 0 && m/\AP0\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)/) {

	    $nucleotids[0] = $1; 
	    $nucleotids[1] = $2; 
	    $nucleotids[2] = $3; 
	    $nucleotids[3] = $4; 

	    $llegint_matriu = 1;

	}

	if ($llegint_matriu == 1 &&
	    m/\A\d+\s+([\-\d\.]+)\s+([\-\d\.]+)\s+([\-\d\.]+)\s+([\-\d\.]+)/) {

	    $matpesos{$nucleotids[0]}[$posicio] = $1;
	    $matpesos{$nucleotids[1]}[$posicio] = $2;
	    $matpesos{$nucleotids[2]}[$posicio] = $3;
	    $matpesos{$nucleotids[3]}[$posicio] = $4;

	    $posicio = $posicio + 1;

	}

	if ($llegint_matriu == 1 && m/\AXX\s+(\d+)/) {     # la última línia complirà l'expressió

	    $matpesos{P}    = $1;
	    $llegint_matriu = 0;

	}

    }
    
    return (%matpesos);
}


#### Funcio ORFVEC ####
# nom: ORFVEC
# finalitat:obtenir un vector on cada component és la posició final d'un ORF 
# entrada:vector seq separada per codons,pauta
# sortida: vector
############################

sub ORFVEC {

    my @seqcodons = @{$_[0]};  #conte la seq separada x codons x cada pauta de lectura
    my $pauta = $_[1];         #conte el frame

    my $codon = 0;       # comptador de codons
    my $comp = 0;     # comptador de posicions
    my @vector;

    $vector[$comp] = $pauta + 1;
   

    while ($codon < scalar(@seqcodons)){

	if (($seqcodons[$codon]=~ m/(TAA|TGA|TAG)/) || ($codon == (scalar(@seqcodons)-1))){ 
	    
	    $comp = $comp + 1;

	    $vector[$comp] = $codon * 3 + 3 + $pauta;  
	        
	}

	$codon = $codon + 1;
    }


    return(@vector);
}

#### Funcio STOP_CODONSvec ####
# nom: STOP_CODONSvec
# finalitat:obtenir una matriu on la primera columna es la posició final del ORF (la de la A o la G de l'Stop codon) i la segona es un 0 (la puntuacio per despres fer la funcio fishing). 
# entrada:vector seq separada per codons,pauta
# sortida: metriu de 2 columnes
############################

sub STOP_CODONSvec {

    my @seqcodons = @{$_[0]};  #conte la seq separada x codons x cada pauta de lectura
    my $pauta = $_[1];         #conte el frame

    my $codon = 0;       # comptador de codons
    my $comp = 0;     # comptador de columnes
    my @vector;

    $vector[$comp][0]= $pauta;
    $vector[$comp][1] = 0;

    while ($codon < scalar(@seqcodons)){

	if (($seqcodons[$codon]=~ m/(TAA|TGA|TAG)/) || ($codon == (scalar(@seqcodons)-1))){ 
	    
	    $comp = $comp + 1;

	    $vector[$comp][0] = $codon * 3 + 3 + $pauta;;
	    $vector[$comp][1] = 0;
	        
	}

	$codon = $codon + 1;

    }


    return(@vector);
}


#### Funcio SPLICING ####
# nom: SPLICING
# finalitat: obtenir una matriu amb les puntacions dels donors o acceptors
# entrada: hash de la matriu de pesos
#          vector que conte la seq separada per nts
#          valor llindar de puntuació dels llocs d'splicing 
# sortida: matriu que en cada fila conte:
#          posicio del donor o acceptor (columna 1)
#          puntuacio del donor o acceptor (columna 2)
#########################


sub SPLICING {

    my %matriupesos = %{$_[0]};
    my @seq = @{$_[1]}; 
    my $llindar_sp = $_[2];

    my @f = values (%matriupesos); #hi passem el valors de la matriu de pesos (tamany finestra)
    my $pos = scalar (@{$f[0]});   #sera el num del tamany de la finestra

    my @matriu;     #matriu de resultats

    my $i = 0;      # posicio del nt dins la sequencia              
    my $b = 0;      # files de la matriu  resultats 
    
    my $pad = $i + $matriupesos{P};          #posicio dels senyals acceptors o donors 
    
    while ($i < (scalar(@seq)+1) - $pos) {   #que estiguem en una posicio que pugui contenir un lloc donador o acceptor         	  
        my $k = 0; 
        my $p = 0;    #puntuacio

	while ($k < $pos) {  # puntuem cada nucleotid a partir del hash de la matriu de pesos
    
	    $p = $p + $matriupesos{$seq[$i+$k]}[$k];
	    $k = $k + 1;
        }

        if ($p > $llindar_sp){  #ara que tenim la posicio comprovem que superi el llindar
        
	    $matriu[$b][0] = $pad;  #posicio inici o final exo (acceptor o donor)            
	    $matriu[$b][1] = $p;    #puntuacio 
	    
             $b = $b + 1; #nova fila de la matriu
    
        }

        $i = $i + 1;  # avancem una posicio

        $pad = $pad + 1;  # tmb hem d'avançar una posicio (depen de $i)

    }

    return @matriu;

}


#### Funcio ATG_CODONS ####
# nom: ATG_CODONS
# finalitat: :obtenir una matriu on la primera columna es la posicio inicial (la A de l'ATG) i la segona es un 0 (la puntuacio per despres fer la funcio fishing).
# entrada:vector seq separada per codons,pauta
# sortida: matriu de 2 columnes
############################
 
sub ATG_CODONS {

    my @seqcodons = @{$_[0]};  #conte la seq separada x codons x cada pauta de lectura
    my $pauta = $_[1];         #conte el frame

    my $codon = 0;       # comptador de codons
    my $comp = 0;        # comptador de components del VECTOR que surt de la funcio
    my @vector;
    
    while ($codon < scalar(@seqcodons)){

	if ($seqcodons[$codon]=~ m/ATG/) {   # quan trobem un ATG registrem la posicio del primer nt del codo (la A)
	
	    $vector[$comp][0] = $codon * 3 + $pauta + 1;

	    $vector[$comp][1] = 0;

	    $comp = $comp + 1;
    
	}

	$codon = $codon + 1;

    }

    return(@vector);

}



#### Funcio FISHING ####
# nom: FISHING
# finalitat: obtenir una matriu amb les posibles combinacions de formacio d'exons
# entrada: ORFs (les posicions de fi)
#          taula de donors o ATG
#          taula d'acceptors o STOP codon 
#          tipus d'exo 
# sortida: matriu:
#                  1a columna: inici de l'exo
#                  2a columna: final de l'exo
#                  3a columna: puntuacio del lloc acceptor d'splicing (o 0 en el cas de ATG)
#                  4a columna: puntuacio del lloc donador d'splicing (o 0 en el cas de STOP)
#                  5a columna: tipus d'exo (segon la combinacio de ATG/acceptor i STOP/donor)
#########################

sub FISHING {
    my @ORF = @{$_[0]};	              	### les posicions finals  de cada ORF
    my @taula_inici = @{$_[1]};	        ### Vector d'inici d'exo
    my @taula_final = @{$_[2]};	        ### Vector de final d'exo 
    my $tipus = $_[3];			### Tipus d'exo 

    my @taula_combinacions;		### Matriu de dades de les combinacions realitzades
    my $i = 0; 		         	### Comptador de files del vector inici
    my $f = 0; 				### Comptador de files del vector final
    my $vec = 0; 	                ### Comptador de les files de la taula de combinacions
    my $o = 0;

    while ( $o < scalar(@ORF)-1){    
	
	while ( $i < scalar(@taula_inici) && $taula_inici[$i][0] > $ORF[$o] && $taula_inici[$i][0] <= $ORF[$o+1]) {   # Recorrem el vector d'inici mentre estiguem dins d'un ORF
	    $f = 0;	
	
	    while($f < scalar(@taula_final)) {    # Recorrem el vector final
	    
		if ($taula_inici[$i][0] < $taula_final[$f][0] && $taula_final[$f][0] > $ORF[$o] && $taula_final[$f][0] <= $ORF[$o+1]) {	   # En el cas de que el nucleotid d'inici sigui menor al de fi fer i estiguin al mateix ORF
		
		    $taula_combinacions[$vec][0] = $taula_inici[$i][0];   # 1a columna nt d'inici de l'exo
		    
		    $taula_combinacions[$vec][1] = $taula_final[$f][0];   # 2a columna nt de final de l'exo
		
		    $taula_combinacions[$vec][2] = $taula_inici[$i][1];   # 3a columna puntuacio del lloc acceptor de splicing o 0 en el cas de ATG.
		    
		    $taula_combinacions[$vec][3] = $taula_final[$f][1];   # 4a columna la puntuacio del lloc donador de splicing o 0 en el cas de STOP
		
		    $taula_combinacions[$vec][4] = $tipus;	          # 5a columna tipus d'exo.
		
		    $vec = $vec +1;
		}

		$f = $f +1;
	    }

	    $i = $i +1;
	}	
	
	$o = $o + 1;
    }
	
	
    return(@taula_combinacions);
}


#### Funcio CODON_BIAS ####
# nom: CODON_BIAS
# finalitat: afegir dues columnes:
#                     7a: pauta
#                     8a: puntuació
# entrada: matriu fishing
#          pauta
#          hash de taula propcodons
# sortida: matriu:
#                  1a columna: inici de l'exo
#                  2a columna: final de l'exo
#                  3a columna: puntuacio del lloc acceptor d'splicing (o 0 en el cas de ATG)
#                  4a columna: puntuacio del lloc donador d'splicing (o 0 en el cas de STOP)
#                  5a columna: tipus d'exo
#                  6a columna: pauta REAL
#                  7a columna: puntuacio total de l'exo 
#########################

sub CODON_BIAS {
    
    my @matriu = @{$_[0]};	        # Matriu resultat de sub_FISHING pero a la columna 8 hi haura la puntuació del codon bias i a la 7 la pauta real
    my $pau = $_[1];	
    my %propcodons = %{$_[2]};	        ### Hash de la taula de us de codons
    my $llindar = $_[3];                ### Llindar d'acceptacio d'exons com a bons que introduim al cridar la funcio
    my @seq = @{$_[4]};
    my @matriucomp;

 			
    	         
    my $a = 0; 		         	### Comptador de files de la matriu STRING
    my $f = 0; 				### Comptador de files de la matriu @matriucomp
    my $i = 0;                          ### variable per la posició real d'inici de l'exo
    my $pauta;                          ### variable per la pauta REAL de l'exo
    my $n;                              ### variable per contar els nts de l'exo
                       
    while ($a < scalar (@matriu)){
	
	$i = $matriu[$a][0] - $pau;   # trobem la posicio d'inici de l'exo dins la pauta (0,1 o 2)
	
		
	if ($i % 3 == 0){          # trobem la posicio del primer nt del primer codo de l'exo
	    $pauta = 2;
	    $n = $i + 1 + $pau - 1; # $n conte la posicio del nt dins el vector de la seq 
	}

	if ($i % 3 == 1){
	    $pauta = 0;
	    $n = $i + $pau - 1;
	}

	if ($i % 3 == 2){
	    $pauta = 1;
	    $n = $i + 2 + $pau - 1;
	}
	 
	

	my $r = 0.0;
	my $c = "";
	
	while ($n < ($matriu[$a][1] - 2)) {    # calculem la rao de versemblanca de l'exo
	    
	    $c = $seq[$n] . $seq[$n+1] . $seq[$n+2];
	    
	    $r = $r + log($propcodons{$c}) - log(1/64);
	    
	    $n = $n + 3;
	    
	}
    
	$matriu[$a][5]= $pauta;

	$matriu[$a][6]= $r + $matriu[$a][2]+  $matriu[$a][3];    # afegim la puntuacio de l'exo a la dels llocs d'splicing
	
	$a = $a + 1;
    }
    
       
    $a = 0;
    $f = 0;
    
    while ($a < scalar (@matriu)){  # registrem nomes els exons que superen el llindar
	
	if ($matriu[$a][6] >= $llindar){
	 
	    $matriucomp[$f]= $matriu [$a];
	   
	    $f =$f + 1;
	    
	}
	$a = $a + 1;
	
    }
    
    return (@matriucomp);
    
}


#### Funcio UNIR_MATRIU ####
# nom: UNIR_MATRIU
# finalitat: unir les 4 matrius de cada pauta de lectura
# entrada: matriu coding_bias
# sortida: matriu:
#                  1a columna: inici de l'exo
#                  2a columna: final de l'exo
#                  3a columna: pauta
#                  4a columna: tipus d'exo
#                  5a columna: puntuacio
#########################
sub UNIR_MATRIU {
    my @m1 = @{$_[0]};
    my @m2 = @{$_[1]};
    my @m3 = @{$_[2]};
    my @m4 = @{$_[3]};
    
    my @unit;

    my $a = 0;   # comptador files de les matrius que ajuntem
    my $r = 0;   # comptador de files de la matriu unida

    while ($a < scalar(@m1)) {
	
	$unit[$r] = $m1[$a];

	$a = $a + 1;
	$r = $r +1;
    }
    
    $a = 0;

    while ($a < scalar(@m2)) {
	
	$unit[$r] = $m2[$a];
	
	$a = $a + 1;
	$r = $r +1;
    }

    $a = 0;

    while ($a < scalar(@m3)) {
	
	$unit[$r] = $m3[$a];
	
	$a = $a + 1;
	$r = $r +1;
    }

    $a = 0;

    while ($a < scalar(@m4)) {
	
	$unit[$r] = $m4[$a];
	
	$a = $a + 1;
	$r = $r +1;
    }

    return (@unit);
}

 
#### Funcio UNIR_MATRIU2 ####
# nom: UNIR_MATRIU2
# finalitat: unir les 3 matriu
# entrada: matriu coding_bias
# sortida: matriu:
#                  1a columna: inici de l'exo
#                  2a columna: final de l'exo
#                  3a columna: pauta
#                  4a columna: tipus d'exo
#                  5a columna: puntuació
#########################
sub UNIR_MATRIU2 {
    my @m1 = @{$_[0]};
    my @m2 = @{$_[1]};
    my @m3 = @{$_[2]};
    
    my @unit;

    my $a = 0;   # comptador files de les matrius que ajuntem
    my $r = 0;   # comptador de files de la matriu unida

    while ($a < scalar(@m1)) {
	
	$unit[$r] = $m1[$a];

	$a = $a + 1;
	$r = $r +1;
    }
    
    $a = 0;

    while ($a < scalar(@m2)) {
	
	$unit[$r] = $m2[$a];
	
	$a = $a + 1;
	$r = $r +1;
    }

    $a = 0;

    while ($a < scalar(@m3)) {
	
	$unit[$r] = $m3[$a];
	
	$a = $a + 1;
	$r = $r +1;
    }

    
    return (@unit);
}

#### Funcio MATRIU_DEF ####
# nom: MATRIU_DEF
# finalitat: canviar el format de la matriu unida
# entrada: matriu unida
#                  1a columna: inici de l'exo
#                  2a columna: final de l'exo
#                  3a columna: puntuació del lloc acceptor d'splicing (o 0 en el cas de ATG)
#                  4a columna: puntuació del lloc donador d'splicing (o 0 en el cas de STOP)
#                  5a columna: tipus d'exo
#                  6a columna: pauta REAL
#                  7a columna: puntuació total 
# sortida: matriu definitiva:
#                  1a columna: id
#                  2a columna: nom del programa: EXON_FISHING
#                  3a columna: tipus d'exo
#                  4a columna: inici de l'exo
#                  5a columna: final de l'exo
#                  6a columna: puntuació total  
#                  7a columna: strand. + 
#                  8a columna: pauta REAL 
#########################

sub MATRIU_DEF {

    my @pre = @{$_[0]};
    my $id = $_[1];
    my $nom = $_[2];
    my $str = $_[3];
    my @matriu_def;

    my $p = 0; #Comptador de la matriu unida
    

    while ($p < scalar (@pre)){
	$matriu_def[$p][0] = $id;
	$matriu_def[$p][1] = $nom;
	$matriu_def[$p][2] = $pre[$p][4];
	$matriu_def[$p][3] = $pre[$p][0];
	$matriu_def[$p][4] = $pre[$p][1];
	$matriu_def[$p][5] = $pre[$p][6];
	$matriu_def[$p][6] = $str;
	$matriu_def[$p][7] = $pre[$p][5];

	$p = $p + 1;
    }
    my @matriudef = sort {${$a}[3]<=> ${$b}[3]|| ${$a}[4]<=> ${$b}[4]}(@matriu_def);
    #ordenem la matriu amb la funcio sort segons la posicio d'inici de l'exo    

    return (@matriudef);
}

#### Funcio FORMAT_GFF ####
# nom: FORMAT_GFF
# finalitat: canviar el format de la matriu ordenada 
# entrada: matriu ordenada
# sortida: matriu en format GFF
##########################

sub FORMAT_GFF {

    my @matriudef = @{$_[0]};

    my $i = 0; # Comptador de files de la matriu
    
    print "La predicció d'exons per a la seqüencia introduida es: \n";

    while ($i < scalar (@matriudef)){

	print "$matriudef[$i][0]\t";
	print "$matriudef[$i][1]\t";
	print "$matriudef[$i][2]\t";
	print "$matriudef[$i][3]\t";
	print "$matriudef[$i][4]\t";
	printf ("%.2f \t", $matriudef[$i][5]);
	print "$matriudef[$i][6]\t";
	print "$matriudef[$i][7]\n";
	

	$i = $i + 1;
    }

    return(@matriudef);
}


#################################### FI DEL PROGRAMA #############################################