#!/usr/bin/env perl
use strict;
use warnings;
=head1 NAME

phyloFlash - A script to rapidly estimate the phylogenetic composition of
an illumina (meta)genomic dataset and reconstruct SSU rRNA genes.

=head1 SYNOPSIS

B<phyloFlash.pl> [OPTIONS] -lib I<name> -read1 F<<file>> -read2 F<<file>>

B<phyloFlash.pl> -help

B<phyloFlash.pl> -man 

B<phyloFlash.pl> -check_env 

=head1 DESCRIPTION

This tool rapidly approximates the phylogenetic composition of a
(meta)genomic read set based on SSU mapping and reconstruction.
Right now Illumina paired end or single HiSeq and MiSeq reads
are supported.

=head1 ARGUMENTS

=over 15

=item -lib I<name>

Library I<name> to use for output file. The name must be one word comprising
only letters, numbers and "_" or "-" (no whitespace or other punctuation).

=item -read1 F<file>

File containing forward reads. Both FASTA and FASTQ formats are understood.
The file may be compressed (.gz). If interleaved read data is provided, please
use --interleaved flag for paired-end processing

=item -read2 F<file>

File containing reverse reads. If this option is omitted, B<phyloFlash>
will run in B<experimental> single-end mode.

=item -check_env

Invokes checking of working environment and dependencies without data input.
Use to test setup.

=item -help

Print brief help.

=item -man

Show manual.

=back

=head1 OPTIONS

=over 15


=item -dbhome F<dir>

Directory containing phyloFlash reference databases.
Use F<phyloFlash_makedb.pl> to create an appropriate directory.

=item -interleaved

Interleaved readfile with R1 and R2 in a single file at read1

=item -readlength I<N>

Sets the expected readlength. Always use this if your read length
differs from 100 (the default). Must be within 50..500.

=item -CPUs I<N>

Set the number of threads to use. Defaults to all available CPU cores.

=item -readlimit I<N>

Limits processing to the first I<N> reads in each input file. Use this
for transcriptomes with a lot of rRNA reads (use values <1000000).
Default: unlimited

=item -amplimit I<N>

Sets the limit of SSU read pairs to switch from emirge.py to
emirge_amplicon.py. This feature is not reliable as emirge_amplicon.py
has been problematic to run (use values >100000).
Default: 500000

=item -id I<N>

Minimum allowed identity for read mapping process in %. Must be within
63..98. Set this to a lower value for very divergent taxa
Default: 70

=item -clusterid I<N>

Identity threshold for clustering with vsearch in %.
Must be within 50..100. Default: 97

=item -maxinsert I<N>

Maximum insert size allowed for paired end read mapping. Must be within
0..1200. Default: 1200

=item -html

Also generate output in HTML format.

=item -treemap

Draw interactive treemap of taxonomic classification in html-formatted
report. This uses Google Visualization API, which requires an internet
connection, requires that you agree to their terms of service (see
https://developers.google.com/chart/terms), and is not open source,
although it is free to use.

=item -crlf

Use CRLF as line terminator in CVS output (to become RFC4180 compliant).

=item -decimalcomma

Use decimal comma instead of decimal point to fix locale problems
(default: off)

=item -skip_emirge

Turn off EMIRGE reconstruction of SSU sequences

=item -skip_spades

Turn off SPAdes assembly of SSU sequences

=item -sc

Turn on single cell MDA data mode for SPAdes assembly of SSU sequences

=back

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2014- by Harald Gruber-Vodicka <hgruber@mpi-bremen.de>
                    and Elmar A. Pruesse <elmar.pruesse@ucdenver.edu>
                    with help from Brandon Seah <kbseah@mpi-bremen.de>

LICENCE

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
=cut

use strict;
use warnings;

use FindBin;
use lib $FindBin::RealBin;

use PhyloFlash;

use Pod::Usage;
use Getopt::Long;
use File::Basename;
use IPC::Cmd qw(can_run);
use Cwd;
use FindBin;

# change these to match your installation
my @dbhome_dirs = (".", $ENV{"HOME"}, $FindBin::RealBin); 

# constants
my $version       = 'phyloFlash v2.0';
my $progname      = $FindBin::Script;
my $cwd = getcwd;

# configuration variables / defaults
my $DBHOME      = undef;
my $readsf_full = undef;        # path to forward read file
my $readsr_full = undef;        # path to reverse read file
my $readsf      = undef;        # forward read filename, stripped of directory names
my $readsr      = undef;        # reverse read filename, stripped of directory names
my $SEmode      = 0;            # single ended mode
my $libraryNAME = undef;        # output basename
my $interleaved = 0;            # Flag - interleaved read data in read1 input (default = 0, no)
my $id          = 70;           # minimum %id for mapping
my $readlength  = 100;          # length of input reads
my $readlimit   = -1;           # max # of reads to use
my $amplimit    = 500000;       # number of SSU pairs at which to switch to emirge_amplicon
my $maxinsert   = 1200;         # max insert size for paired end read mapping
my $cpus        = get_cpus      # num cpus to use
my $clusterid   = 97;           # threshold for vsearch clustering

my $html_flag   = 0;            # generate HTML output? (default = 0, off)
my $treemap_flag = 0;           # generate interactive treemap (default = 0, off)
my $crlf        = 0;            # csv line terminator
my $decimalcomma= 0;            # Decimal separator (default = .)
my $skip_emirge = 0;            # Flag - skip Emirge step? (default = 0, no)
my $skip_spades = 0;            # Flag - skip SPAdes assembly? (default = 0, no)
my $sc          = 0;            # Flag - single cell data? (default = 0, no)
my $check_env   = 0;            # Check environment (runs check_environment subroutine only)
my @tools_list;                 # Array to store list of tools required
                                # (0 will be turned into "\n" in parsecmdline)

my $emirge_db   = "SILVA_SSU.noLSU.masked.trimmed.NR96.fixed";
my $vsearch_db  = "SILVA_SSU.noLSU.masked.trimmed";


my $ins_used = "SE mode!";


# variables for report generation
my %taxa_from_hitmaps; # Hash of read counts from mapping, keyed by taxon string
my @taxa_from_hitmaps_sorted;
my @ssuassem_results_sorted; #sorted list of SSU sequences for reporting
my @ssurecon_results_sorted;
my $readnr_pairs;
my $SSU_total_pairs;
my $SSU_ratio;
my $SSU_ratio_pc;
my $chao1 = 0;
my @xtons = (0,0,0);  # singleton, doubleton and tripleton count
my $readnr = 0;
my $ins_me = 0;
my $ins_std =0;
my $runtime;


# display welcome message incl. version
sub welcome {
    print STDERR "\nThis is $version\n\n";
}

# checks whether a given directory is a valid dbhome
# (contains the necessary files for bbmap, emirge and vsearch)
sub check_dbhome {
    my $dbhome = shift;
    foreach ('ref/genome/1/summary.txt', $emirge_db.".fasta",
	     $vsearch_db.".fasta") {
	return "${dbhome}/$_"
	    unless -r "${dbhome}/$_"
    }
    return "";
}

# searches @dbhome_dirs for the dbdir with the highest version
# returns "" if none found
sub find_dbhome {
    my @dirs;
    my @dbdirs;

    foreach (@dbhome_dirs) {
	push(@dirs, get_subdirs($_));
    }
    foreach (@dirs) {
	if (check_dbhome($_) eq "") {
	    push(@dbdirs, $_);
	}
    }
    if (scalar @dbdirs > 0) {
	@dbdirs = version_sort(@dbdirs);
	return $dbdirs[0];
    }

    return "";
}

# Specify list of required tools. Run this subroutine AFTER parse_cmdline()
sub process_required_tools {
  # binaries needed by phyloFlash
    require_tools(
        bbmap => "bbmap.sh",
        barrnap => "$FindBin::RealBin/barrnap-HGV/bin/barrnap_HGV",
        vsearch => "vsearch",
        mafft => "mafft",
        fastaFromBed => "fastaFromBed",
        sed => "sed",
        grep => "grep",
        awk => "awk",
        cat => "cat",
        plotscript => "$FindBin::RealBin/phyloFlash_plotscript.R"
    );
    if ($skip_spades == 0) {
        require_tools(spades => "spades.py");
    }
    if ($skip_emirge == 0) {
        require_tools(emirge => "emirge.py",
                      emirge_amp => "emirge_amplicon.py",
                      emirge_rename_fasta => "emirge_rename_fasta.py");
    }
}

# parse arguments passed on commandline and do some
# sanity checks
sub parse_cmdline {
    GetOptions('read1=s' => \$readsf_full,
               'read2=s' => \$readsr_full,
               'lib=s' => \$libraryNAME,
               'dbhome=s' => \$DBHOME,
	       'interleaved' => \$interleaved,
               'readlength=i' => \$readlength,
               'readlimit=i' => \$readlimit,
	       'amplimit=i' => \$amplimit,
               'maxinsert=i' => \$maxinsert,
               'id=i' => \$id,
               'clusterid=i' => \$clusterid,
               'CPUs=i' => \$cpus,
               'html' => \$html_flag,
               'treemap' => \$treemap_flag,
               'crlf' => \$crlf,
               'decimalcomma' => \$decimalcomma,
               'skip_emirge' => \$skip_emirge,
               'skip_spades' => \$skip_spades,
               'sc' => \$sc,
               'check_env' => \$check_env,
               'help' => sub { pod2usage(1) },
               'man' => sub { pod2usage(-exitval=>0, -verbose=>2) },
           )
        or pod2usage(2);


    # verify tools present
    if ($check_env == 1) {
      process_required_tools();
      check_environment(); # will die on failure
    }


    # verify database present
    if (defined($DBHOME)) {
	if (my $file = check_dbhome($DBHOME)) {
	    pod2usage("\nBroken dbhome directory: missing file \"$file\"")
	}
    } else {
	$DBHOME = find_dbhome();
	pod2usage("Failed to find suitable DBHOME. (Searched \""
		  .join("\", \"",@dbhome_dirs)."\".)\nPlease provide a path using -dbhome. "
		  ."You can build a reference database using phyloflash_makedb.pl\n")
	    if ($DBHOME eq "");
    }
    msg("Using dbhome '$DBHOME'");


    # verify valid lib name
    pod2usage("Please specify output file basename with -lib")
        if !defined($libraryNAME);
    pod2usage("\nArgument to -lib may not be empty")
        if length($libraryNAME) == 0;
    pod2usage("\nArgument to -lib may contain only alphanumeric characters,"
              ."'_' and '-'.")
        if not $libraryNAME =~ m/[a-zA-Z0-9_-]/ ;

    msg("working on library $libraryNAME");

    
    # verify read files
    pod2usage("\nPlease specify input forward read file with -read1")
        if !defined($readsf_full);
    pod2usage("\nUnable to open forward read file '$readsf_full'. ".
              "Make sure the file exists and is readable by you.")
        if ! -e $readsf_full;

    # strip directory paths from forward read filename
    if ($readsf_full =~ m/.*\/(.+)/) {
      $readsf = $1;
    } else { 
	$readsf = $readsf_full; 
    }
    
    if (defined($readsr_full)) {
        pod2usage("\nUnable to open reverse read file '$readsr_full'.".
                  "Make sure the file exists and is readable by you.")
            if ! -e $readsr_full;
        pod2usage("\nForward and reverse input read file need to be different")
            if ($readsr_full eq $readsf_full);
        if ($readsr_full =~ m/.*\/(.+)/) {    # strip directory paths from reverse read filename
          $readsr = $1;
        } else { $readsr = $readsr_full; }
     
     } elsif ( $interleaved == 1 ){
	msg("Using interleaved read data");
        
    } else {
        $SEmode = 1; # no reverse reads, we operate in single ended mode
        $readsr = "<NONE>";
        $readsr_full = "<NONE>";
    }

    msg("Forward reads $readsf_full");
    if ($SEmode == 0)  {
        if (defined($readsr_full)) {
	    msg("Reverse reads $readsr_full");
	} else{
	    msg("Reverse reads from interleaved read file $readsf_full");
	}
    } else {
        msg("Running in single ended mode");
    }


    # check lengths
    pod2usage("\nReadlength must be within 50...500")
        if ($readlength < 50 or $readlength > 500);
    pod2usage("\nMaxinsert must be within 0..1200")
        if ($maxinsert < 0 or $maxinsert > 1200);
    pod2usage("\nReadmapping identity (-id) must be within 63..98")
        if ($id < 63 or $id > 98);
    pod2usage("\nClustering identidy (-clusterid) must be within 50..100")
        if ($clusterid < 50 or $clusterid > 100);

    $crlf = $crlf ? "\r\n":"\n";

    # check CPUS
    if ($cpus eq "all" or $cpus < 0) {
        $cpus = get_cpus();
    }

    # check surplus arguments
    err("Command line contains extra words:", @ARGV)
        if ($ARGV[0]);
}

sub print_report {
    ## Write plaintext report file

    msg("writing final files...");
    my $fh;
    open_or_die(\$fh, '>', $libraryNAME.'.phyloFlash');

    print {$fh} qq ~
$version - high throughput phylogenetic screening using SSU rRNA gene(s) abundance(s)
Library name:\t$libraryNAME
---
Forward read file\t$readsf_full~;
if ($SEmode == 0) {
  if ($interleaved == 1) { # reads are provided interleaved
        print {$fh} qq~
Reverse reads provided interleaved in file\t$readsf_full~;}
  else { # reads are provided in two separate files
    print {$fh} qq ~
Reverse read file\t$readsr_full~;
  }
}

print {$fh} qq~
---
Current working directory\t$cwd
---
Minimum mapping identity:\t$id%
~;

    if (defined($readsr_full) || $interleaved == 1) { # If in PE mode
        print {$fh} qq~
---
Input PE-reads:\t$readnr_pairs
Mapped SSU reads:\t$SSU_total_pairs
Mapping ratio:\t$SSU_ratio_pc%
Detected median insert size:\t$ins_me
Used insert size:\t$ins_used
Insert size standard deviation:\t$ins_std
~;
    } else { # Else if in PE mode
        print {$fh} qq~
---
Input SE-reads:\t$readnr_pairs
Mapped SSU reads:\t$SSU_total_pairs
Mapping ratio:\t$SSU_ratio_pc%
~;
    }

    print {$fh} qq~
---
Runtime:\t$runtime
CPUs used:\t$cpus
---
Read mapping based higher taxa (NTUs) detection

NTUs observed once:\t$xtons[0]
NTUs observed twice:\t$xtons[1]
NTUs observed three or more times:\t$xtons[2]
NTU Chao1 richness estimate:\t$chao1

List of NTUs in order of abundance (min. 3 reads mapped):
NTU\treads
~;

    # sort keys numerically descending in hash of
    # mapping-based detected higher taxa
    foreach my $taxonshortstring ( @taxa_from_hitmaps_sorted ) {
        # Print the name of this higher taxon, and the
        # corresponding no. of unambig hits mapped
        print {$fh} join("\t",@$taxonshortstring)."\n";
    }

    if ($skip_spades == 0) {
        ## Print the table of SSU assembly-based taxa to report file
        print {$fh} "---\n";
        print {$fh} "SSU assembly based taxa:\n";
        print {$fh} "OTU\tcoverage\tdbHit\ttaxonomy\t%id\talnlen\tevalue\n";

        foreach my $arr (@ssuassem_results_sorted) {
            print {$fh} join("\t",  @$arr)."\n";
        }
    }

    if ($skip_emirge == 0) {
        ## Print the table of SSU reconstruction-based taxa to report file
        print {$fh} "---\n";
        print {$fh} "SSU reconstruction based taxa:\n";
        print {$fh} "OTU\tratio\tdbHit\ttaxonomy\t%id\talnlen\tevalue\n";
        foreach my $arr (@ssurecon_results_sorted) {
            print {$fh} join("\t", @$arr)."\n";
        }
    }

    close($fh);
}

sub write_csv {
    msg("exporting results to csv");
    my $fh;

    my @report = csv_escape((
        "version",$version,
        "library name",$libraryNAME,
        "forward read file",$readsf_full,
        "reverse read file",$readsr_full,
        "cwd",$cwd,
        "minimum mapping identity",$id,
        "single ended mode",$SEmode,
        "input reads",$readnr_pairs,
        "mapped SSU reads",$SSU_total_pairs,
        "mapping ration",$SSU_ratio_pc,
        "detected median insert size",$ins_me,
        "used insert size",$ins_used,
        "insert size stddev",$ins_std,
        "runtime",$runtime,
        "CPUs",$cpus,
        "NTUs observed once",$xtons[0],
        "NTUs observed twice",$xtons[1],
        "NTUs observed three or more times",$xtons[2],
        "NTU Chao1 richness estimate",$chao1
    ));

    open_or_die(\$fh, ">", "$libraryNAME.phyloFlash.report.csv");
    while ($#report > 0) {
        print {$fh} shift(@report).",".shift(@report).$crlf;
    }
    close($fh);

    open_or_die(\$fh, ">", "$libraryNAME.phyloFlash.NTUabundance.csv");
    print $fh "NTU,reads\n";
    foreach my $arr ( @taxa_from_hitmaps_sorted ) {
        print {$fh} join(",",csv_escape(@$arr)).$crlf;
    }
    close($fh);

    if ($skip_spades + $skip_emirge < 2) {  # Check if SPAdes or Emirge were skipped
      open_or_die(\$fh, ">", "$libraryNAME.phyloFlash.extractedSSUclassifications.csv");
      print $fh "OTU,coverage,dbHit,taxonomy,%id,alnlen,evalue\n";
      if ($skip_spades == 0) {
        foreach my $arr (@ssuassem_results_sorted) {
            print {$fh} join(",",csv_escape(@$arr)).$crlf;
        }
      }
      if ($skip_emirge == 0) {
        foreach my $arr (@ssurecon_results_sorted) {
            print {$fh} join(",",csv_escape(@$arr)).$crlf;
        }
      }
      close($fh);
    }
}


sub bbmap_fast_filter_run {
    # input: $readsf, $readsr
    # output: lib.$readsf.SSU.{1,2}.fq
    #         lib.bbmap.out
    #         lib.inserthistogram
    # tmp:    tmp.lib.basecompositionhistogram
    msg("filtering reads with SSU db using minimal identity of $id%");
    if ($readlimit != -1) {
        msg("Only using the first $readlimit reads");
    }

    my $minID= $id / 100;
    if ($minID < 0.63) {
        $minID = 0.63
    }

    my $args = "";
    if ($SEmode == 0) {
	if ($interleaved == 1) {
	    $args =
	    "  outm2=$libraryNAME.$readsf.SSU.2.fq "
	    . "pairlen=$maxinsert interleaved=t";
	} else {
	    $args =
	    "  outm2=$libraryNAME.$readsf.SSU.2.fq "
	    . "pairlen=$maxinsert in2=$readsr_full";
	}
    }
    run_prog("bbmap",
             "  fast=t "
             . "minidentity=$minID "
             . "-Xmx20g reads=$readlimit "
             . "threads=$cpus "
             . "po=f "
             . "outputunmapped=f "
             . "path=$DBHOME "
             . "outm=$libraryNAME.$readsf.SSU.1.fq "
             . "build=1 "
             . "in=$readsf_full "
             . "bhist=tmp.$libraryNAME.basecompositionhistogram "
             . "ihist=$libraryNAME.inserthistogram "
             . "idhist=$libraryNAME.idhistogram "
             . "scafstats=$libraryNAME.hitstats "
             . $args,
             undef,
             "$libraryNAME.bbmap.out");

    msg("done...");
}


sub bbmap_fast_filter_parse() {
    # parsing bbmap.out for used read numbers, mapped reads,
    # insert size median and standard deviation

    # input: lib.bbmap.out

    my $ssu_pairs     = 0;
    my $ssu_bad_pairs = 0;
    my $ssu_f_reads   = 0;
    my $ssu_r_reads   = 0;
    my $forward_count = 0;

    my $fh;
    open_or_die(\$fh, "<", $libraryNAME.'.bbmap.out');
    while (<$fh>) {
        if (/^Reads\ Used\:\ +\t+([0-9]*).*$/) {
            $readnr = $1;
            msg("single reads mapped: $readnr");
        }
        if (/^mated pairs:\s+\S+\s+([0-9]*).*$/) {
            $ssu_pairs = $1;
            msg("mapped SSU pairs: $ssu_pairs");
        }
        if (/^bad pairs:\s+\S+\s+([0-9]*).*$/) {
            $ssu_bad_pairs = $1;
            msg("mapped bad SSU pairs: $ssu_bad_pairs");
        }
        if (/^insert\ median:\ +\t+\ +([0-9]*).*$/) {
            $ins_me = $1;
            msg("insert size median: $ins_me");
        }
        if (/^insert\ std\ dev:\ +\t+\ +([0-9]*).*$/) {
            $ins_std = $1;
            msg("insert size std deviation: $ins_std");
        }
        if ($forward_count == 0) {
            if (/^mapped:\s+\S+\s+([0-9]*).*$/) {
                $ssu_f_reads = $1;
                msg("mapped forward SSU reads: $ssu_f_reads");
                $forward_count++;
                next;
            }
        }
        if ($forward_count == 1) {
            if (/^mapped:\s+\S+\s+([0-9]*).*$/) {
                $ssu_r_reads = $1;
                msg("mapped reverse SSU reads: $ssu_r_reads");
                last;
            }
        }
    }
    close($fh);

    # calculating mapping ratio
    $readnr_pairs = $readnr;
    if ($SEmode == 0) {
        $readnr_pairs /= 2;
    }

    $SSU_total_pairs =
        $ssu_f_reads + $ssu_r_reads
        - $ssu_pairs - $ssu_bad_pairs;
    if ($SEmode == 0) {
        msg("mapped pairs output: $SSU_total_pairs")
    };

    $SSU_ratio = $SSU_total_pairs / $readnr_pairs;
    $SSU_ratio_pc = $SSU_ratio * 100;

    msg("mapping rate: $SSU_ratio_pc%");

    if ($SSU_total_pairs * 2 * $readlength < 1800) {
      msg("WARNING: mapping coverage lower than 1x,\n
      reconstruction with SPADES and Emirge disabled.");
      $skip_emirge = 1;
      $skip_spades = 1;
    }
}

sub bbmap_hitstats_parse {
    # create taxa list from hitmaps with at least 3 unambiguously mapping reads
    # input: lib.hitstats
    msg("creating taxon list from read mappings");

    my $fh;
    open_or_die(\$fh, "<", "$libraryNAME.hitstats");

    # hitstats format/example
    #name %unambiguousReads unambiguousMB %ambiguousReads ambiguousMB unambiguousReads ambiguousReads
    #X03680.934.2693 Eukaryota;Opistho[...]abditis elegans\t4,72750\t0,57297\t52,23750\t6,33119\t5673\t62685

    while (<$fh>) {
        chomp;

        # skip comments
        next if ($_ =~ /^#/);

        # space to tab in name: "<acc>.<start>.<stop> <taxpath>"
        s/(\w+\.\d+\.\d+)\s/$1\t/;

        my @hitstats_line = split ("\t", $_);

        # skip 0 unambiguousReads
        next if ($hitstats_line[6] == 0);

        # truncate materialized path taxonomy string to 6 levels
        my $taxonshortstring;
        my @taxonstringarray = split (";", $hitstats_line[1]);
        if ( $#taxonstringarray > 5 ) {
            $taxonshortstring = join (";", @taxonstringarray[0..5]);
        } else {
            $taxonshortstring = $hitstats_line[1];
        }

        # add to hash or increment existing count
        if ( !exists $taxa_from_hitmaps{$taxonshortstring} ) {
            $taxa_from_hitmaps{$taxonshortstring} = $hitstats_line[6];
        } else {
            $taxa_from_hitmaps{$taxonshortstring} += $hitstats_line[6];
        }

    }
    close($fh);

    @taxa_from_hitmaps_sorted =
        sort { @$b[1] <=> @$a[1] }
        grep { if (@$_[1] < 3) { @xtons[@$_[1]-1]++;} @$_[1] > 2 }
        map  { [$_, $taxa_from_hitmaps{$_}] }
        keys %taxa_from_hitmaps;

    $xtons[2] = $#taxa_from_hitmaps_sorted +1;

    if ($xtons[1] > 0) {
        $chao1 =
          $xtons[2] +
          ($xtons[0] * $xtons[0]) / 2 / $xtons[1];
    } else {
        $chao1 = 'n.d.';
    }
    msg("done...");
}

sub spades_run {
    # running SPADES on bbmap output
    msg("creating phylotypes with SPAdes");

    my $kmer;
    if ($readlength >= 134) {
        $kmer = "99,111,127";
    } else {
        my $spades_rl = $readlength - $readlength % 2; # drop to even number
        $kmer = ($spades_rl - 27).",".($spades_rl - 17).",".($spades_rl - 7);
    }
    msg ("kmers for SPAdes are ".$kmer);

    my $args;
    if ($sc == 1) {
      $args = '--sc ';
    }
    if ($SEmode == 1) {
        $args = $args."-s $libraryNAME.$readsf.SSU.1.fq";
    } else {
        $args = $args."-1 $libraryNAME.$readsf.SSU.1.fq -2 $libraryNAME.$readsf.SSU.2.fq";
    }

    run_prog("spades",
             "-o $libraryNAME.spades -t $cpus -m 20 -k $kmer "
             . $args,
             "$libraryNAME.spades.out","&1"
         );

    msg("done...");
}

sub spades_parse {
    # getting spades output and reformatting it...
    msg("getting SSU phylotypes and their coverages...");

    #spades scaffolds file is empty, settting skip_spades variable to avoid
    #further processing
    if (! -s "$libraryNAME.spades/scaffolds.fasta") {
        msg("no phylotypes assembled with SPAdes");
        $skip_spades = 1;
        system ("rm ./$libraryNAME.spades -r");
    }

    # run barrnap once for each domain
    # if single cell data - accept partial rRNAs down to 0.1
    # and use lower e-value setting
    my $b_args = " --evalue 1e-100 --reject 0.6 " ;
    if ($sc == 1) {
        $b_args = " --evalue 1e-20 --reject 0.1 ";
    }

    foreach ('bac', 'arch', 'euk') {
        run_prog("barrnap",
                 $b_args.
                 "--kingdom $_ --gene ssu --threads $cpus " .
                 "$libraryNAME.spades/scaffolds.fasta",
                 "$libraryNAME.scaffolds.$_.gff",
                 "$libraryNAME.barrnap.out");
    }

    # now merge multi-hits on the same scaffold-and-strand by picking
    # the lowest start and highest stop position.

    my %ssus;
    # pre-filter with grep for speed
    my $fh;
    open_or_die(\$fh, "-|",
                "grep -hE '16S_rRNA\|18S_rRNA' ".
                "$libraryNAME.scaffolds.bac.gff ".
                "$libraryNAME.scaffolds.arch.gff ".
                "$libraryNAME.scaffolds.euk.gff");
    while (my $row = <$fh>) {
        my @cols    = split("\t", $row);
        # gff format:
        # 0 seqname, 1 source, 2 feature, 3 start, 4 end,
        # 5 score, 6 strand, 7 frame, 8 attribute

        my $seqname = $cols[0];
        my $start   = $cols[3];
        my $stop    = $cols[4];
        my $strand  = $cols[6];

        # put our desired output fasta name into "feature" col 3
        # the may be "bug" using / mixing bed and gff formats
        # but it saves us messing with the fasta afterwards
        $seqname =~ m/NODE_([0-9]*)_.*cov_([0-9\\.]*)/;
        $cols[2] = "$libraryNAME.PFspades_$1_$2";

        # do the actual merging, left most start and right most stop wins
        if (exists $ssus{$seqname.$strand}) {
            my $old_start = $ssus{$seqname.$strand}[3];
            my $old_stop  = $ssus{$seqname.$strand}[4];
            $cols[3] = ($start < $old_start) ? $start : $old_start;
            $cols[4] = ($stop  > $old_stop)  ? $stop  : $old_stop;
        }
        $ssus{$seqname.$strand} = [@cols];
    }
    close($fh);

    if (scalar keys %ssus == 0) {
	msg("no contig in spades assembly found to contain rRNA");
	return;
    }

    open_or_die(\$fh, ">", "tmp.$libraryNAME.scaffolds.final.gff");
    for my $key (sort keys %ssus) {
        print $fh join("\t",@{$ssus{$key}});
    }
    close($fh);

    # fastaFromBed will build a .fai index from the source .fasta
    # However, it does not notice if the .fasta changed. So we
    # delete the .fai if it is older than the .fasta.
    if ( -e "$libraryNAME.spades/scaffolds.fasta.fai" &&
         file_is_newer("$libraryNAME.spades/scaffolds.fasta",
                       "$libraryNAME.spades/scaffolds.fasta.fai")) {
        unlink("$libraryNAME.spades/scaffolds.fasta.fai");
    }

    # extract rrna fragments from spades scaffolds accoding to gff
    run_prog("fastaFromBed",
             "  -fi $libraryNAME.spades/scaffolds.fasta "
             . "-bed tmp.$libraryNAME.scaffolds.final.gff "
             . "-fo $libraryNAME.spades_rRNAs.final.fasta "
             . "-s -name",
             "tmp.$libraryNAME.fastaFromBed.out",
             "&1");

    msg("done...");
}


sub emirge_run {
    # running Emirge on bbmap output
    msg("creating phylotypes with Emirge");

    my $cmd = "emirge";
    my $args = "-1 $libraryNAME.$readsf.SSU.1.fq ";

    if ($SEmode == 1) {
        msg("only one read file provided - running in single end mode");
    } elsif ($readlength < 152) {
        #long reads will hardly map with bowtie in paired end mode, using
        #forward+reverse reads combined as single read data when > 151bp
        msg("reads < 152 bp - running in paired end mode");

        # checking for too phyphysmall insert size
        msg("setting library insert size according to insert size distribution");
        # Calculate minimum insert size for emirge.
        my $min_ins = int(2.2 * $readlength + 0.5);
        if ($ins_me < $min_ins) {
            msg("Warning: estimated insert size very small: $ins_me, "
                . "using $min_ins instead");
            $ins_used = $min_ins;
        } else {
            $ins_used = $ins_me;
        }

        msg("the insert size used is $ins_used +- $ins_std");
        # FIXME: EMIRGE dies with too many SSU reads, the cutoff needs to be adjusted...
        if ($SSU_total_pairs <= $amplimit) {
            msg("Less than $amplimit SSU read pairs - using Emirge");
        } else {
            $cmd = "emirge_amp";
            msg("Warning: More than $amplimit SSU reads - using Emirge Amplicon");
        }

        $args = "  -1 $libraryNAME.$readsf.SSU.1.fq "
                . "-2 $libraryNAME.$readsf.SSU.2.fq "
                . "-i $ins_used -s $ins_std ";
    } else {
        msg("reads > 151 bp - running in single end mode");
        run_prog("cat",
                 "$libraryNAME.$readsf.SSU.1.fq $libraryNAME.$readsf.SSU.2.fq",
                 "tmp.$libraryNAME.SSU_all.fq");
        # ename the reads with a running number to make emirge happy
        # using awk for speed, these files can be huge

        run_prog("awk",
                 "\'{print (NR%4 == 1) ? \"\@\" ++i  : (NR%4 == 3) ? \"+\" :\$0}\'"
                 . " tmp.$libraryNAME.SSU_all.fq",
                 "tmp.$libraryNAME.renamed.SSU_all.fq");

        $args = " -1 tmp.$libraryNAME.renamed.SSU_all.fq ";
    }

    run_prog($cmd,
             " $libraryNAME.emirge "
             . $args
             . " -f ${DBHOME}/${emirge_db}.fasta"
             . " -b ${DBHOME}/${emirge_db}.bt "
             . " -l $readlength -a $cpus --phred33 ",
             , "$libraryNAME.emirge.out", "&1");

    msg("done...");
}

sub emirge_parse {
    # getting emirge output and reformatting it...
    msg("getting Emirge phylotypes and their abundances...");
    run_prog("emirge_rename_fasta",
             "./$libraryNAME.emirge/iter.40/",
             "tmp.$libraryNAME.emirge.result.fasta");

    my $fh_in;
    my $fh_out;
    open_or_die(\$fh_in, "<","tmp.$libraryNAME.emirge.result.fasta");
    open_or_die(\$fh_out, ">", "$libraryNAME.emirge.final.fasta");
    while (<$fh_in>) {
        chomp;
        if ($_ =~ />(\d*)\|.*NormPrior=([\d.]*)/ ) {
            print {$fh_out} ">$libraryNAME.PFemirge_".$1."_".$2."\n";
        } else {
            print {$fh_out} $_."\n";
        }
    }
    close($fh_in);
    close($fh_out);

    msg("done...");
}

sub vsearch_best_match {
    # running vsearch to map the SPADES output to the taxonomy
    msg("searching for DB matches with vsearch");

    # join emirge and spades hits into one file
    # (vsearch takes a while to load, one run saves us time)
    if ($skip_spades == 1 && $skip_emirge == 0) {
      run_prog("cat",
               "   $libraryNAME.emirge.final.fasta",
               "$libraryNAME.all.final.fasta");
    }
    elsif ($skip_emirge == 1 && $skip_spades == 0){
      run_prog("cat",
               "   $libraryNAME.spades_rRNAs.final.fasta",
               "$libraryNAME.all.final.fasta");
    }
    elsif ($skip_emirge == 0 && $skip_spades == 0){
      run_prog("cat",
             "   $libraryNAME.emirge.final.fasta"
             . " $libraryNAME.spades_rRNAs.final.fasta",
             "$libraryNAME.all.final.fasta");
    }

    if (-s "$libraryNAME.all.final.fasta") {
       run_prog("vsearch",
             "-usearch_global $libraryNAME.all.final.fasta "
             . "-db ${DBHOME}/${vsearch_db}.fasta "
             . "-id 0.7 "
             . "-userout $libraryNAME.all.vsearch.csv "
             . "-userfields query+target+id+alnlen+evalue+id3+qs+pairs+gaps+mism+ids "
             . "-threads $cpus --strand plus --notrunclabels "
             . "-notmatched $libraryNAME.all.final.phyloFlash.notmatched.fa "
             . "-dbmatched $libraryNAME.all.final.phyloFlash.dbhits.fa ",
             "tmp.$libraryNAME.all.vsearch.out",
             "&1");

       # query, target: labels
       # id: "100* matching colums / (alignment length - terminal gaps)"
       # alnlen: "number of alignment columns"
       # id3: "MBL definition of %id - counting each extended gap as single difference"
       # qs: query segment length
       # pairs: # letter pair cols
       # gaps: # gap cols
       # mism: # mismatches
       # ids: # matches
    }
}

sub vsearch_parse {
    my @vsearch_matches;            # list of vsearch best-match results

    # Parse the output from Vsearch and store in the hash %SSU_assembly
    my $fh;
    open_or_die(\$fh, "<", "$libraryNAME.all.vsearch.csv");
    while (<$fh>) {
        chomp;
        # lib.PFspades_1_1.23332\tAH12345.1.1490 Bacteria;...\t...
        s/PF(\w+)_([^_]+)_([^\t]+)\t(\w+\.\d+\.\d+)\s/PF$1_$2\t$3\t$4\t/;
        push @vsearch_matches, [split("\t",$_)];
    }
    close($fh);

    # Sort numerically descending the list of
    # assembled SSU sequences by coverage value

    @ssuassem_results_sorted =
        sort { @{$b}[1] <=> @{$a}[1] or @{$a}[3] cmp @{$b}[3] }
        grep { @{$_}[0] =~ /^$libraryNAME.PFspades/ }
        @vsearch_matches;

    # Sort numerically descending the list of reconstructed
    # SSU sequences by mapping ratio
    @ssurecon_results_sorted =
        sort { @{$b}[1] <=> @{$a}[1] or @{$a}[3] cmp @{$b}[3] }
        grep { @{$_}[0] =~ /^$libraryNAME.PFemirge/ }
        @vsearch_matches;

    msg("done...");
}

sub vsearch_cluster {
    my $clusterid = 97;
    msg("clustering DB matches at $clusterid%");
    run_prog("vsearch",
             "  --cluster_fast $libraryNAME.all.final.phyloFlash.dbhits.fa "
             . "-id ".($clusterid/100)." "
             . "-centroids $libraryNAME.all.dbhits.NR97.fa "
             . "-notrunclabels "
             . "--threads $cpus ",
             "tmp.$libraryNAME.clusterdbhits.out",
             "&1");

    msg("done...");
}

sub mafft_run {
    msg("creating alignment and tree...");

    if ($skip_spades == 0 && $skip_emirge == 1) {
        run_prog("cat",
                 "$libraryNAME.all.dbhits.NR97.fa "
                 . "$libraryNAME.spades_rRNAs.final.fasta ",
                 "$libraryNAME.SSU.collection.fasta");

    } elsif ($skip_spades == 1 && $skip_emirge == 0) {
        run_prog("cat",
                 "$libraryNAME.all.dbhits.NR97.fa "
                 . "$libraryNAME.emirge.final.fasta ",
                 "$libraryNAME.SSU.collection.fasta");

    } elsif ($skip_spades == 0 && $skip_emirge == 0) {
        run_prog("cat",
                 "$libraryNAME.all.dbhits.NR97.fa "
                 . "$libraryNAME.spades_rRNAs.final.fasta "
                 . "$libraryNAME.emirge.final.fasta ",
                 "$libraryNAME.SSU.collection.fasta");
    }

    run_prog("mafft",
             "--treeout $libraryNAME.SSU.collection.fasta ",
             "$libraryNAME.SSU.collection.alignment.fasta",
             "tmp.$libraryNAME.SSU.collection.alignment.mafftout");

    # fix missing ; at and of MaFFT newick tree
    my $fh;
    open_or_die(\$fh, ">>", "$libraryNAME.SSU.collection.fasta.tree");
    print {$fh} ";";
    close($fh);

    msg("done...");
}

sub clean_up {
    # cleanup of intermediate files and folders
    msg("cleaning temp files...");
    if ($skip_spades == 0) {
        system ("rm ./$libraryNAME.spades -r");
    }
    if ($skip_emirge == 0) {
        system ("rm ./$libraryNAME.emirge -r");
    }
    system ("rm tmp.$libraryNAME.* -r");
    msg("done...");
}

sub run_plotscript {
    msg("generating histogram and tree graphics");
    my $inshist = "$libraryNAME.inserthistogram"; # Name of insert histogram file
    if ($SEmode==1) { # If running in SE mode ...
      $inshist="SEmode"; # ... replace name of ins histogram file with "SEmode"
    }
    #FIXME: crashes if .inserthistorgram contains no lines
    if ($skip_spades + $skip_emirge == 2) {
        run_prog("plotscript",
                 "--args NULL "
                 . "$inshist "
                 . "$libraryNAME.idhistogram "
                 . "$decimalcomma ",
                 "tmp.$libraryNAME.plotscript.out",
                 "&1");
    }
    else {
        run_prog("plotscript",
                 "--args $libraryNAME.SSU.collection.fasta.tree "
                 . "$inshist "
                 . "$libraryNAME.idhistogram "
                 . "$decimalcomma ",
                 "tmp.$libraryNAME.plotscript.out",
                 "&1");
    }
}

sub generate_treemap_data_rows {
  # Generate data rows for drawing treemap chart
  my %parents_HoH; # Hash of count vals by parent and child taxa
  my @output; # Array to store output
  # Parse taxstrings into hash of child-parent relationships

  foreach my $taxstring (keys %taxa_from_hitmaps) {
    my @taxsplit = split ";", $taxstring; # Get taxonomy string, split by semicolons
    my $taxlen = scalar @taxsplit; # Get length of tax string
    while (scalar @taxsplit > 1) {
      my $countval = 0; # Initialize count value as dummy "zero" by default
      if (scalar @taxsplit == $taxlen) { # If leaf node, set count value to real value
          $countval = $taxa_from_hitmaps{$taxstring};
      }
      my $child_taxstring = join ";", @taxsplit;
      my $dummy = pop @taxsplit; # Get parent node
      my $parent_taxstring = join ";", @taxsplit;
      # Remove non-word and non-semicolon chars to avoid problems with Javascript
      $child_taxstring =~ s/[^\w;_]/_/g;
      $parent_taxstring =~ s/[^\w;_]/_/g;
      # Update the parent-child hash if this taxon not already represented
      if (!exists $parents_HoH{$parent_taxstring}{$child_taxstring}) {
        $parents_HoH{$parent_taxstring}{$child_taxstring} = $countval;
      }
    }  
  }
  
  # Write output in dataRow format for treemap chart
  # Root and top-level taxa
  push @output, "[\'Cellular organisms\',\t,\t0],\n";
  push @output, "[\'Bacteria\',\t\'Cellular organisms\',\t0],\n";
  push @output, "[\'Archaea\',\t\'Cellular organisms\',\t0],\n";
  push @output,"[\'Eukaryota\',\t\'Cellular organisms\',\t0],\n";
  # Go through sorted hash and write parent-child data rows
  foreach my $parent (sort {$a cmp $b} keys %parents_HoH) {
    foreach my $child (sort {$a cmp $b} keys %{$parents_HoH{$parent}}) {
      # Concatenate output as string
      my $outstring = "[\'".$child."\',\t\'".$parent."\',\t".$parents_HoH{$parent}{$child}."],\n";
      push @output, $outstring;
      }
  }
  # Return array of output lines
  return @output;
}

sub write_report_html {
    # Generate HTML-formatted report file -- lots of blocks of verbatim HTML
    # in this section
    msg("Generating HTML-formatted report and graphics...");

    my $fh;
    open_or_die(\$fh, ">", "$libraryNAME.phyloFlash.html");

    print {$fh} <<ENDHTML;
<!DOCTYPE html>
<html>
<head>
ENDHTML

print {$fh} "  <title>phyloFlash results summary for library ".$libraryNAME."</title>\n";

print {$fh} <<ENDHTML;
  <script language="javascript" type="text/javascript">
  // adapted from http://www.cssnewbie.com/example/showhide-content/
  function showHide(shID) {
    if (document.getElementById(shID)) {
      if (document.getElementById(shID).style.display == 'none') {
        document.getElementById(shID).style.display = 'block';
      }
      else {
        document.getElementById(shID).style.display = 'none';
      }
    }
  }
  </script>
ENDHTML

if ($treemap_flag == 1) { # Script for interactive treemap if flag is on
print {$fh} <<ENDHTML;
  <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
  <script type="text/javascript">
  google.charts.load('current', {'packages':['treemap']});
  google.charts.setOnLoadCallback(drawChart);
  function drawChart() {
    var data = new google.visualization.DataTable();
    data.addColumn('string','ID');
    data.addColumn('string','Parent');
    data.addColumn('number','NumReads');
    data.addRows([
ENDHTML
my @output_array = generate_treemap_data_rows();
while (scalar @output_array > 0) {
  print {$fh} shift @output_array;
}
print {$fh} <<ENDHTML;
    ]);

    tree = new google.visualization.TreeMap(document.getElementById('chart_div'));

    tree.draw(data, {
      minColor: '#009688',
      midColor: '#f7f7f7',
      maxColor: '#ee8100',
      highlightOnMouseOver: true,
      minHighlightColor: '#ee8100',
      midHighlightColor: '#f7f7f7',
      maxHighlightColor: '#009688',
      maxPostDepth: 2,
      headerHeight: 15,
      fontColor: 'black',
      showScale: false,
      generateTooltip: showFullTooltip
    });
    
    function showFullTooltip(row,size,value) {
      return '<div style="background:white; padding:10px; border-style:none">' +
      '<b>' + data.getValue(row, 0) + '</b><br>' +
      'Total reads: ' + size + '</div>';
    }

  }
</script>
ENDHTML
}

print {$fh} <<ENDHTML;
  <style type="text/css">
    body {
      font-family: "Helvetica", "Gill Sans", "Gill Sans MT", sans-serif;}

    th {
      background-color: #dee;
      padding: .5em .5em .5em .5em;
      font-weight: bold;}
    td {
      padding: 0em .5em 0em .5em;}

    table.slimTable th {
      padding: 0em .5em 0em .5em;
      font-weight: normal;
      text-align: right;}

    .withHoverText {
      text-decoration: none;
      border-bottom: 1px grey dotted;}

    .more {
      display: none;}
    a.showLink {
      text-decoration: none;}
    a.showLink:link {
      color: grey;}
    a.showLink:visited {
      color: grey;}
    a.showLink:hover {
      color: white;
      background-color: grey;}

  </style>
</head>
<body>

<h3><a href="https://github.com/HRGV/phyloFlash">
ENDHTML
print {$fh} $version; # Print phyloFlash name and version number
print {$fh} <<ENDHTML;
 </a> by <a href="mailto:hgruber\@mpi-bremen.de">Harald Gruber-Vodicka</a> - high throughput phylogenetic screening using SSU rRNA gene(s) abundance(s)</h3>
 <p>Click on report section headers to expand, mouse-over underlined text to see explanations.</p>
ENDHTML

print {$fh} "<h1>Library name: ".$libraryNAME."</h1>\n";

print {$fh} <<ENDHTML;
<h2>Parameters</h2>

<h3>Input files</h3>
<table class="slimTable">
  <tr>
    <th>Forward read file</th>
ENDHTML

print {$fh} "    <td>".$readsf_full."</td>\n";

print {$fh} <<ENDHTML;
  </tr>
  <tr>
    <th>Reverse read file</th>
ENDHTML

print {$fh} "    <td>".$readsr_full."</td>\n";

print {$fh} <<ENDHTML;
  </tr>
</table>

<h3>Mapping parameters</h3>
<table class="slimTable">
  <tr>
    <th><span class="withHoverText" title="Minimum sequence identity for mapping to SSU database to be accepted">Minimum mapping identity</span></th>
ENDHTML

print {$fh} "    <td>".$id."\%</td>\n";
if ($SEmode == 0) {
print {$fh} <<ENDHTML;
  </tr>
  <tr>
    <th>Input PE-reads</th>
ENDHTML

print {$fh} "    <td>".$readnr_pairs."</td>\n";

print {$fh} <<ENDHTML;
  </tr>
  <tr>
    <th>Mapped SSU read pairs</th>
ENDHTML

print {$fh} "    <td>".$SSU_total_pairs."</td>\n";
} else
{
print {$fh} <<ENDHTML;
  </tr>
  <tr>
    <th>Input SE-reads</th>
ENDHTML

print {$fh} "    <td>".$readnr."</td>\n";

print {$fh} <<ENDHTML;
  </tr>
  <tr>
    <th>Mapped SSU SE-reads</th>
ENDHTML

print {$fh} "    <td>".$SSU_total_pairs."</td>\n";
}
print {$fh} <<ENDHTML;
  </tr>
  <tr>
    <th><span class="withHoverText" title="Fraction of library mapping to SSU references">Mapping ratio</span></th>
ENDHTML

print {$fh} "    <td>".$SSU_ratio_pc."\%</td>\n";
print {$fh} <<ENDHTML;
  </tr>
ENDHTML
if ($SEmode==0) { # Only print insert size information if in paired-end mode
print {$fh} <<ENDHTML;
  <tr>
    <th>Detected median insert size</th>
ENDHTML

print {$fh} "    <td>".$ins_me."</td>\n";
print {$fh} <<ENDHTML;
  </tr>
ENDHTML

if ($skip_emirge == 0) {
print {$fh} <<ENDHTML;
  <tr>
    <th>Used insert size</th>
ENDHTML

print {$fh} "     <td>".$ins_used."</td>\n";
print {$fh} <<ENDHTML;
  </tr>
ENDHTML
}

print {$fh} <<ENDHTML;
  <tr>
    <th>Insert size standard deviation</th>
ENDHTML

print {$fh} "    <td>".$ins_std."</td>\n";
print {$fh} <<ENDHTML;
  </tr>
ENDHTML
}
print {$fh} <<ENDHTML;
</table>
ENDHTML

if ($SEmode==0) { # Only display insert size histogram if in paired-end mode
print {$fh} <<ENDHTML;
<h3><a href="#" id="histo-show" class="showLink" onclick="showHide('histo');return false;" title="Click to expand">Insert size histogram</a></h3>
<div id="histo" class="more">
<p>Insert sizes for read pairs. Distribution should generally be unimodal; more than one peak may indicate contamination from other libraries.</p>
ENDHTML

print {$fh} "<img width=660 height=480 src=\"".$libraryNAME.".inserthistogram.png\" />\n";
print {$fh} "<p><a href=\"".$libraryNAME.".inserthistogram.pdf\">PDF version</a></p>\n";
print {$fh} <<ENDHTML;
</div>
ENDHTML
}

print {$fh} <<ENDHTML;

<h3><a href="#" id="idhisto-show" class="showLink" onclick="showHide('idhisto');return false;" title="Click to expand">Mapping identity histogram</a></h3>
<div id="idhisto" class="more">
<p>Read-mapping %identity of reads vs. reference database. Lower %identity hits may indicate presence of divergent taxa not represented in the database.</p>
ENDHTML

print {$fh} "<img width=660 height=480 src=\"".$libraryNAME.".idhistogram.png\" />\n";
print {$fh} "<p><a href=\"".$libraryNAME.".idhistogram.pdf\">PDF version</a></p>\n";
print {$fh} <<ENDHTML;
</div>

<h3>Output files</h3>
<table class="slimTable">
ENDHTML

print {$fh} "  <tr>\n";
print {$fh} "    <th>PhyloFlash report (plaintext)</th>\n";
print {$fh} "    <td>".$libraryNAME.".phyloFlash</td>\n";
print {$fh} "  </tr>\n";

print {$fh} "  <tr>\n";
print {$fh} "    <th>PhyloFlash report (HTML)</th>\n";
print {$fh} "    <td>".$libraryNAME.".phyloFlash.html</td>\n";
print {$fh} "  </tr>\n";

if ($SEmode==0) { # Only dislpay insert size information if in paired-end mode
print {$fh} "  <tr>\n";
print {$fh} "    <th>Insert size histogram (plaintext)</th>\n";
print {$fh} "    <td>".$libraryNAME.".inserthistogram</td>\n";
print {$fh} "  </tr>\n";

print {$fh} "  <tr>\n";
print {$fh} "    <th>Insert size histogram (graphics)</th>\n";
print {$fh} "    <td>".$libraryNAME.".inserthistogram.png or .pdf</td>\n";
print {$fh} "  </tr>\n";
}

print {$fh} "  <tr>\n";
print {$fh} "    <th>Mapping identity histogram (plaintext)</th>\n";
print {$fh} "    <td>".$libraryNAME.".idhistogram</td>\n";
print {$fh} "  </tr>\n";

print {$fh} "  <tr>\n";
print {$fh} "    <th>Mapping identity histogram (graphics)</th>\n";
print {$fh} "    <td>".$libraryNAME.".idhistogram.png or .pdf</td>\n";
print {$fh} "  </tr>\n";

if ($skip_spades + $skip_emirge < 2) {

print {$fh} "  <tr>\n";
print {$fh} "    <th>Tree of recovered SSU sequences (Newick)</th>\n";
print {$fh} "    <td>".$libraryNAME.".SSU.collection.fasta.tree</td>\n";
print {$fh} "  </tr>\n";

print {$fh} "  <tr>\n";
print {$fh} "    <th>Tree of recovered SSU sequences (graphics)</th>\n";
print {$fh} "    <td>".$libraryNAME.".SSU.collection.fasta.tree.png or .pdf</td>\n";
print {$fh} "  </tr>\n";

}

print {$fh} <<ENDHTML;
</table>

<h2>Results</h2>
ENDHTML

if ($treemap_flag == 1) { # Display interactive treemap if flag is on
print {$fh}<<ENDHTML;
<h3>Interactive treemap of mapping-based taxonomic read classification</h3>
    <p><b>Navigation</b>: Left-click to go down, right-click to go up in taxonomic hierarchy, hover to see counts.</p>
    <p>Based on read-mapping hits to reference database, provides an approximate overview of taxonomic composition.</p>
    <div id="chart_div" style="width: 900px; height: 500px;"></div>
    <p>Drawn with Google Visualization API (<a href="https://developers.google.com/chart/terms">terms of service</a>)</p>
ENDHTML
}

print {$fh} <<ENDHTML;
<h3><a href="#" id="taxa-show" class="showLink" onclick="showHide('taxa');return false;">Read mapping based detected higher taxa in order of appearance (min. 3 reads mapped)</a></h3>
<div id="taxa" class="more">
<p>Based on read-mapping hits to reference database, provides an approximate overview of taxonomic composition.</p>
<table>
  <tr>
    <th><span class="withHoverText" title="Higher taxon found by SSU mapping to reference database">Taxon</span></th>
    <th><span class="withHoverText" title="No. reads mapped unambiguously to this taxonomic group">Unambig maps</span></th>
  </tr>
ENDHTML

## write list of higher taxa found
foreach my $taxonshortstring ( @taxa_from_hitmaps_sorted ) {
    # For each of these higher taxa
    print {$fh} "  <tr>\n";
    # print name of taxon
    print {$fh} "    <td>".@$taxonshortstring[0]."</td>\n";
    # print no . of reads mapping unambiguously
    print {$fh} "    <td>".@$taxonshortstring[1]."</td>\n";
    print {$fh} "  </tr>\n";
}

print {$fh} <<ENDHTML;
</table>
</div>
ENDHTML

if ($skip_spades == 0) {
## write list of assembled SSU sequences
print {$fh} <<ENDHTML;
<h3><a href="#" id="spades-show" class="showLink" onClick="showHide('spades');return false;">SSU assembly based taxa</a></h3>
<div id="spades" class="more">
<table>
  <tr>
    <th><span class="withHoverText" title="Name assigned to assembled SSU sequence">OTU</span></th>
    <th><span class="withHoverText" title="Per-base coverage of assembled SSU sequence, from assembler">coverage</span></th>
    <th><span class="withHoverText" title="Closest hit in SSU reference database">dbHit</span></th>
    <th>taxonomy</th>
    <th>\%id</th>
    <th><span class="withHoverText" title="Length of pairwise alignment between assembled SSU sequence and reference">alnlen</span></th>
    <th>evalue</th>
  </tr>
ENDHTML

foreach (@ssuassem_results_sorted) {
    my @split_entry = @$_;
    my @get_genbank = split (/\./,$split_entry[2]);
        # Parse the database entry number of the reference sequence to get Genbank accession
    print {$fh} "  <tr>\n";
    print {$fh} "    <td>".$split_entry[0]."</td>\n";
    print {$fh} "    <td>".$split_entry[1]."</td>\n";
    print {$fh} "    <td><a href=\"http://www.ncbi.nlm.nih.gov/nuccore/".$get_genbank[0]."\">".$split_entry[2]."</a></td>\n";	# Link to Genbank entry using accession no.
    #	print {$fh} "    <td>".$split_entry[2]."</td>\n";
    print {$fh} "    <td>".$split_entry[3]."</td>\n";
    print {$fh} "    <td>".$split_entry[4]."</td>\n";
    print {$fh} "    <td>".$split_entry[5]."</td>\n";
    print {$fh} "    <td>".$split_entry[6]."</td>\n";
    print {$fh} "  </tr>\n";
}
}

if ($skip_emirge == 0) {
## write list of reconstructed SSU sequences
print {$fh} <<ENDHTML;
</table>
</div>

<h3><a href="#" id="emirge-show" class="showLink" onclick="showHide('emirge');return false;">SSU reconstruction based taxa</a></h3>
<div id="emirge" class="more">
<table>
  <tr>
    <th>OTU</th>
    <th>ratio</th>
    <th>dbHit</th>
    <th>taxonomy</th>
    <th>\%id</th>
    <th>alnlen</th>
    <th>evalue</th>
  </tr>
ENDHTML

foreach (@ssurecon_results_sorted) {
    print {$fh} "  <tr>\n";
    my @split_entry = @$_;
    my $test = $split_entry[2];
    my @get_genbank = split (/\./,$test);
    print {$fh} "    <td>".$split_entry[0]."</td>\n";
    print {$fh} "    <td>".$split_entry[1]."</td>\n";
    print {$fh} "    <td><a href=\"http://www.ncbi.nlm.nih.gov/nuccore/".$get_genbank[0]."\">".$split_entry[2]."</a></td>\n";
#	print {$fh} "    <td>".$split_entry[2]."</td>\n";
    print {$fh} "    <td>".$split_entry[3]."</td>\n";
    print {$fh} "    <td>".$split_entry[4]."</td>\n";
    print {$fh} "    <td>".$split_entry[5]."</td>\n";
    print {$fh} "    <td>".$split_entry[6]."</td>\n";
    print {$fh} "  </tr>\n";
}
}

if ($skip_spades + $skip_emirge < 2) {
print {$fh} <<ENDHTML;
</table>
</div>
<h3><a href="#" id="tree-show" class="showLink" onclick="showHide('tree');return false;">Combined tree of sequences</a></h3>
<div id="tree" class="more">
ENDHTML

print {$fh} "<img src=\"".$libraryNAME.".SSU.collection.fasta.tree.png\" />\n";
print {$fh} "<p><a href=\"".$libraryNAME.".SSU.collection.fasta.tree.pdf\">PDF version</a></p>\n";
}

print {$fh} <<ENDHTML;
</div>
<h4>Please cite...</h4>
<p>List of citations including dependencies</p>
</body>
</html>
ENDHTML

close($fh);
}

######################### MAIN ###########################
welcome();
parse_cmdline();
process_required_tools();
check_environment();

my $timer = new Timer;

bbmap_fast_filter_run();
bbmap_fast_filter_parse();
bbmap_hitstats_parse();
if ($skip_spades == 0) {  # Run SPAdes if not explicitly skipped
    spades_run();
    spades_parse();
}
if ($skip_emirge == 0) {  # Run Emirge if not explicitly skipped
    emirge_run();
    emirge_parse();
}
if ($skip_spades + $skip_emirge < 2) {  # If at least one of either SPAdes or Emirge is activated, parse results
    vsearch_best_match();
    vsearch_parse();
    vsearch_cluster();
    mafft_run();
}

$runtime = $timer->minutes;

print_report();
write_csv();
run_plotscript()    if ($html_flag);
write_report_html() if ($html_flag);
clean_up();

msg("Walltime used: $runtime with $cpus CPU cores");
msg("Thank you for using phyloFlash
You can find your results in $libraryNAME.*,
Your main result file is $libraryNAME.phyloFlash");
