package Bio::MUST::Drivers::Blast::Query;
# ABSTRACT: internal class for BLAST driver
$Bio::MUST::Drivers::Blast::Query::VERSION = '0.173510';
use Moose;
use namespace::autoclean;

use autodie;
use feature qw(say);

# use Smart::Comments;

use Carp;
use File::Temp;
use IPC::System::Simple qw(system);

use Bio::MUST::Core 0.153360;
extends 'Bio::MUST::Core::Ali::Temporary';

use Bio::MUST::Drivers::Utils qw(stringify_args);
use aliased 'Bio::FastParsers::Blast::Table';
use aliased 'Bio::FastParsers::Blast::Xml';


# TODO: avoid hard-coded convenience methods?

sub blastn {                                ## no critic (RequireArgUnpacking)
    my $self = shift;
    return $self->_blast('blastn', @_);
}

sub blastp {                                ## no critic (RequireArgUnpacking)
    my $self = shift;
    return $self->_blast('blastp', @_);
}

sub blastx {                                ## no critic (RequireArgUnpacking)
    my $self = shift;
    return $self->_blast('blastx', @_);
}

sub tblastn {                               ## no critic (RequireArgUnpacking)
    my $self = shift;
    return $self->_blast('tblastn', @_);
}

sub tblastx {                               ## no critic (RequireArgUnpacking)
    my $self = shift;
    return $self->_blast('tblastx', @_);
}

my %pgm_for = (             # cannot be made constant to allow undefined keys
	'nucl:nucl' =>  'blastn',
	'nucl:prot' =>  'blastx',
	'prot:prot' =>  'blastp',
	'prot:nucl' => 'tblastn',
);

sub blast {                                 ## no critic (RequireArgUnpacking)
    my $self = shift;
    my $db   = shift;

    # auto-select BLAST program based on query/database type
    my $pgm = $pgm_for{ $self->type . ':' . $db->type };
    croak 'Error: Cannot get -db_type for ' . $db->filename . '; aborting!'
        unless $pgm;

    return $self->_blast($pgm, $db, @_);
}

sub _blast {
    my $self = shift;
    my $pgm  = shift;
    my $db   = shift;
    my $args = shift // {};

    ### $pgm
    ### $args

    # setup output file and output format
    # Note: only tabular, XML and HTML outputs are allowed
    # if specified -html takes precedence on -outfmt
    my $suffix = ".$pgm";
    if (exists $args->{-html}) {
        $suffix .= '.html';
        delete $args->{-outfmt};            # enforce precedence policy
    }
    else {
        unless (defined $args->{-outfmt} && $args->{-outfmt} =~ m/[567]/xms) {
            carp 'Warning: no valid -outfmt specified; defaulting to tabular!';
            $args->{-outfmt} = 6;
        }
    }
    my $out = File::Temp->new(UNLINK => 0, EXLOCK => 0, SUFFIX => $suffix);

    # automatically setup remote BLAST based on database "class"
    $args->{-remote} = undef if $db->remote;

    # format BLAST (optional) arguments
    $args->{-query} = $self->filename;
    $args->{-db}    =   $db->filename;
    $args->{-out}   =  $out->filename;
    my $args_str = stringify_args($args);

    # create BLAST command
    my $cmd = join q{ }, $pgm, $args_str, '> /dev/null 2> /dev/null';
    ### $cmd

    # try to robustly execute BLAST
    my $ret_code = system( [ 0, 127 ], $cmd);
    if ($ret_code == 127) {
        carp "Warning: cannot execute $pgm command; returning without parser!";
        return;
    }

    # return Bio::FastParsers::Blast of the right subclass
    # depending on the output format (XML or tabular)
    # or the Path::Class::File of the report for HTML output
    return exists $args->{-html} ?                    $out->filename  :
           $args->{-outfmt} == 5 ?   Xml->new(file => $out->filename) :
                                   Table->new(file => $out->filename)
    ;

    # TODO: devise a way to unlink report without affecting parsing
    # should be an option of the FastParsers?
}

__PACKAGE__->meta->make_immutable;
1;

__END__

=pod

=head1 NAME

Bio::MUST::Drivers::Blast::Query - internal class for BLAST driver

=head1 VERSION

version 0.173510

=head1 SYNOPSIS

    # TODO

=head1 DESCRIPTION

    # TODO

=head1 AUTHOR

Denis BAURAIN <denis.baurain@uliege.be>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2013 by University of Liege / Unit of Eukaryotic Phylogenomics / Denis BAURAIN.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut
