#!/usr/bin/env perl

# MANUAL FOR seqscreen_tsv_report.pl

=pod

=head1 NAME

seqscreen_tsv_report.pl -- generates report for the S2FAST pipeline

=head1 SYNOPSIS

 seqscreen_tsv_report.pl --taxonomy=/Path/to/taxonomy_results.txt --taxlookup=/Path/to/names.txt --functional=/Path/to/fxn_results.txt --bpocs=/Path/to/bpoc_queries.txt --fasta=/Path/to/input.fasta --out=/Path/to/report.tsv
                     [--help] [--manual]

=head1 DESCRIPTION

 Generates the per-seqeuence TSV report for an S2FAST run.
 
=head1 OPTIONS

=over 3

=item B<-t, --taxonomy>=FILENAME

File containing the S2FAST taxonomy results. (Required)

=item B<-tl, --taxlookup>=FILENAME

Lookup file of NCBI tax IDs and the scientific name associated with that ID. (Required)
This is the "taxa_lookup.txt" file under the "databases/taxonomy/" directory.

=item B<-f, --functional>=FILENAME

File containing the S2FAST functional results. (Required)

=item B<-th, --bpocs>=FILENAME

File containing the queries thought to be a bpoc. (Required)

=item B<-fa, --fasta>=FILENAME

The FASTA file analyzed by the pipeline. (Required)

=item B<-o, --out>=FILENAME

Output report file. (Required) 

=item B<-h, --help>

Displays the usage message.  (Optional) 

=item B<-m, --manual>

Displays full manual.  (Optional) 

=back

=head1 DEPENDENCIES

Requires the following Perl libraries.



=head1 AUTHOR

Written by Daniel Nasko, 
Center for Bioinformatics and Computational Biology, University of Maryland.

=head1 REPORTING BUGS

Report bugs to dnasko@umiacs.umd.edu

=head1 COPYRIGHT

Copyright 2017 The S2FAST Team.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.  
This is free software: you are free to change and redistribute it.  
There is NO WARRANTY, to the extent permitted by law.  

=cut


use strict;
use warnings;
use Getopt::Long;
use File::Basename;
use Pod::Usage;

#ARGUMENTS WITH NO DEFAULT
my($functional,$taxonomy,$taxlookup,$bpocs,$fasta,$out,$help,$manual);

GetOptions (	
				"f|functional=s"=>	\$functional,
                "t|taxonomy=s"  =>      \$taxonomy,
                "tl|taxlookup=s"=>      \$taxlookup,
                "th|bpocs=s"  =>      \$bpocs,
                "fa|fasta=s"    =>      \$fasta,
				"o|out=s"	=>	\$out,
				"h|help"	=>	\$help,
				"m|manual"	=>	\$manual) || pod2usage({-exitval => 2, -verbose => 1, -output => \*STDERR});

# VALIDATE ARGS
pod2usage(-verbose => 2)  if ($manual);
pod2usage( {-exitval => 0, -verbose => 2, -output => \*STDERR} )  if ($help);
pod2usage( -msg  => "\n\n ERROR!  Required argument --functional not found.\n\n", -exitval => 2, -verbose => 1)  if (! $functional );
pod2usage( -msg  => "\n\n ERROR!  Required argument --taxonomy not found.\n\n", -exitval => 2, -verbose => 1)  if (! $taxonomy );
pod2usage( -msg  => "\n\n ERROR!  Required argument --taxlookup not found.\n\n", -exitval => 2, -verbose => 1)  if (! $taxlookup );
pod2usage( -msg  => "\n\n ERROR!  Required argument --bpocs not found.\n\n", -exitval => 2, -verbose => 1)  if (! $bpocs );
pod2usage( -msg  => "\n\n ERROR!  Required argument --fasta not found.\n\n", -exitval => 2, -verbose => 1)  if (! $fasta );
pod2usage( -msg  => "\n\n ERROR!  Required argument --out not found.\n\n", -exitval => 2, -verbose => 1)  if (! $out );

## Output fields and the order they will appear, now with confidences!
## Entry   adhesion        secretion       host_cell_death antibiotic      invasion        evasion cytotoxicity    degrade_ecm                                            ## disable_organ    is_virus        is_bacteria target_human    target_primate  target_livestock        target_crop

my @OutputFields = ("query", "taxid", "go", "multi_taxids_confidence", "go_id_confidence", "adhesion", "secretion", "host_cell_death","antibiotic", "invasion", "evasion", "cytotoxicity", "degrade_ecm","disable_organ", "size", "organism","gene_name", "uniprot", "uniprot evalue");

## Globals
my %Bpocs_list; ## Holds the confidence for an assignment
my %Confidence; ## Holds the confidence for an assignment
my %ConfSum;    ## Holds the confidence summary
my %Taxlookup;  ## Holds the taxid to tax info

## Go through the Taxonomy lookup file to get that information in a dictionary
open(my $txfh,'<',"$taxlookup") || die "\n Cannot open the file: $taxlookup\n";
while(<$txfh>) {
    chomp;
    my @a = split(/\t/, $_);
    if (scalar(@a) == 2) {
	$Taxlookup{$a[0]} = $a[1];
    }
    else { die "\n Error: You may have passed the wrong file to --taxlookup. There should be 2 fields, not " . scalar(@a) . " fields\n\n";}
}
close($txfh);

## Go through the bpocs file to stores bpoc per uniprot id
open(my $thfh,'<',"$bpocs") || die "\n Cannot open the file: $bpocs\n";
while(<$thfh>) {
    chomp;
    my @a = split(/\t/, $_);
    unless ($a[0] eq "Entry") {
	my $bin = $a[2];
	my $conf = $a[3];
	my $confsum = $a[5];
	$Bpocs_list{$a[0]} = [$a[1],$a[2],$a[3],$a[4],$a[5],$a[6],$a[7],$a[8],$a[9]];
        #print $Bpocs_list{$a[0]};
    }
}
close($thfh);

## Go through the FASTA file to get the size of each sequence
my %Sizes; ## Holds the size of each sequence
my $headerid = "";
my $sequence = "";

open(my $ffh,'<',"$fasta") || die "\n Cannot open the file: $fasta\n";
while(<$ffh>) {
    $_ =~ s/\r[\n]*/\n/gm; ## remove any weird metacharacters
    chomp;
    if ($_ =~ m/^>/) { ## If header line
	unless ($headerid eq "") { ## If we're not on the first header of the file
	    $Sizes{$headerid} = length($sequence);
	    $sequence = ""; ## clear out this variable for the next sequence
	}
	$headerid = $_;
	$headerid =~ s/^>//;  ## strip off the '>'
	$headerid =~ s/ .*//; ## remove any text after the first space
    }
    else { ## If sequence line
	$sequence = $sequence . $_; ## keep adding sequence lines to this variable
    }
}
close($ffh);
$Sizes{$headerid} = length($sequence); ## last sequence


## Go through the taxa first, becuase the fxn holds the order from the input.
my %Taxa; ## Hold the taxonomic results
my %TaxaConf; ## Hold the taxonomic results
my %Taxam; ## Hold single tax id from multi assignment
my $line_count=0; ## keep track of line number, used to pass over the header line

open($txfh,'<',"$taxonomy") || die "\n Cannot open the file: $taxonomy\n";
while(<$txfh>) {
    chomp;
    my @a = split(/\t/, $_);
    unless ($line_count== 0) { ## the first line is header information, we dont want that
        my $query  = $a[0];
        my $taxids = $a[1];
        my $source = $a[2];
        my $conf = $a[3];
            my @merged;

            my @Taxtmp = split(/,/, $taxids); ## Sometimes multiple taxids are reported. We just want the first in that case                                                                                  
            my @Conftmp = split(/,/, $conf); ## Sometimes multiple taxids are reported. We just want the first in that case                                                                                  
        foreach my $i (0..$#Taxtmp) 
        {
            push @merged, join(":",$Taxtmp[$i],$Conftmp[$i]);
            #print join(":",$Taxtmp[$i],$Conftmp[$i]) + "\n";
        }
        #take first taxa, should be "best" representative
        $Taxam{$query} = $Taxtmp[0];
        $TaxaConf{$query} = join(",", @merged); ## populate %TaxaConf with taxa and conf
    }
    $line_count++;
}
close($txfh);

$line_count=0; ## Reset the counter for the next file

## Open up the output file
open(my $ofh,'>',"$out") || die "\n Cannot open the outfile: $out\n"; ## open the output file
print $ofh join("\t", @OutputFields) . "\n"; ## print out the header

my %FieldPos = ("query" => "", "gene_name" => "", "uniprot" => "", "evalue" => "", "go" => "");
open($ffh,'<',"$functional") || die "\n Cannot open the file: $functional\n";
while(<$ffh>) {
    chomp;
    my @a = split(/\t/, $_);
    if ($line_count == 0) { ## the first line is header information, we dont want that
        my $header = $_; $header =~ s/^#//;
        find_fields($header); ## populate the %FieldPos with field positions
    }
    else {
        my ($query, $taxid, $go, $multi_taxconf, $go_confs, $adhesion, $secretion,$host_cell_death,$antibiotic,$invasion,$evasion,$cytotoxicity,$degrade_ecm,$disable_organ,$size, $organism, $gene_name, $uniprot, $uniprot_evalue) = ("","", "", "", "", "NA","NA","NA","NA","NA","NA","NA","NA","NA","","","", "");

        $query = $a[$FieldPos{'query'}];
        $gene_name = $a[$FieldPos{'gene_name'}];
        $uniprot = $a[$FieldPos{'uniprot'}];
        $uniprot_evalue = $a[$FieldPos{'evalue'}];
        #my $go_confs;
        
        if (exists $Taxam{$query}) { ## If there were tax results from the tax file
            $taxid = $Taxam{$query};

            my @Taxtmp = split(/,/, $taxid); ## Sometimes multiple taxids are reported. We just want the first in that case
                
            if (exists $Taxlookup{$Taxtmp[0]}) {
                $organism = $Taxlookup{$Taxtmp[0]};
            }
            # else { die "\n Error: A taxid was given to query $query that an organism name cannot be found for: $taxid\n"; }
        }
        if ($a[$FieldPos{'go'}]) { ## if there's a go field
            $go = $a[$FieldPos{'go'}];
            my @go_terms = split(/;/, $go);
            for (my $i=0; $i<scalar(@go_terms)-1; $i++) {
                $go_confs = $go_confs . join("",$go_terms[$i],"[1.0];");
            }
            $go_confs = $go_confs . join("",$go_terms[scalar(@go_terms)-1],"[1.0]");
        }
        if (exists $Sizes{$query}) {
            $size = $Sizes{$query};
            delete $Sizes{$query}; ## Delete this, so we know we've reported this sequence
        }
        else { die "\n Error: Missing sequence size information for the query: $query\n"; }
        if (exists $Bpocs_list{$uniprot}) { ## check that this uniprot has bpocs
            #print @Bpocs_list{$uniprot} . "\n" ; 
            $adhesion = $Bpocs_list{$uniprot}[0];
            $secretion = $Bpocs_list{$uniprot}[1];
            $host_cell_death = $Bpocs_list{$uniprot}[2];
            $antibiotic = $Bpocs_list{$uniprot}[3];
            $invasion = $Bpocs_list{$uniprot}[4];
            $evasion = $Bpocs_list{$uniprot}[5];
            $cytotoxicity = $Bpocs_list{$uniprot}[6];
            $degrade_ecm = $Bpocs_list{$uniprot}[7];
            $disable_organ = $Bpocs_list{$uniprot}[8];
        }
        else{
            $adhesion = "0";
            $secretion = "0";
            $host_cell_death = "0";
            $antibiotic = "0";
            $invasion = "0";
            $evasion = "0";
            $cytotoxicity = "0";
            $degrade_ecm = "0";
            $disable_organ = "0";
        }
        if (exists $TaxaConf{$query}) {
            $multi_taxconf = $TaxaConf{$query};
        }

        print $ofh join("\t",$query, $taxid, $go, $multi_taxconf, $go_confs, $adhesion, $secretion,$host_cell_death,$antibiotic,$invasion,$evasion,$cytotoxicity,$degrade_ecm,$disable_organ,$size, $organism, $gene_name, $uniprot, $uniprot_evalue) . "\n";
    }
    $line_count++;
}
close($ffh);

foreach my $seq (sort keys %Sizes) {
    my $taxid = $Taxam{$seq};
    my $multi_taxconf = $TaxaConf{$seq};

    if (defined $taxid && $taxid ne "" ){
        print $ofh join("\t", $seq, $taxid, "-", $multi_taxconf,"-","-","-","-","-","-","-","-","-","-", $Sizes{$seq}, $Taxlookup{$taxid}, "-", "-", "-") . "\n";
    }
    else {
        print $ofh join("\t", $seq, "-", "-", "-", "-","-","-","-","-","-","-","-","-","-",$Sizes{$seq}, "-", "-", "-", "-") . "\n";
    }
}
close($ofh);

exit 0;

sub find_fields
{
    my $h = $_[0];
    my $fields_expected = keys %FieldPos;
    my $fields_found = 0;
    my @a = split(/\t/, $h);
    for (my $i=0; $i<scalar(@a); $i++) {
	if (exists $FieldPos{$a[$i]}) {
	    $FieldPos{$a[$i]} = $i;
	    $fields_found++;
	}
    }
    unless ($fields_found == $fields_expected) { die "\n Error: all of the fields were not found in the functional file\n\n"; }
}
