#!/usr/bin/perl

use strict;
use lib '../modules';
use Bio::Tools::Run::Chinook::Batch;
use Bio::Tools::Run::Chinook::ChinookManager;
use Bio::Tools::Run::Chinook::SupportData::SupportData;
use Bio::Tools::Run::Chinook::Report;
use Data::Dumper;

##########################################################################################################################
##DESCRIPTION:
##A service, and its corresponding description in a Batch file must be turned into a BatchQueue file, where 
##The appropriate parameters and data entry object sets (DEOSETS) are defined.
##This script walks through running LAGAN remotely using two files from the command line (an object called DNA_FILE is used)
##
###########################################################################################################################

######	VERIFY THE INPUT PARAMETERS ARE VALID

if (!defined(@ARGV[0]) || !defined(@ARGV[1] || !defined(@ARGV[2]))) { 
	die("Need to specify input fasta files, i.e. perl t_distributePairwiseAlignment.pl LAGAN /tmp/file1.fa /tmp/file2.fa"); 
}

###### FIND THE ASSOCIATED SERVICE ON CHINOOK

##This is the input service name should be a pairwise alignment program that is accessible over Chinook.
##
my $service_name = @ARGV[0];

##Get the Chinook Manager (talks directly to Chinook Client), you have to start the Perl Engine before you can run this script
##
my $chinook_man = Bio::Tools::Run::Chinook::ChinookManager->new( machine_name => "localhost", port => "7999");

##Get a service from Chinook that matches our service name 
##
my $service = @{$chinook_man->getRandomMatchingService($service_name)};
if (!defined ($service)) {
	die("Could not find service: $service_name\n");
}

###### GET THE BATCH FILE FOR THE SERVICE

##Get the Batch file associated with the service, this describes what is required to run the service (parameters, data, etc).
##A filled batch file is called a batch queue file and can be run over and over again by direct submission.  The majority
##of this code is how a batch queue file gets made...
##
my $batch = Bio::Tools::Run::Chinook::Batch->new ( batch_filename => $service->getBatchFilename() );
		
##Get information about the type of data sets that this service requires
##
my @deosets = @{$batch->getDEOSets()};
foreach my $deoset (@deosets) {
	my @deos;

	##For each set of data, various types of data are allowed to satisfy the services requirements
	##Example: Your program has two datasets one is a collection of background files and the other is a collection of sequences to analyze
	##Each of these datasets (deosets) can be satisfied by having either EnsEMBL coordinates or a fasta file (these are the allowed deo types).
	##
	my @required_deo_names = @{$deoset->getAllowedDEOTypes()};

	foreach my $required_deo_name (@required_deo_names) {

		##Since we have fasta files, containing sequence information, we will use the DNA_FILE deo, if it exists
		##
		if ($required_deo_name eq "DNA_FILE") {

			##Obtain the number of data entry objects that are required in this set, should be 2 since
			##we are distributing a pairwise alignment service
			##
			my $minimum_count = $deoset->getMinimumRequiredCount();

			##For the minimum number of Data Entry Objects in this set
			##
                 	for (my $i = 0; $i < $minimum_count; $i++) {

				##Get the information about this data entry object (called DNA_FILE)
				##
				my $deo = $chinook_man->getDEO($required_deo_name);

				##The server can interpret a certain number of sequence files, this determines
				##if FASTA is an acceptable type
				##
				my $available_file_types = $chinook_man->getAvailableSequenceFileTypes($service);
				my $match = 0;
				foreach my $available_file_type (@$available_file_types) {
					if (uc($available_file_type) eq "FASTA") {
						$match = 1;
					}
				}
				if (!$match) {
					die "FAILED, SERVICE " . $service->getLocation() . " DOES NOT SUPPORT SEQUENCE FILES OF TYPE FASTA\n";
				}

				##For each of the files that we want the server to use, we must upload them to the server
				##This attempts to upload each file to the server and get a corresponding reference ID
				##
				my $file_id = $chinook_man->uploadFile($service, @ARGV[$i]);
				if (!defined($file_id)) {
					die "FAILED, COULD NOT UPLOAD FILE TO SERVER " . $service->getLocation() . "\n";
				}

				##Here we set various attributes of the DNA_FILE data entry object
				##
				$deo->setName("SEQUENCE" . $i);	##A unique name for the object
				$deo->setOrder("-1");	##The precedence of the object in the set
				my $attributes = $deo->getAttributes();	##The collection of attributes
                            	while ( ( my $key, my $value ) = each(%$attributes) ) {
					##How the file will be uploaded, not absolutely required
					##
					if ($key eq "getMode") { %$attributes->{$key}->{0} = $service->getMode(); }  
					elsif ($key eq "getFilewireUri") { %$attributes->{$key}->{0} = $service->getFilewireUri(); }

					##The filename, not absolutely required
					##
					elsif ($key eq "getAbsoluteFileName") { %$attributes->{$key}->{0} = @ARGV[$i];  }

					##Information about the type and location of the file on the server, required
					##
					elsif ($key eq "getFileType") { %$attributes->{$key}->{0} = "FASTA"; }
					elsif ($key eq "getFileId") { %$attributes->{$key}->{0} = $file_id; }
					else {
						#do nothing
					}
				}
				##Put the formatted data entry object into an array
				##
				push @deos, $deo;
			}
		}
	}

	##Put all the formatted data entry objects back into the deoset
	##
	$deoset->setDEOs(\@deos);
}

####### BUILD THE PARAMETERS

##Get the parameters, we can set them if we want
##
my $parameters_ref = $batch->getParameters();


####### BUILD THE QUEUE BATCH FILE

##Create a QueueBatch object
##

my $rand_id = int (rand (time ^ $$));
my $queue_batch = Bio::Tools::Run::Chinook::QueueBatch->new(    	deosets => \@deosets,
                                                                     	parameters => $parameters_ref,
                                                                       	batch => $batch,
                                                                       	filename => $chinook_man->getBatchQueueDirectoryPath() . "chinook.$rand_id.$service_name.batchqueue");
        	
##Write it to file and get an ID to monitor its status (when submitted)
##
my $id = $queue_batch->writeQueueBatch();


###### RUN THE JOB ON CHINOOK

##Schedule the queue batch to be processed on the server
##
my $submitted = $chinook_man->processQueueBatch($queue_batch->getFilename);

if ($submitted) {
	##This loops until the report is ready, with appropriate sleep states
	##
	print STDERR "Waiting for report\n";
	my $report_filename;
	my $download_report_to = "/tmp/lagan.$rand_id.report";
       	my $report_not_done = 1;  #true
       	while ($report_not_done) {
             	$report_filename = $chinook_man->isReportReady($id, $download_report_to);
               	if (defined($report_filename)) {
                    	$report_not_done = 0; #false
               	}
        }

	##When the report is done, print out the contents of the analyses
	##
	&analyzeReport($chinook_man, $service, $report_filename, $rand_id);
}


########################### ANALYZE THE REPORT SUBROUTINE

sub analyzeReport() {
	my $chinook_man = shift;
	my $service = shift;
	my $report_filename = shift;
	my $rand_id = shift;

	##Build a report object from the report at the file location, specified
	##
	my $report = Bio::Tools::Run::Chinook::Report->new( report_filename => $report_filename);

	if ($report->getStatus() eq "FAILED") {
                print "JOB FAILED: " . $report->getFailureMessage() . "\n";

        } elsif ($report->getStatus() eq "SUCCESS") {

		##Get the canonical results file for the analysis
		##
		my $report_file = $report->getCanonicalReportFile();

		##Download the canonical results to the local system
		##
		my $download_to_file = "/tmp/lagan.$rand_id.results.out";
		$chinook_man->downloadFile($service, $report_file->getFileId(), $download_to_file);

		##Open and print the canonical results file
		##
		open(INFILE,"<$download_to_file") || die ("Cannot open " . $download_to_file);
		while(my $currentLine = <INFILE>) {
        		print $currentLine;
		}

		close( INFILE ) || die ("Cannot close " . $download_to_file);
	} else {
		print "ERROR UNKNOWN JOB STATUS: " . $report->getStatus() . "\n";
	}
}

