#!/usr/local/ensembl/bin/perl -w 

use strict;
use Bio::EnsEMBL::Pipeline::DBSQL::DBAdaptor;
use Bio::EnsEMBL::Pipeline::Analysis;
use Getopt::Long;
use Bio::EnsEMBL::Utils::Exception qw(verbose throw warning info);

my $dbhost;
my $dbuser;
my $dbpass = '';
my $dbport = 3306;
my $dbname;
my $input_id;
my $logic_name;
my $check  = 0;
my $output_dir;
my $write = 0;
my $help = 0; 
my $verbose = 0;
my $update = 0;
my $input_type;
my $module;
my $analysis;
my $perl_path = 'Bio/EnsEMBL/Pipeline/RunnableDB';
my $utils_verbosity = 'WARNING'; #how verbose do you want the 
#Bio::EnsEMBL::Utils::Exceptions module to be by default it is set to
#WARNING as this gives warning and throws but not deprecates or infos
my @command_args = @ARGV;
&GetOptions( 
            'dbhost=s'      => \$dbhost,
            'dbname=s'      => \$dbname,
            'dbuser=s'      => \$dbuser,
            'dbpass=s'      => \$dbpass,
            'dbport=s'      => \$dbport,
            'input_id:s'  => \$input_id,
            'analysis|logic_name:s'  => \$logic_name,
            'check'       => \$check,
            'write!' => \$write,
            'help!' => \$help,
            'verbose!' => \$verbose,
            'update_input_id_analysis!' => \$update,
            'input_id_type:s'=> \$input_type,
            'module:s'    => \$module,
            'runnabledb_path:s' => \$perl_path,
            'utils_verbosity=s' => \$utils_verbosity,
           );
if(!$dbpass){ $dbpass = ''; }
$| = 1;
verbose($utils_verbosity);
if($check ) {
  print STDERR "args: $dbhost : $dbuser : $dbpass : $dbname : $input_id : $logic_name\n";
  exit 0;
}

if(!$dbhost || !$dbuser || !$dbname || !$input_id || !$logic_name){
  $help = 1;
}

&useage(\@command_args) if($help);

if(!$write){
  $update = 0;
}

print STDERR "args: $dbhost : $dbuser : $dbpass : $dbname : $input_id : $logic_name\n" if($verbose);

my $db = new Bio::EnsEMBL::Pipeline::DBSQL::DBAdaptor
  (
   -host   => $dbhost,
   -user   => $dbuser,
   -dbname => $dbname,
   -pass   => $dbpass,
   -port   => $dbport,
  );

die "No input id entered" unless defined ($input_id);

my $aa = $db->get_AnalysisAdaptor;
print "Fetching ".$logic_name." from ".$db->dbname."\n";
$analysis = $aa->fetch_by_logic_name($logic_name);


if(!$analysis){
  die("Can't create an analysis without a module and input type") 
    unless($module && $input_type);
  print STDERR "creating analysis object ".$logic_name." ".$module.
    " ".$input_type."\n" if($verbose);
  print STDERR "This object will be stored in the database when the ".
    "features are written\n" if($verbose && $write);
  $analysis = new Bio::EnsEMBL::Pipeline::Analysis
    (-logic_name => $logic_name,
     -module     => $module,
     -input_type => $input_type
    );
  
}

my $runnable;
my $file;
if($analysis->module =~ "Bio::"){ 
  $runnable = $analysis->module; 
  ($file = $runnable) =~ s/::/\//g;
  
}else{
  if($perl_path){
    $file = $perl_path."/".$analysis->module; 
  }else{
    $file = $analysis->module;
  }
  #print "Analysis ".$analysis->logic_name." has module ".$analysis->module.
  #  " and file ".$file."\n";
  ($runnable = $file) =~ s/\//::/g;
}
eval{
  require "$file.pm";
};
if($@){
  throw("Couldn't require $file $@");
}
print STDERR "creating runnable ".$file."\n" if($verbose);

$runnable =~ s/\//::/g;
my $runobj = "$runnable"->new(-db    => $db,
                              -input_id => $input_id,
                              -analysis => $analysis,
                              -verbosity => $utils_verbosity,
			     );
print STDERR "Instantiated ".$runnable." runnabledb\n" if($verbose);
$runobj->fetch_input;
print STDERR "Fetched input\n" if($verbose);
$runobj->run;
print STDERR "Run ".$runobj."\n" if($verbose);

if($write){
  $runobj->write_output;
  print STDERR "written output\n" if($verbose);
}

my $sql = "insert into input_id_analysis(input_id, input_id_type, analysis_id, created) values( ?, ?, ?, now())";

if($write){
  if($update){
    my $sth = $db->prepare($sql);
    $sth->execute($input_id, $analysis->input_id_type, $analysis->dbID);
  }
}
my @output = @{$runobj->output};
if(ref($output[0]) eq 'ARRAY'){
  my $temp = $output[0];
  @output = @$temp;
}
print "There is ".@output." features output\n\n";

#$verbose = 1;
if($verbose){
  my @output = @{$runobj->output};
  if(!@output){
    print STDERR "either ".$runobj." doesn't put its output in ".
      $runobj->output." or your analysis hasn't produced any output\n";
  }
  print STDERR "have ".@output." results\n";
  my $exon_count = 0;
  my $transcript_count = 0;
  foreach my $out (@output) { 
    if ($out->isa("Bio::EnsEMBL::Gene")) {
      #print "\n";
      my $type = $out->type;
      foreach my $tran (@{$out->get_all_Transcripts}) {
        foreach my $exon (@{$tran->get_all_Exons}) {
	  #fetch exon again, avoid caching masked sequence
          $exon->{'_seq_cache'} = undef;
	  $exon->slice($exon->slice->adaptor->db->get_SliceAdaptor->fetch_by_name($exon->slice->name));
          if($verbose){
	    print("exon\t".$exon->start."\t".$exon->end."\t300\t".
		  $exon->strand."\t".$exon->phase."\t".$exon->end_phase."\n");
	    print $exon->seq->seq ."\n";
	  }
          foreach my $ev (@{$exon->get_all_supporting_features}) {
            print print_gff($ev) . "\n";
          }
          $exon_count++;
        }
        $transcript_count++;
	if($verbose && $tran->translate){ print "translation " . $tran->translate->seq . "\n"; }
      }
    } elsif ($out->isa("Bio::EnsEMBL::Pipeline::Tools::Pmatch::PmatchFeature")) {
      print_gff($out, $out->chr_name );
    } else {
      print $out->slice;
      my @values = split /\:/, $out->slice;
      my $name = $values[2];
      print_gff($out, $name);
    }
  }
  print "have ".$exon_count." exons\n";
}



sub print_gff{
  my ($feature, $name) = @_;

  my $str .= ($name) ?  $name."\t":"\t";
  $str .=  "\t"; #source tag
  $str .=  "\t"; #primary tag
  $str .= ($feature->start)    ?  $feature->start."\t":"\t";
  $str .= ($feature->end)      ?  $feature->end."\t":"\t";
  $str .= ($feature->score)    ?  $feature->score."\t" :"\t";
 
  unless ($feature->isa("Bio::EnsEMBL::Pipeline::Tools::Pmatch::PmatchFeature")) {
     $str .= ($feature->strand)   ?  $feature->strand."\t":  ".\t";
  }
  $str .= ($feature->hseqname) ?  $feature->hseqname()."\t": "\t" 
    if($feature->can('hseqname'));
  $str .=  ".\t"; #phase
  $str .=  ".\t"; #end phase
  print $str."\n";
}

sub useage{
  my ($command_args) = @_;
  print "Your commandline was :\n".
    "test_RunnableDB ".join("\t", @$command_args), "\n\n";
	exec('perldoc', $0);
	exit;
}



# POD documentation - main docs before the code

=pod

=head1 NAME

  test_RunnableDB

=head1 SYNOPSIS
 
  will run any runnableDB which will run as part of the pipeline

=head1 DESCRIPTION

  takes database arguments along with an input_id and an analysis object
  and will run the analysis


=head1 OPTIONS

    -dbhost      host name for database (gets put as host= in locator)
    -dbport      For RDBs, what port to connect to (port= in locator)
    -dbname    For RDBs, what name to connect to (dbname= in locator)
    -dbuser    For RDBs, what username to connect as (dbuser= in locator)
    -dbpass    For RDBs, what password to use (dbpass= in locator)
    -input_id  a input id for the analysis
    -logic_name  the logic_name of the analysis
    
     The above are all compulsory options you must provide them 
     otherwise the script won't work'
 
    -input_id_type the input id type
    -module the module to be run, this should either be a module which is
                present in Bio::Ensembl::Pipeline::RunnableDB or it 
                should be the full path

    These two options should be passed if your database doesn't already
    contain the analysis object you want to use, if the write flag is 
    switched on this analysis object will be stored in the database when
    the features are stored, note if you are using the pipeline the
    input id type won't be stored by the core api so it will cause
    RuleManagers db sanity checks to fail 

    -update_input_id_analysis update the input_id_analysis, this can be
               switched off with the -noupdate_input_id_analysis flag
               but if you pass the -nowrite option this will be switched
               off automatically 
    -check     a pre exec option if you want to use it on the farm
    -write     whether to write the results to the database, by default
               this is true but i can be switched off with -nowrite
    -verbose   switch on a series of chatty prints giving you info about
               how its running
    -help      summary of options

=head1 EXAMPLES

  ./test_RunnableDB -dbhost ecs2b -dbuser ensadmin -dbpass **** -dbname
  rat_Jun03_mk2 -input_id 11.14000001-15000000 -analysis Marker

  note if -write isn't swtiched off this script requires your database
  to have pipeline tables in your database as it writes a entry to the
  input_id_analysis table when the job is complete'

=cut
