#!/usr/bin/perl

use strict;
use warnings;
use lib q(myClasses);
use EvaluationResult;
use PDBParser;

###########################################################
#
# The script runs 3 programs to generate scores, used by 
# BK in CASP10:
#  - HANDEDNESS
#  - CoDM
#  - DFM
#
###########################################################
my $RSYNC = 1;  # the parameter-switcher whether rsync data from/to $SERVER
                # 1 - for normal functioning of the program
                # 0 - for cases when network connection was too slow

my $CASP = "CASP13";
my $TARGETS_DIR = "/local/$CASP/TARGETS/";
my $MODELS_DIR = "/local/$CASP/MODELS/";
my @TARGETS;
my $RESULT_DIR = "/local/$CASP/RESULTS/BK/";

my $TMP_DIR = "/tmp/BK_.$$"; #"/local/$CASP/RESULTS/BK/"; # "tmp_$$";

my $SERVER = "predictioncenter.org";

my $CoDM_program = "python /usr/local/CoDM_release/CoDM.py ";
my $DFM_program = "python /usr/local/DFM_release/DFM.py ";
my $HANDEDNESS_program = "perl /usr/local/HANDEDNESS/calc_handedness.pl ";


# rsync targets from predictioncenter.org (p3)
&rsyncTargets($TARGETS_DIR);


# read targets_dir and select targets that have to be re/calculated
&parseTargetsDir();


if (defined($ARGV[0])){
	my $t = $ARGV[0];
	if (-e "$TARGETS_DIR/$t.pdb"){
		@TARGETS = ();
		push @TARGETS, $t; 
	}
}


#exit;

# loop over targets
foreach my $target (@TARGETS){
	# rsync models from predictioncenter.org (p3)
	&rsyncModels("$MODELS_DIR/$target");	
#	print $target."\n"; next;
	my $resFile = &runForTarget($target);
	# upload result file to predictioncenter.org (p3)
	if (defined($resFile) && (-f $resFile)){
		&uploadResultFile($resFile);
		# TR targets
		if ($target =~ m/^TR/ ){
			&runHANDEDNESS_TR($target);
			&runCoDM_TR($target);
			&runDFM_TR($target);
		}
	}
}

# clean
&clean(); #DON'T CLEAN UNLESS TEMPRARY DIR IS USED FOR CALCULATIONS

exit;


#---------------------------
# SUBROUTINES
#---------------------------
sub runForTarget {
    my $target = shift;
    my @models = &parseModels($target);
    my @evalResults = ();
    foreach my $m (@models){
	my $evalResult;
	$evalResult = &runHANDEDNESS($target, $m, $evalResult);
	$evalResult = &runCoDM($target, $m, $evalResult);
	$evalResult = &runDFM($target, $m, $evalResult);
	push @evalResults, $evalResult;
    }
    if (scalar(@evalResults) == 0){
	return undef;
    }
    my $resFile = &printResultFile($target, \@evalResults);
    if (-f $resFile){
	return $resFile;
    } else {
	return undef;
    }
}

# print out file
sub printResultFile{
    my ($target, $refEvalResults) = @_;
    my @evalResults = @{$refEvalResults};
    my $resultFile = sprintf("%s/%s.bk.csv", $RESULT_DIR, $target);
    my $firstDone = 0;
    open OUT, "> $resultFile";
    foreach my $evalResult (@evalResults){
	my $header = "Model";
	my $record = sprintf("%s", $evalResult->createModelName());
        foreach my $score (sort keys $evalResult->{_scores}){
		$header .= "\t$score";
		$record .= sprintf("\t%5.3f",$evalResult->{_scores}{$score});
	}
	if ($firstDone == 0){
		print OUT $header."\n";
	}
		print OUT $record."\n";
	$firstDone = 1;
    }
    close OUT;
    return $resultFile;
}

# run HANDEDNESS
sub runHANDEDNESS {
    my ($target, $model, $evalResult) = @_;
    my $targFile = sprintf("%s/%s.pdb", $TARGETS_DIR, $target);
    my $modelFile = sprintf("%s/%s/%s", $MODELS_DIR, $target, $model);
    if (!-e "$TMP_DIR/$target/"){
	system ("mkdir -p $TMP_DIR/$target/; chmod 775 $TMP_DIR/$target/ ");
    }
    my $tmp_target = sprintf("%s/%s/%s.pdb", $TMP_DIR, $target, $target);
    if (!-e "$tmp_target"){
	my $NEW_FILE;
	if (open($NEW_FILE, sprintf("> %s", $tmp_target))) {
	      my $pdb_parser = new PDBParser();
	      $pdb_parser->open($targFile);
	      $pdb_parser->transform_chains_into_1000($NEW_FILE);
	      close($NEW_FILE);
	      $pdb_parser->close();
	} else {
	      printf(STDERR "Can't open file: %s", $tmp_target);
	      exit 1;
        }
    }
    my $tmp_model = sprintf("%s/%s/%s", $TMP_DIR, $target, $model);
    if (!-e "$tmp_model"){
        my $NEW_FILE;
        if (open($NEW_FILE, sprintf("> %s", $tmp_model))) {
              my $pdb_parser = new PDBParser();
              $pdb_parser->open($modelFile);
              $pdb_parser->transform_chains_into_1000($NEW_FILE);
              close($NEW_FILE);
              $pdb_parser->close();
        } else {
              printf(STDERR "Can't open file: %s", $tmp_model);
              exit 1;
        }
    }


    my $tmp_out = "$TMP_DIR/$target/$model.hand";
    my $program = sprintf("%s  %s %s 50000 > %s", $HANDEDNESS_program, $tmp_target, $tmp_model, $tmp_out);
    if (!defined($evalResult)){
	$evalResult = new EvaluationResult($model);
    }
    if (system("$program") == 0){ 
    open OUT, "< $tmp_out";
      my $out = <OUT>;
	if ($out =~ m/\S+\s+(\S+)\s+(\S+)/){
		my $handedness = $1;
		my $handedness_ratio = $2;
		$evalResult->{_scores}{handedness} = $1;
		$evalResult->{_scores}{handedness_ratio} = $2;
    	}
    	close OUT;
    }
    return $evalResult;
}

# run Handedness for TR
sub runHANDEDNESS_TR{
    my $target = shift;
    my $targFile = sprintf("%s/%s.pdb", $TARGETS_DIR, $target);
    my $startModelFile = sprintf("%s/templates/%s.pdb.txt", $TARGETS_DIR, $target);
    if (!-e "$TMP_DIR/TR/$target/"){
        system ("mkdir -p $TMP_DIR/TR/$target/; chmod 775 $TMP_DIR/TR/$target/ ");
    }
    my $tmp_out = "$TMP_DIR/TR/$target/$target.pdb.txt.hand";
    my $program = sprintf("%s  %s %s 50000 > %s", $HANDEDNESS_program, $targFile, $startModelFile, $tmp_out);
    system("$program");
    # copy results
    my $resDir = "$RESULT_DIR/TR/$target/";
    if (! -d $resDir){
	system("mkdir -p $resDir");
    }
    my $resFile = "$resDir/$target.pdb.txt.hand";
    system("cp $tmp_out $resFile");
    &uploadResultFile($resDir);
}

# run CoDM
sub runCoDM {
    my ($target, $model, $evalResult) = @_;
    my $targFile = sprintf("%s/%s.pdb", $TARGETS_DIR, $target);
    my $modelFile = sprintf("%s/%s/%s", $MODELS_DIR, $target, $model);
    if (!-e "$TMP_DIR/$target/"){
        system ("mkdir -p $TMP_DIR/$target/; chmod 775 $TMP_DIR/$target/ ");
    }

    my $tmp_target = sprintf("%s/%s/%s.pdb", $TMP_DIR, $target, $target);
    if (!-e "$tmp_target"){
        my $NEW_FILE;
        if (open($NEW_FILE, sprintf("> %s", $tmp_target))) {
              my $pdb_parser = new PDBParser();
              $pdb_parser->open($targFile);
              $pdb_parser->transform_chains_into_1000($NEW_FILE);
              close($NEW_FILE);
              $pdb_parser->close();
        } else {
              printf(STDERR "Can't open file: %s", $tmp_target);
              exit 1;
        }
    }
    my $tmp_model = sprintf("%s/%s/%s", $TMP_DIR, $target, $model);
    if (!-e "$tmp_model"){
        my $NEW_FILE;
        if (open($NEW_FILE, sprintf("> %s", $tmp_model))) {
              my $pdb_parser = new PDBParser();
              $pdb_parser->open($modelFile);
              $pdb_parser->transform_chains_into_1000($NEW_FILE);
              close($NEW_FILE);
              $pdb_parser->close();
        } else {
              printf(STDERR "Can't open file: %s", $tmp_model);
              exit 1;
        }
    }

    my $tmp_out = "$TMP_DIR/$target/$model.codm";
    my $program = sprintf("%s  %s %s > %s", $CoDM_program, $tmp_target, $tmp_model, $tmp_out);
    if (!defined($evalResult)){
        $evalResult = new EvaluationResult($model);
    }
    if (system("$program") == 0){
     open OUT, "< $tmp_out";
       my $out = <OUT>;
       if ($out =~ m/\S+\s+(\S+)\s+(\S+)/){
           $evalResult->{_scores}{CoDM} = $1;
           $evalResult->{_scores}{CoDM_ratio} = $2;
       }
     close OUT;
    }
    return $evalResult;
}

# run CoDM for TR
sub runCoDM_TR{
    my $target = shift;
    my $targFile = sprintf("%s/%s.pdb", $TARGETS_DIR, $target);
    my $startModelFile = sprintf("%s/templates/%s.pdb.txt", $TARGETS_DIR, $target);
    if (!-e "$TMP_DIR/TR/$target/"){
        system ("mkdir -p $TMP_DIR/TR/$target/; chmod 775 $TMP_DIR/TR/$target/ ");
    }
    my $tmp_out = "$TMP_DIR/TR/$target/$target.pdb.txt.codm";
    my $program = sprintf("%s  %s %s > %s", $CoDM_program, $targFile, $startModelFile, $tmp_out);
    system("$program");
    # copy results
    my $resDir = "$RESULT_DIR/TR/$target/";
    if (! -d $resDir){
        system("mkdir -p $resDir");
    }
    my $resFile = "$resDir/$target.pdb.txt.codm";
    system("cp $tmp_out $resFile");
    &uploadResultFile($resDir);
}


# run DFM 
sub runDFM{
    my ($target, $model, $evalResult) = @_;
    my $targFile = sprintf("%s/%s.pdb", $TARGETS_DIR, $target);
    my $modelFile = sprintf("%s/%s/%s", $MODELS_DIR, $target, $model);
    if (!-e "$TMP_DIR/$target/"){
        system ("mkdir -p $TMP_DIR/$target/; chmod 775 $TMP_DIR/$target/ ");
    }
    my $tmp_target = sprintf("%s/%s/%s.pdb", $TMP_DIR, $target, $target);
    if (!-e "$tmp_target"){
        my $NEW_FILE;
        if (open($NEW_FILE, sprintf("> %s", $tmp_target))) {
              my $pdb_parser = new PDBParser();
              $pdb_parser->open($targFile);
              $pdb_parser->transform_chains_into_1000($NEW_FILE);
              close($NEW_FILE);
              $pdb_parser->close();
        } else {
              printf(STDERR "Can't open file: %s", $tmp_target);
              exit 1;
        }
    }
    my $tmp_model = sprintf("%s/%s/%s", $TMP_DIR, $target, $model);
    if (!-e "$tmp_model"){
        my $NEW_FILE;
        if (open($NEW_FILE, sprintf("> %s", $tmp_model))) {
              my $pdb_parser = new PDBParser();
              $pdb_parser->open($modelFile);
              $pdb_parser->transform_chains_into_1000($NEW_FILE);
              close($NEW_FILE);
              $pdb_parser->close();
        } else {
              printf(STDERR "Can't open file: %s", $tmp_model);
              exit 1;
        }
    }



    my $tmp_out = "$TMP_DIR/$target/$model.dfm";
    my $program = sprintf("%s  %s %s > %s", $DFM_program, $tmp_target, $tmp_model, $tmp_out);
    if (!defined($evalResult)){
        $evalResult = new EvaluationResult($model);
    }
    if (system("$program") == 0){
     open OUT, "< $tmp_out";
      my $out = <OUT>;
      if ($out =~ m/\S+\s+(\S+)/){
          $evalResult->{_scores}{DFM} = $1;
      }
      close OUT;
    }
    return $evalResult;
}

# run CoDM for TR
sub runDFM_TR{
    my $target = shift;
    my $targFile = sprintf("%s/%s.pdb", $TARGETS_DIR, $target);
    my $startModelFile = sprintf("%s/templates/%s.pdb.txt", $TARGETS_DIR, $target);
    if (!-e "$TMP_DIR/TR/$target/"){
        system ("mkdir -p $TMP_DIR/TR/$target/; chmod 775 $TMP_DIR/TR/$target/ ");
    }
    my $tmp_out = "$TMP_DIR/TR/$target/$target.pdb.txt.dfm";
    my $program = sprintf("%s  %s %s > %s", $DFM_program, $targFile, $startModelFile, $tmp_out);
    system("$program");
    # copy results
    my $resDir = "$RESULT_DIR/TR/$target/";
    if (! -d $resDir ){
        system("mkdir -p $resDir");
    }
    my $resFile = "$resDir/$target.pdb.txt.dfm";
    system("cp $tmp_out $resFile");
    &uploadResultFile($resDir);
}


sub parseModels{
    my $target = shift;
    my @models = (); 
    if (! -d "$MODELS_DIR/$target"){return @models;}
    opendir D, sprintf("%s/%s/", $MODELS_DIR, $target);
	while(defined(my $m = readdir(D))){
		next until $m =~ m/^(T|R).*TS[0-9]{3}/;
		push @models, $m;
	}
    closedir D;
    @models = sort @models;
    return @models;
}

sub parseTargetsDir {
    opendir D, $TARGETS_DIR;
    while(defined(my $f = readdir(D))){
	next unless $f =~ m/^(T|R).*.pdb$/;
	# skip targets -D1 that have been copied from -D0
	if (($f =~ m/-D1\.pdb/) && (-l "$TARGETS_DIR/$f")) {next;}
	# skip combined domains -D12  
	if ($f =~ m/-D[1-9]{2}/) {next;}
	# skip test domain
	if ($f =~ m/-D[7-9]{1}/) {next;} # skip test domains
	$f =~ s/\.pdb$//; 
	if (&checkIfResultsExist($f)){
		push @TARGETS, $f;
	}
    }
    closedir D;
}


sub checkIfResultsExist {
    my $target = shift;
    my $targetFile = sprintf("%s/%s.pdb", $TARGETS_DIR, $target);
    my $resultFile = sprintf("%s/%s.bk.csv", $RESULT_DIR, $target);
    if (! -e $resultFile) {
	return 1;
    }
    # check if target file has been modified AFTER result file has been created
    if ((stat($targetFile))[9] > (stat($resultFile))[9]){
	return 1;
    }
    return 0;	
}

sub clean{
   if (-e $TMP_DIR) {
	system("rm -rf $TMP_DIR");
   }
}

sub rsyncModels{
    my ($fullPathModelDir) = @_;
    unless ($RSYNC) {return ;} # if $RSYNC = 0 then do nothing
    my $command = sprintf("rsync -az -e ssh $SERVER:/%s/ /%s/ --delete ", $fullPathModelDir, $fullPathModelDir);
    system("$command");
#    print("$command\n");
}

sub rsyncTargets{
    my ($fullPathTargetDir) = @_; 
    unless ($RSYNC) {return ;} # if $RSYNC = 0 then do nothing
    my $command = sprintf("rsync -az -e ssh $SERVER:/%s/ /%s/ --delete", $fullPathTargetDir, $fullPathTargetDir);
    system("$command");
    $command = sprintf("rsync -az -e ssh $SERVER:/%s/templates/ /%s/templates/ --delete", $fullPathTargetDir, $fullPathTargetDir);
    system("$command");
    #print("$command\n");
}

sub uploadResultFile{
    my ($fullPathResFile) = shift;
    unless ($RSYNC) {return ;} # if $RSYNC = 0 then do nothing
    my $command = sprintf("rsync -az -e ssh $fullPathResFile $SERVER:/$fullPathResFile");
    system("$command");
#    print("$command\n");

} 
