#!/usr/bin/perl
# 
# convertTaxonomyFile.pl -- given one of Ashley's taxonomy files for clustered
#              sequence data, prepare it for bestTaxonomy script.
#               
# Input format: 
#        # comment line
#        #otuId:  otu1,otu2, ... ,otun,Kingdom,Phylum,Class, Order, Family, Genus, Species
#        seqId1,otu1#,otu2#, ... otun#,k__name,p__name, ... , s__name
#        seqId2,otu1#,otu2#, ... otun#,k__name,p__name, ... , s__name
#        ...
#     Not all taxonomic name fields need be present.
#     Some taxonomic names are degenerate; p__
#             degenerate names need to be deleted
#
# Output format
#  header   |seqId, database, Kingdom, Phylum, Class, Order, Family, Genus, Species  
#  data     |seqid, dbId, k__name, p__name, c__name, o__name, g__name, s__name
#
# 07/21/13 rdb: created
# 07/22/13 v. 0.1 sent to Ashley on 7/23
#

#------------------------------------------------------------------------------------
use strict;
use warnings;

my $usageMsg = q( Usage:  convertTaxonomyFile.pl dbId in.csv [out.tax]  
        where in.csv is a comma-separated file with otu data and taxonomy data
              out.csv will be the taxonomy data only with addition of the dbId
                if out.csv is not specified, outputfile will be named:
                     in.tax
);
                
#--------------------- main --------------------------------------------
if ( @ARGV < 2 || $ARGV[ 0 ] eq "-h" )
{
  die "$usageMsg\n";
}

my $dbId = $ARGV[ 0 ];
my $inFile = $ARGV[ 1 ];
my $outFile = $ARGV[ 2 ];

if ( !defined( $outFile ) )
{
    $outFile = $inFile;
    $outFile =~ s/^(.*)\..*/$1.tax/;
}

open IN, $inFile or die "Unable to open input: $inFile";
open OUT, ">$outFile" or die "Unable to open output file: $outFile";

# start header with 2 fields not in the input file
my $header = "seqId, database";
my $otuCount = 0;

# As incredible as it  may be, Excel "save as csv" on Macs, still generates
#   carriage returns (CR) as end of line instead of line feeds (LF); the
#   simplest way to handle this is to read the entire file at once and
#   replace all CR with LF
my @lines = <IN>;   # Note: there will only be 1 line if this file uses CR
if ( @lines <= 1 )
{
    $lines[ 0 ] =~ s/\r/\n/g;
    @lines = split( '\n', $lines[ 0 ] );
}

# Now process each line in the file
foreach my $line ( @lines )
{
    chomp $line;
    if ( substr( $line, 0, 1 ) eq "#" )
    {
        if ( $line =~ /Kingdom/ )   # this is the header
        {
            my ( $data, $hdr ) = $line =~ /^(.*),(Kingdom.*)/; # extract parts
            my @otuFields = split( ",", $data );
            $otuCount = @otuFields - 1;  # first field is "#OtuID
            $header = "$header, $hdr";
            print OUT "$header\n";
        }
    }
    else
    {
        my ( $seqId, @fields ) = split( ",", $line );
        my @taxonFields = splice( @fields, $otuCount );
        # check for empty fields and degenerate names
        # do this by "popping" the array as long as an empty field
        #   or degenerate name is in it. As soon as we get a good
        #   name, we push it back on and we are done; we assume
        #   that once we get a good name, the higher order names are good.
        
        my $lastName = pop( @taxonFields );
        while ( $lastName
               && ( length( $lastName ) == 0 || $lastName =~ /__\s*$/ ))
        {
            $lastName = pop( @taxonFields );
        }
        if ( $lastName )
        {
            push( @taxonFields, $lastName );
        }
    
        my $outLine = join( ", ", ($seqId, $dbId, @taxonFields ));
        print OUT "$outLine\n";
    }
}
