package TarballsForQAManager;

use strict;
use warnings;

use lib qw(Core);
use TargetsManager;
use LocalConfiguration;
use PredictionsManager;
use GroupsManager;
use Email;
use ClustersForQAManager;

use Configuration;

use Distribution;
use Thread;

# the length of model should be at least $lengthCutOff*100%
# of the target's length to be included in mvsm_serv evaluation
my $lengthCutOff = 0.75;

# nummber of bins in stage 1
my $nr_bins = $LOCAL_CONFIG->{NUMBER_MODELS_QA_STAGE1};

# number of best models in stage 2
my $nr_best = $LOCAL_CONFIG->{NUMBER_MODELS_QA_STAGE2};

# list of targets to skip
my $ignored_targets = $LOCAL_CONFIG->{TARGETS_IGNORED_FOR_QA};

my $delta_evaluation = {
   days => 0,
   hours => 0,
   minutes => 0
};

my $delta_check_eval = {
   days => 1,
   hours => 0,
   minutes => 0
};

my $delta_stage1 = {
   days => $LOCAL_CONFIG->{QA_STAGE1_RELEASE_DAYS},
   hours => 0,
   minutes => 0
};

my $delta_stage2 = {
   days => $LOCAL_CONFIG->{QA_STAGE2_RELEASE_DAYS},
   hours => 0,
   minutes => 0
};
 
my $delta_all = {
   days => $LOCAL_CONFIG->{QA_STAGE2_EXPIRED_DAYS},
   hours => 0,
   minutes => 0
};
#----------------------------------------------------------
# S U B R O U T I N E S
#----------------------------------------------------------

sub new {
    my ($class) = @_;
    
    my $self = {

    };

    bless $self, $class;

    return $self;
}

# methods returns array of targets for evaluation
# the trigger for evaluation is experation the date 
# for predictions from server groups
sub get_targets_for_evaluation {
    my ($self) = @_;
    my $targetsmanager = new TargetsManager();
    my $params = {
	view_targets => ' ',
	view => 'regular'
    };
    my @targets = (); 
    my $current = DateTime->now(time_zone => 'America/Los_Angeles');
    foreach my $target ($targetsmanager->public_targets($params)){
	if($target->{IS_CANCELED} == 1){
		next;
	}
	my $date_line = $target->{SERVER_EXPIRATION_DATE};
	my $day = 0; my $month = 0; my $year = 0;
	if($date_line =~ m/(\d+)\-(\d+)\-(\d+)/){
		$year = $1; $month = $2; $day = $3;
	}
        my $date = new DateTime (
            year => $year,
            month => $month,
            day => $day,
            hour => $LOCAL_CONFIG->{EXPIRED_HOURS},
            minute => $LOCAL_CONFIG->{EXPIRED_MINUTES},
            time_zone => 'America/Los_Angeles'
        );
	my $date_new = new DateTime (
            year => $year,
            month => $month,
            day => $day,
            hour => $LOCAL_CONFIG->{EXPIRED_HOURS},
            minute => $LOCAL_CONFIG->{EXPIRED_MINUTES},
            time_zone => 'America/Los_Angeles'
        );
        $date_new->add(days => 1);
	if(DateTime->compare_ignore_floating($date, $current) <= 0 && 
		DateTime->compare_ignore_floating($current, $date_new) < 0) {
		my $target_name = $target->{NAME};
		if ($ignored_targets =~ m/$target_name/) {
			next;
		}
		push(@targets, $target);
	}
    }
    return @targets;
}



sub get_targets_check_evaluation {
    my ($self) = @_;
    my $targetsmanager = new TargetsManager();
    my $params = {
	view_targets => ' ',
        view => 'regular'
    };
    my @targets = ();
    my $current = DateTime->now(time_zone => 'America/Los_Angeles');
    
    foreach my $target ($targetsmanager->public_targets($params)){
        if($target->{IS_CANCELED} == 1){
                next;
        }
        my $date_line = $target->{SERVER_EXPIRATION_DATE};
        my $day = 0; my $month = 0; my $year = 0;
        if($date_line =~ m/(\d+)\-(\d+)\-(\d+)/){
                $year = $1; $month = $2; $day = $3;
        }
       my $date = new DateTime (
            year => $year,
            month => $month,
            day => $day,
            hour => $LOCAL_CONFIG->{EXPIRED_HOURS},
            minute => $LOCAL_CONFIG->{EXPIRED_MINUTES},
            time_zone => 'America/Los_Angeles'
        );
	$date->add(days => ($delta_check_eval->{days}));
        my $date_new = new DateTime (
            year => $year,
            month => $month,
            day => $day,
            hour => $LOCAL_CONFIG->{EXPIRED_HOURS},
            minute => $LOCAL_CONFIG->{EXPIRED_MINUTES},
            time_zone => 'America/Los_Angeles'
        );
	$date_new->add(days => ($delta_check_eval->{days} + 1));
        if(DateTime->compare_ignore_floating($date, $current) <= 0 &&
                DateTime->compare_ignore_floating($current, $date_new) < 0) {
		my $target_name = $target->{NAME};
                if ($ignored_targets =~ m/$target_name/) {
                        next;
                }
                push(@targets, $target);
        }

    }
    return @targets;
}

sub get_targets_for_stage1{
    my ($self) = @_;
    my $targetsmanager = new TargetsManager();
    my $params = {
	view_targets => ' ',
        view => 'regular'
    };
    my @targets = ();
    my $current = DateTime->now(time_zone => 'America/Los_Angeles');

    foreach my $target ($targetsmanager->public_targets($params)){
        if($target->{IS_CANCELED} == 1){
                next;
        }
	my $target_name = $target->{NAME};
        if ($ignored_targets =~ m/$target_name/) {
		next;
        }
        my $date_line = $target->{SERVER_EXPIRATION_DATE};
        my $day = 0; my $month = 0; my $year = 0;
        if($date_line =~ m/(\d+)\-(\d+)\-(\d+)/){
                $year = $1; $month = $2; $day = $3;
        }
        my $date = new DateTime (
            year => $year,
            month => $month,
            day => $day,
            hour => $LOCAL_CONFIG->{EXPIRED_HOURS},
            minute => $LOCAL_CONFIG->{EXPIRED_MINUTES},
            time_zone => 'America/Los_Angeles'
        );
        $date->add(days => $delta_stage1->{days});
        my $date_new = new DateTime (
            year => $year,
            month => $month,
            day => $day,
            hour => $LOCAL_CONFIG->{EXPIRED_HOURS},
            minute => $LOCAL_CONFIG->{EXPIRED_MINUTES},
            time_zone => 'America/Los_Angeles'
        );
        $date_new->add(days => ($delta_stage1->{days} + 1));

        if(DateTime->compare_ignore_floating($date, $current) <= 0 &&
                DateTime->compare_ignore_floating($current, $date_new) < 0) {
                push(@targets, $target);
        }

    }
    return @targets;
}


sub get_targets_for_stage2{
    my ($self) = @_;
    my $targetsmanager = new TargetsManager();
    my $params = {
	view_targets => ' ', 
        view => 'regular'
    };
    my @targets = ();
    my $current = DateTime->now(time_zone => 'America/Los_Angeles');

    foreach my $target ($targetsmanager->public_targets($params)){
        if($target->{IS_CANCELED} == 1){
                next;
        }
	my $target_name = $target->{NAME};
        if ($ignored_targets =~ m/$target_name/) {
                next;
        }
        my $date_line = $target->{SERVER_EXPIRATION_DATE};
        my $day = 0; my $month = 0; my $year = 0;
        if($date_line =~ m/(\d+)\-(\d+)\-(\d+)/){
                $year = $1; $month = $2; $day = $3;
        }
        my $date = new DateTime (
            year => $year,
            month => $month,
            day => $day,
            hour => $LOCAL_CONFIG->{EXPIRED_HOURS},
            minute => $LOCAL_CONFIG->{EXPIRED_MINUTES},
            time_zone => 'America/Los_Angeles'
        );
        $date->add(days => $delta_stage2->{days});
        my $date_new = new DateTime (
            year => $year,
            month => $month,
            day => $day,
            hour => $LOCAL_CONFIG->{EXPIRED_HOURS},
            minute => $LOCAL_CONFIG->{EXPIRED_MINUTES},
            time_zone => 'America/Los_Angeles'
        );
        $date_new->add(days => ($delta_stage2->{days} + 1));
        if(DateTime->compare_ignore_floating($date, $current) <= 0 &&
                DateTime->compare_ignore_floating($current, $date_new) < 0) {
                push(@targets, $target);
        }

    }
    return @targets;
}


sub get_targets_for_all{
    my ($self) = @_;
    my $targetsmanager = new TargetsManager();
    my $params = {
	view_targets => ' ', 	
        view => 'regular'
    };
    my @targets = ();
    my $current = DateTime->now(time_zone => 'America/Los_Angeles');

    foreach my $target ($targetsmanager->public_targets($params)){
        if($target->{IS_CANCELED} == 1){
                next;
        }
        my $date_line = $target->{SERVER_EXPIRATION_DATE};
        my $day = 0; my $month = 0; my $year = 0;
        if($date_line =~ m/(\d+)\-(\d+)\-(\d+)/){
                $year = $1; $month = $2; $day = $3;
        }
        my $date = new DateTime (
            year => $year,
            month => $month,
            day => $day,
            hour => $LOCAL_CONFIG->{EXPIRED_HOURS},
            minute => $LOCAL_CONFIG->{EXPIRED_MINUTES},
            time_zone => 'America/Los_Angeles'
        );
        $date->add(days => $delta_all->{days});
        my $date_new = new DateTime (
            year => $year,
            month => $month,
            day => $day,
            hour => $LOCAL_CONFIG->{EXPIRED_HOURS},
            minute => $LOCAL_CONFIG->{EXPIRED_MINUTES},
            time_zone => 'America/Los_Angeles'
        );
        $date_new->add(days => ($delta_all->{days} + 1));
        if(DateTime->compare_ignore_floating($date, $current) <= 0 &&
                DateTime->compare_ignore_floating($current, $date_new) < 0) {
                push(@targets, $target);
        }

    }
    return @targets;
}


sub send_for_evaluation{
   my ($self) = @_;
   my @targets = $self->get_targets_for_evaluation();
   return if scalar(@targets) == 0;
   # copy predidctions
   $self->copy_predictions_for_evaluation(\@targets);	

   my $message = "";
   # run script which sends tasks for evaluation by mvsm_serv plugin
   foreach my $target (@targets){
	system(sprintf(" cd /local/Projects/Perl/casp13/src/scripts/evaluation_scripts/ ;  ./rsync_upload.sh '%s' '%s' '%s' '%s' > /tmp/log.log", $target->{NAME}, 'mvsm_serv', '*', ''));
	system("chgrp users /tmp/log.log");
	sleep(1);
	system(sprintf(" cd /local/Projects/Perl/casp13/src/scripts/evaluation_scripts/ ;  ./rsync_upload.sh '%s' '%s' '%s' '%s' > /tmp/log.log", $target->{NAME}, 'molprb_serv', '*', ''));
	$message .= $target->{NAME}." ";
   }
	# TODO : change e-mails
        Email::send_email($CONFIG->{SUPPORT_EMAIL_ADMIN},$CONFIG->{SUPPORT_EMAIL},'','bmonast@gmail.com', 'mvsm_serv & molprb_serv: sent for evaluation '.$message,'');
#print $message."\n";
}

sub copy_predictions_for_evaluation{
   my ($self, $ref_targets) = @_;
   my @targets = @$ref_targets;
   return if scalar(@targets) == 0;
   my $predictions_manager = new PredictionsManager();
  
   for(my $t_count = 0; $t_count < scalar(@targets); $t_count++){
      # len_target - length of target sequence
      my $len_target = $targets[$t_count]->{NUMBER_OF_AA};
  
      # get all server TS and AL predictions for the target
      my @predictions = $predictions_manager->tarballs_predictions($targets[$t_count]->{NAME}, "server");
      my $old_dir = sprintf("%s/%s", $LOCAL_CONFIG->{CLEAN_PREDICTIONS_DIR}, $targets[$t_count]->{NAME});
      my $new_dir = sprintf("%s/%s", $LOCAL_CONFIG->{DATA_SERV_MODELS_DIR}, $targets[$t_count]->{NAME});
      if(!(-e $new_dir)){
          system(sprintf("mkdir -p %s",$new_dir));
          system(sprintf("chgrp users %s", $new_dir));
          system(sprintf("chmod 775 %s", $new_dir));
  
          for(my $p_count = 0; $p_count < scalar(@predictions); $p_count++) {
  
               my $old_file = sprintf("%s/%s%s%03d_%s", $old_dir, $predictions[$p_count]->{TARGET}, $predictions[$p_count]->{PFRMAT}, $predictions[$p_count]->{GROUP_CODE}, $predictions[$p_count]->{MODEL});
               # check of file existance
               if(! -f $old_file){
                     warn "file $old_file doesn't exist but the corresponding prediction is in database. Check directory ./prediction/junk/";
               } else{
                      # check length requirement: the model has to cover at least 75% of the target's sequence
                      my $len_model = `grep \'ATOM\' $old_file | grep -c \' CA\'`; chomp $len_model;
                      if($len_model > $lengthCutOff * $len_target){
  
                          my $new_file = sprintf("%s/%s%s%03d_%s", $new_dir, $predictions[$p_count]->{TARGET}, $predictions[$p_count]->{PFRMAT}, $predictions[$p_count]->{GROUP_CODE}, $predictions[$p_count]->{MODEL});
                          system("cp $old_file $new_file");
                       }
 
                }
           }
      }
     sleep(1);
   }
}

sub check_evaluation_old{
   my ($self) = @_;
   my $message = "Resume after 1 day of evaluation mvsm_serv\nfor targets:\n";
   my @targets = $self->get_targets_check_evaluation();
   my $result = 1;
   return 1 if scalar(@targets) == 0;
   
   foreach my $target (@targets){
	my $error_flag = 0;
        my $pred_dir = $LOCAL_CONFIG->{DATA_SERV_MODELS_DIR}."/".$target->{NAME};
   	my $res_dir = $LOCAL_CONFIG->{RESULTS_DIR}."/MVSM_SERV/DATA/".$target->{NAME};
	$message .= "\n".$target->{NAME}.": ";
	# read files from $pred_dir and save them in array
	my @files;
	if(! open FILES, "ls -1 $pred_dir | "){$message .= " $pred_dir doesn't exist\n";  next;} 
	while(<FILES>){
		chomp $_;
		push(@files, $_);
	}
	close (FILES);
	
	foreach my $file (@files){
		$file = substr($file, rindex($file,"/") + 1);
		my $file_path = $res_dir."/".$file;
		if(! -f $file_path){ # if file doesn't exist or is empty
			$message .= "\n $file_path doesn't exist ";
			$error_flag = 1;
			$result = 0;
		}elsif(-z $file_path){
			$message .= "\n $file_path is empty ";
                        $error_flag = 1;
			$result = 0;
		}
	}
	if(0 == $error_flag){
		#$message .= "OK\n";
	}else{
		$message .= "\n";
		Email::send_email($CONFIG->{SUPPORT_EMAIL_ADMIN},$CONFIG->{SUPPORT_EMAIL},'','bmonast@gmail.com','mvsm_serv: missing results for target '.$target->{NAME}, $message);
		next;
	}
	if(0 == $error_flag && !(-e "/data/".$LOCAL_CONFIG->{CASP_VERSION}."/tmp_QA/".$target->{NAME}.".stage2.3D.srv.tar.gz")){
	  my $cl_manager = new ClustersForQAManager($target->{NAME});
	  if(1 == $cl_manager->process()){
		$message .= "OK\n";
		Email::send_email($CONFIG->{SUPPORT_EMAIL_ADMIN},$CONFIG->{SUPPORT_EMAIL},'','bmonast@gmail.com','mvsm_serv: OK for target '.$target->{NAME}, $message);
	  }else{
		Email::send_email($CONFIG->{SUPPORT_EMAIL_ADMIN},$CONFIG->{SUPPORT_EMAIL},'','bmonast@gmail.com','mvsm_serv: problem creating tarballs for target '.$target->{NAME}, $message);
		$result = 0;
	  }
	}
	
   }
   return $result;
}

# this check is valid if mvsm_serv plugin was run once for pairs (pred_model1, pred_model2) (pred_model2, pred_model1)
sub check_evaluation{
   my ($self) = @_;

   my @targets = $self->get_targets_check_evaluation();
   my $result = 1;
   return 1 if scalar(@targets) == 0;

   foreach my $target (@targets){
        my $error_flag = 0;
        my $pred_dir = $LOCAL_CONFIG->{DATA_SERV_MODELS_DIR}."/".$target->{NAME};
        my $res_dir = $LOCAL_CONFIG->{RESULTS_DIR}."/MVSM_SERV/DATA/".$target->{NAME};
	my $message = sprintf("Resume after 1 day of evaluation mvsm_serv for target %s:\n",$target->{NAME});

	# check if number of results file = number of predictions model - 1
	my $n_p = `ls -1 $pred_dir | wc -l`;
	my $n_r = `ls -1 $res_dir | wc -l`;
	if(($n_p - 1) != $n_r){
		$message .= "Calculated models $n_r of ".($n_p - 1)." (IMPORTANT: the dependence isn't linear)\n";
		Email::send_email($CONFIG->{SUPPORT_EMAIL_ADMIN},$CONFIG->{SUPPORT_EMAIL},'','bmonast@gmail.com','mvsm_serv: missing results for target '.$target->{NAME}, $message);
		$error_flag = 1;
                next;
	}
        # read all files from $pred_dir and save them in array
        my @files;
        if(! open FILES, "ls -1 $pred_dir | "){$message .= " $pred_dir doesn't exist\n";  next;}
        while(<FILES>){
                chomp $_;
                push(@files, $_);
        }
        close (FILES);

	# cat all results file and check if there are all results for all targets
	
        foreach my $file (@files){
                $file = substr($file, rindex($file,"/") + 1); # name of file T0123TS123_4
		my $command = sprintf("cat %s/* | grep AVERAGE -v | grep SIMILAR -v | grep %s -c", $res_dir, $file);	
		my $l = `$command`;
	#	print "$file\t$l\n";
		if($l != ($n_p - 1)){
			chomp $l;
			$message .= sprintf("Missing results for model %s: calculated %s of %s\n", $file, $l, $n_r);
			$error_flag = 1;
		}
        }

	# check molprobity result
	my $molprb_res_file = sprintf("%s/MOLPROBITY/%s.molprb", $LOCAL_CONFIG->{RESULTS_DIR}, $target->{NAME});
	if (! -e $molprb_res_file){
			$message .= sprintf("Missing file with molprobity results for target %s\n", $target->{NAME});
			$error_flag = 1;
	}

        if(0 == $error_flag){
                #$message .= "OK\n";
        }else{
                $message .= "\n";
                Email::send_email($CONFIG->{SUPPORT_EMAIL_ADMIN},$CONFIG->{SUPPORT_EMAIL},'','bmonast@gmail.com','mvsm_serv: missing some results for target '.$target->{NAME}, $message);
                next;
        }
        if(0 == $error_flag && !(-e "/data/".$LOCAL_CONFIG->{CASP_VERSION}."/tmp_QA/".$target->{NAME}.".stage2.3D.srv.tar.gz")){
          my $cl_manager = new ClustersForQAManager($target->{NAME});
          if(1 == $cl_manager->process()){
                $message .= "OK\n";
                Email::send_email($CONFIG->{SUPPORT_EMAIL_ADMIN},$CONFIG->{SUPPORT_EMAIL},'','bmonast@gmail.com','mvsm_serv: tarballs OK for target '.$target->{NAME}, $message);
          }else{
                Email::send_email($CONFIG->{SUPPORT_EMAIL_ADMIN},$CONFIG->{SUPPORT_EMAIL},'','bmonast@gmail.com','mvsm_serv: problem creating tarballs for target '.$target->{NAME}, $message);
                $result = 0;
          }
        }
#	print $message."\n";
   }
   return $result;
}




sub download_tarballs_stage1{
    my ($self) = @_;
    my @targets = $self->get_targets_for_stage1();
    return if scalar(@targets) == 0;
    foreach my $target (@targets){

	my $tarball_name = sprintf("%s.stage1.3D.srv.tar.gz", $target->{NAME});

	my $tmp_QA_area = sprintf("/data/".$LOCAL_CONFIG->{CASP_VERSION}."/tmp_QA/%s", $tarball_name);
 	my $download_area = sprintf("/www/download_area/".$LOCAL_CONFIG->{CASP_VERSION}."/server_predictions/%s", $tarball_name);
	system("cp $tmp_QA_area $download_area");
	next;


	# OBSOLETE CODE
        my @predictions = $self->get_predictions_for_stage1_for_target($target);
        # sort @predictions alphabetically
        @predictions = sort {$a->{GROUP_NAME} cmp $b->{GROUP_NAME}} @predictions;

       
        if (!(-e $download_area)) {
              my $new_dir = sprintf("%s/%s", $LOCAL_CONFIG->{TARBALLS_PREDICTIONS_DIR}, $target->{NAME});
              my $old_dir = sprintf("%s/%s", $LOCAL_CONFIG->{CLEAN_PREDICTIONS_DIR}, $target->{NAME});
              if(!(-e $new_dir)) {
                  system(sprintf("mkdir %s", $new_dir));
                  system(sprintf("chgrp users %s", $new_dir));
                  system(sprintf("chmod 775 %s", $new_dir));
              }

              for(my $p_count = 0; $p_count < scalar(@predictions); $p_count++) {
                  my $new_file = sprintf("%s/%s_%s%s%s", $new_dir, $predictions[$p_count]->{GROUP_NAME}, $predictions[$p_count]->{PFRMAT}, $predictions[$p_count]->{MODEL}, (($predictions[$p_count]->{PFRMAT} eq 'AL')?'.pdb':''));
                   my $old_file = sprintf("%s/%s%s%s_%s", $old_dir, $target->{NAME}, $predictions[$p_count]->{PFRMAT}, $predictions[$p_count]->{GROUP_CODE}, $predictions[$p_count]->{MODEL});

                  system(sprintf("cp %s %s", $old_file, $new_file));
                  system(sprintf("chmod a+r %s", $new_file))
              }

              system(sprintf("cd %s; tar -czf %s %s/* --remove-files", $LOCAL_CONFIG->{TARBALLS_PREDICTIONS_DIR}, $tarball_name, $target->{NAME}));
              system(sprintf("chgrp users %s/%s",$LOCAL_CONFIG->{TARBALLS_PREDICTIONS_DIR}, $tarball_name));
              system(sprintf("chmod 664 %s/%s",$LOCAL_CONFIG->{TARBALLS_PREDICTIONS_DIR}, $tarball_name));

              system(sprintf("mv %s/%s %s", $LOCAL_CONFIG->{TARBALLS_PREDICTIONS_DIR}, $tarball_name, $download_area));
	      system(sprintf("rm -f -r %s/%s ", $LOCAL_CONFIG->{TARBALLS_PREDICTIONS_DIR}, $target->{NAME}));
       }

    }
}

sub distribute {
	my ($self) = @_;
	my $groups_manager = new GroupsManager();
	my @servers = $groups_manager->distribution_servers("qa_only");
        my $servers_count = scalar(@servers);
	# stage 1
	my @targets_1 = $self->get_targets_for_stage1();
        if(scalar(@targets_1) > 0){
	  foreach my $target (@targets_1){
	          for(my $i = 0; $i < $servers_count; ++$i) {
			$self->sent_request($target->{ID}, $servers[$i]->{ID}, 1);	
	          }
		  sleep(60);
	      Email::send_email($CONFIG->{SUPPORT_EMAIL_ADMIN},$CONFIG->{SUPPORT_EMAIL},'','bmonast@gmail.com','distribution QA 1 : '.$target->{NAME}, '');
	      sleep(5);
	      $self->submitDavisQApredictions("Davis-EMAconsensus", $target, 1);
	      sleep(5);
	      $self->submitDavisQApredictions("Davis-EMAconsensusAL", $target, 1);
	   }
	}
	# stage 2 
	my @targets_2 = $self->get_targets_for_stage2();
	if(scalar(@targets_2) > 0){
	  foreach my $target (@targets_2){
            for(my $i = 0; $i < $servers_count; ++$i) {
 	  	$self->sent_request($target->{ID}, $servers[$i]->{ID}, 2);               
            }
	    sleep(60);
	    Email::send_email($CONFIG->{SUPPORT_EMAIL_ADMIN},$CONFIG->{SUPPORT_EMAIL},'','bmonast@gmail.com','distribution QA 2 : '.$target->{NAME}, '');
	    sleep(5);
            $self->submitDavisQApredictions("Davis-EMAconsensus", $target, 2);
            sleep(5);
            $self->submitDavisQApredictions("Davis-EMAconsensusAL", $target, 2);

	  }
	}

	# wait for a while and check the status of jobs
	sleep(600); # sleep 15 min

	my $jobs_manager = new JobsManager();
	# stage 1
	if(scalar(@targets_1) > 0){
          foreach my $target (@targets_1){
                  for(my $i = 0; $i < $servers_count; ++$i) {
                        my %hash_job = $jobs_manager->get_job($servers[$i]->{ID},$target->{ID});
                        if(defined $hash_job{STATUS} && $hash_job{STATUS} >= 2){
				# OK
                        }else{
                                $self->sent_request($target->{ID}, $servers[$i]->{ID}, 1);
                        }
                  }
                  sleep(60);
           }
	}
	# stage 2
        if(scalar(@targets_2) > 0){
          foreach my $target (@targets_2){
                  for(my $i = 0; $i < $servers_count; ++$i) {
                        my %hash_job = $jobs_manager->get_job($servers[$i]->{ID},$target->{ID});
                        if(defined $hash_job{STATUS} && $hash_job{STATUS} >= 2){
				# OK
                        }else{
				$self->sent_request($target->{ID}, $servers[$i]->{ID}, 2);
                        }
                  }
                  sleep(60);
           }
        }
}



sub download_tarballs_stage2{
    my ($self) = @_;
    my @targets = $self->get_targets_for_stage2();
    return if scalar(@targets) == 0;
    foreach my $target (@targets){

        my $tarball_name = sprintf("%s.stage2.3D.srv.tar.gz", $target->{NAME});

        my $tmp_QA_area = sprintf("/data/".$LOCAL_CONFIG->{CASP_VERSION}."/tmp_QA/%s", $tarball_name);
        my $download_area = sprintf("/www/download_area/".$LOCAL_CONFIG->{CASP_VERSION}."/server_predictions/%s", $tarball_name);
        system("cp $tmp_QA_area $download_area");
        next;


	# obsolete code
        my @predictions = $self->get_predictions_for_stage2_for_target($target);
        # sort @predictions alphabetically
        @predictions = sort {$a->{GROUP_NAME} cmp $b->{GROUP_NAME}} @predictions;
        
        if (!(-e $download_area)) {
              my $new_dir = sprintf("%s/%s", $LOCAL_CONFIG->{TARBALLS_PREDICTIONS_DIR}, $target->{NAME});
              my $old_dir = sprintf("%s/%s", $LOCAL_CONFIG->{CLEAN_PREDICTIONS_DIR}, $target->{NAME});
              if(!(-e $new_dir)) {
                  system(sprintf("mkdir %s", $new_dir));
                  system(sprintf("chgrp users %s", $new_dir));
                  system(sprintf("chmod 775 %s", $new_dir));
              }

              for(my $p_count = 0; $p_count < scalar(@predictions); $p_count++) {
                  my $new_file = sprintf("%s/%s_%s%s%s", $new_dir, $predictions[$p_count]->{GROUP_NAME}, $predictions[$p_count]->{PFRMAT}, $predictions[$p_count]->{MODEL}, (($predictions[$p_count]->{PFRMAT} eq 'AL')?'.pdb':''));
                   my $old_file = sprintf("%s/%s%s%s_%s", $old_dir, $target->{NAME}, $predictions[$p_count]->{PFRMAT}, $predictions[$p_count]->{GROUP_CODE}, $predictions[$p_count]->{MODEL});

                  system(sprintf("cp %s %s", $old_file, $new_file));
                  system(sprintf("chmod a+r %s", $new_file))
              }

              system(sprintf("cd %s; tar -czf %s %s/* --remove-files", $LOCAL_CONFIG->{TARBALLS_PREDICTIONS_DIR}, $tarball_name, $target->{NAME}));
              system(sprintf("chgrp users %s/%s",$LOCAL_CONFIG->{TARBALLS_PREDICTIONS_DIR}, $tarball_name));
              system(sprintf("chmod 664 %s/%s",$LOCAL_CONFIG->{TARBALLS_PREDICTIONS_DIR}, $tarball_name));

              system(sprintf("mv %s/%s %s", $LOCAL_CONFIG->{TARBALLS_PREDICTIONS_DIR}, $tarball_name, $download_area));
	      system(sprintf("rm -f -r %s/%s", $LOCAL_CONFIG->{TARBALLS_PREDICTIONS_DIR}, $target->{NAME}));
       }

    }
}


sub download_tarballs_all{
    my ($self) = @_;
    my @targets = $self->get_targets_for_all();
    return if scalar(@targets) == 0;
    my $predictions_manager = new PredictionsManager();
    foreach my $target (@targets){
        my @predictions = $predictions_manager->tarballs_predictions($target->{NAME}, "server");

        my $tarball_name = sprintf("%s.3D.srv.tar.gz", $target->{NAME});

        my $download_area = sprintf("/www/download_area/".$LOCAL_CONFIG->{CASP_VERSION}."/server_predictions/%s", $tarball_name);
        if (!(-e $download_area)) {
              my $new_dir = sprintf("%s/%s", $LOCAL_CONFIG->{TARBALLS_PREDICTIONS_DIR}, $target->{NAME});
              my $old_dir = sprintf("%s/%s", $LOCAL_CONFIG->{CLEAN_PREDICTIONS_DIR}, $target->{NAME});
              if(!(-e $new_dir)) {
                  system(sprintf("mkdir %s", $new_dir));
                  system(sprintf("chgrp users %s", $new_dir));
                  system(sprintf("chmod 775 %s", $new_dir));
              }

              for(my $p_count = 0; $p_count < scalar(@predictions); $p_count++) {
                  my $new_file = sprintf("%s/%s_%s%s%s", $new_dir, $predictions[$p_count]->{GROUP}, $predictions[$p_count]->{PFRMAT}, $predictions[$p_count]->{MODEL}, (($predictions[$p_count]->{PFRMAT} eq 'AL')?'.pdb':''));
                   my $old_file = sprintf("%s/%s%s%s_%s", $old_dir, $target->{NAME}, $predictions[$p_count]->{PFRMAT}, $predictions[$p_count]->{GROUP_CODE}, $predictions[$p_count]->{MODEL});

                  system(sprintf("cp %s %s", $old_file, $new_file));
                  system(sprintf("chmod a+r %s", $new_file))
              }

              system(sprintf("cd %s; tar -czf %s %s/* --remove-files", $LOCAL_CONFIG->{TARBALLS_PREDICTIONS_DIR}, $tarball_name, $target->{NAME}));
              system(sprintf("chgrp users %s/%s",$LOCAL_CONFIG->{TARBALLS_PREDICTIONS_DIR}, $tarball_name));
              system(sprintf("chmod 664 %s/%s",$LOCAL_CONFIG->{TARBALLS_PREDICTIONS_DIR}, $tarball_name));

              system(sprintf("mv %s/%s %s", $LOCAL_CONFIG->{TARBALLS_PREDICTIONS_DIR}, $tarball_name, $download_area));
	      system(sprintf("rm -f -r %s/%s", $LOCAL_CONFIG->{TARBALLS_PREDICTIONS_DIR}, $target->{NAME}));
       }

    }
}


sub get_predictions_for_stage1_for_target{
    my ($self, $target) = @_;
    my @predictions = $self->rank_predictions_for_target($target,0);
    my @result;
    my $incr = int(scalar(@predictions)/$nr_bins);
    if($incr == 0){
	$incr = 1;
    }
    for(my $i = 0; $i < scalar(@predictions) ; $i += $incr) {
	push(@result, $predictions[$i]);
	last if scalar(@result) == $nr_bins;
    }
    return @result;
}

sub get_predictions_for_stage2_for_target{
    my ($self, $target) = @_;
    my @predictions = $self->rank_predictions_for_target($target,1);
    my @result;
    for(my $i = 0; $i < scalar(@predictions); $i++){
	if($i == $nr_best){last;}
	push(@result,$predictions[$i]);
    }
    return @result;
}

sub rank_predictions_for_target{
   my ($self, $target, $keep_same) = @_;
   my $res_dir = $LOCAL_CONFIG->{RESULTS_DIR}."/MVSM_SERV/DATA/".$target->{NAME}."/";
   my @files;
   
   my %files_to_skip = (); # hash to keep models to be skipped: if rmsd between several models = 0, we keep only one model if parameter $keep_same = 0
   
   if(!(open FILES, "ls -1 ".$res_dir." |")) { my $message = "ALARM! $res_dir doesn't exist.\n"; return 0}
   while(<FILES>){
	chomp $_;
	push (@files, $_);
   }
   close(FILES);
   

   my $groups_manager = new GroupsManager();
   my $predictions_manager = new PredictionsManager();
   my @predictions;
   foreach my $file (@files){
	
	my $file = substr($file, rindex($file, '/') + 1); # remove all subdirs in path if any
	my $file_path = $res_dir.$file;
#	print $file_path."\n";

	# check if file is in %files_to_skip
	next if (exists $files_to_skip{$file} && $keep_same == 0);

	my $pfrmat; my $model;  my $group_code; my $group_id; my $group_name; my $pr_id;
	if($file =~ m/^([TR][0-9]{4})([A-Z]{2})([0-9]{3})_([1-5])/){
		$pfrmat = $2;
		$group_code = $3;
		$model = $4;
		$group_id = $groups_manager->get_id_by_code($group_code);
		$group_name = $groups_manager->name($group_id);
		$pr_id = $predictions_manager->prediction_exist($target,$model,$pfrmat,$group_id);
	}else{
		next;
	}
	if($keep_same == 0){
	open SIMILARLINE, "grep SIMILAR $file_path |";
	my $line = <SIMILARLINE>;
		my @tokens = split(/\s+/,$line);
		if(scalar(@tokens)>2){
			for(my $i = 2; $i<scalar(@tokens); $i++){
				$files_to_skip{$tokens[$i]}=1;
			}
		}
	close(SIMILARLINE);
	}

	open AVERAGELINE, "grep AVERAGE $file_path | ";
	my $line =  <AVERAGELINE>;
	my $gdt_ts_avr; # read the whole line
	($gdt_ts_avr,$gdt_ts_avr,$gdt_ts_avr,$gdt_ts_avr) = split(/\s+/,$line); # fourth token is gdt_ts_avr
	close(AVERAGELINE);
	
	push(@predictions, {
		ID => $pr_id,
		TARGET => $target,
		GROUP_CODE => sprintf('%03d', $group_code),
		GROUP_NAME => $group_name,
		PFRMAT => $pfrmat,
		MODEL => $model,
		GDT_TS_AVR => $gdt_ts_avr
	});
   }

   #sort
   @predictions = sort {$b->{GDT_TS_AVR} <=> $a->{GDT_TS_AVR}} @predictions;

   return @predictions;
}

sub shuffle {
        my ($self, $servers) = @_;

        my $servers_count = scalar(@{$servers});

        for(my $i = 0; $i < $servers_count; $i++) {
                my $index = int(rand($servers_count - 1));

                my $tmp = $$servers[$i];
                $$servers[$i] = $$servers[$index];
                $$servers[$index] = $tmp;
        }

        return;
}

sub sent_request {
        my ($self, $target_id, $server_id, $is_qa_request) = @_;

        my $distribution_manager = new Distribution(0);
        $distribution_manager->submit($target_id, $server_id, $is_qa_request);
}

# send e-mails with predictions of groups Davis-QAconsensus and Davis-QAconsensusALL
# these groups should be registred in the system
# in CASP_11 they were registered by BM and send from e-mail: bmonastyrskyy@ucdavis.edu
sub submitDavisQApredictions{
    my ($self, $davisQA_groupName, $target, $stage) = @_;
    # check arguments
    if (!(defined $target->{NAME} && defined($stage) && ($stage == 1 || $stage == 2))){
	
	return; # do nothing 
    }
    my $file = sprintf("/data/%s/tmp_QA/%s.%s.stage%s", $LOCAL_CONFIG->{CASP_VERSION}, $target->{NAME}, $davisQA_groupName, $stage);
    if (-f $file){
	my $body = "";
	open F, "< $file";
	while(defined(my $l = <F>)){
		$body .= $l;
	}
	close F; 
	$body .= "\n";
	Email::send_email('bmonastyrskyy@ucdavis.edu', $LOCAL_CONFIG->{SERVERS_DISTRIBUTION_EMAIL}, '', 'bmonast@gmail.com', '', $body);
    }
}

1; 
