package Submission;

use strict;
use warnings;

use POSIX qw(strftime);

use lib qw(Core);

use Configuration;
use LocalConfiguration;

use Email;
use Common;
use Database;
use GroupsManager;
use PredictionsManager;
use PredictorsManager;
use MembersManager;
use TargetsManager;
use Account;
use PDBUtils;
use String;
use Messages;

use CopyPredictionsManager;

use StatusManager;

use Rearange;
use Logger;

use MultimerTargetVerificationManager;

my $VERIFICATORS_DIR = 'Core/bin';

my $AL_VER = 'al_ver';
my $TS_VER = 'ts_ver';
my $QS_VER = 'qs_ver';
my $TS_VER_SERV = 'ts_ver_serv';
my $RR_VER = 'rr_ver';
my $DP_VER = 'dp_ver';
my $DR_VER = 'dr_ver';
my $SS_VER = 'ss_ver';
my $QA_VER = 'qa_ver.pl';
my $FN_VER = 'fn_ver.pl';
my $IA_VER = 'ia_ver.pl';

my $AL2TS  = 'al2ts';



my @PREDICTION_TYPES = ('TS', 'DR', 'AL', 'RR', 'QA', 'IA');
#my @PREDICTION_TYPES = ('TS', 'DR', 'AL', 'RR', 'DP', 'FN', 'QA', 'SS');

my $logger = new Logger();
my $status_manager = new StatusManager();

sub new {
    my ($class, $email, $prediction_filename, $type, $predictor_id, $uid, $skip) = @_;
    my @models = ();
    my $self = {
        _database => Database->new($CONFIG->{HOSTNAME}, $CONFIG->{PORT}, $CONFIG->{DATABASE}, $CONFIG->{USERNAME}, $CONFIG->{PASSWORD}),
        
        _email => $email,
        _skip => (defined($skip) ? $skip : ''),
        _predictor_id => (defined($predictor_id) ? $predictor_id : 0),
        _prediction_filename => $prediction_filename,
        _prediction_file => sprintf("%s/%s", $LOCAL_CONFIG->{SUBMITED_PREDICTIONS_DIR}, $prediction_filename),
        _FILEHANDLE => 0,
        _pfrmat => '',
        _type => $type,
        _author => '',
        _model => 0,
        _parent=> '',
        _target => '',
        _target_id => 0,
        _is_server => 0,
        _groups_id => 0,
        _groups_name => '',
	_groups_code => 0, # BM
        _case_id => (defined($uid) ? $uid : 0),
        _models => \@models
    };
    
    my $PREDICTION_FILE;
    if(open($PREDICTION_FILE, $self->{_prediction_file})) {
        $self->{_FILEHANDLE} = $PREDICTION_FILE;
    } else {
        die(sprintf("Cant open file: %s\n", $self->{_prediction_file}));
    }
    
    bless $self, $class;
    return $self;
}

sub DESTROY {
    my ($self) = @_;
    if(defined($self->{_FILEHANDLE})) {
        close($self->{_FILEHANDLE});
    }
}

sub process {
    my ($self, $error_messages) = @_;
    
    my $author = '';
    my $target = '';
    
    my @messages = ();
    
    my $result = 0;
    
    $self->register_prediction();
      
    if(! $self->author_validation(\@messages)) {
        my $message = sprintf($MESSAGES->{AUTHOR_VALIDATION_FAILED}, $self->{_email});
        
        $self->notification_errors($message, \@messages, $self->{_prediction_filename});
        $error_messages = \@messages;
        $self->add_predictions_log(0, "rejected", $self->{_prediction_filename}, "author_validation");
        return $result;
    }
     
    
    if(! $self->database_validation(\@messages)) {
        my $message = sprintf($MESSAGES->{VALIDATION_FAILED}, $self->{_email}, $self->{_author}, $self->{_target}, $self->{_pfrmat});
        
        $self->notification_errors($message, \@messages, $self->{_prediction_filename});
        $error_messages = \@messages;
        $self->add_predictions_log(0, "rejected", $self->{_prediction_filename}, "database validation");
        return $result;
    }    
    

    if(! $self->rough_validation(\@messages)) {
        my $message = sprintf($MESSAGES->{ROUGH_VALIDATION_FAILED}, $self->{_email});
        
        if(($self->{_target} ne '') && ($self->{_author} ne '')) {
            $message = sprintf("%s (%s, %s)", $message, $self->{_author}, $self->{_target})
        } elsif($self->{_target} ne '') {
            $message = sprintf("%s (%s)", $message, $self->{_target})
        } elsif($self->{_pfrmat} ne '') {
            $message = sprintf("%s (%s)", $message, $self->{_pfrmat})
        } elsif($self->{_author} ne '') {
            $message = sprintf("%s (%s)", $message, $self->{_author})
        }  
        
        $self->notification_errors($message, \@messages, $self->{_prediction_filename});
        $error_messages = \@messages;
        $self->add_predictions_log(0, "rejected", $self->{_prediction_filename}, "rough_validation");
        return $result;
    }
    
    my $targets_manager = new TargetsManager();
    my $target_id = $targets_manager->get_id_by_name($self->{_target});
    $self->{_target_id} = $target_id;

    if($self->{_skip} ne "target_validation") {
        if(! $self->target_validation(\@messages)) {
            my $message = sprintf($MESSAGES->{TARGET_VALIDATION_FAILED}, $self->{_email}, $self->{_author}, $self->{_target}, $self->{_pfrmat});
            $self->notification_errors($message, \@messages, $self->{_prediction_filename});
            $error_messages = \@messages;
            $self->add_predictions_log(0, "rejected", $self->{_prediction_filename}, "target_validation");
            return $result;
        }
    }
    $self->is_heteromer_target(); # check if target is heteromer - has two or more chains in fasta seq template
    ##################
    my $models_validation_status = $self->models_validation(\@messages); 
    if(0 == $models_validation_status) {
        #TODO: add checking of model number - it should be from 1 to 5 
        my $message = sprintf($MESSAGES->{VALIDATION_FAILED}, $self->{_email}, $self->{_author}, $self->{_target}, $self->{_pfrmat});
        $self->notification_errors($message, \@messages, $self->{_prediction_filename});
        $error_messages = \@messages;
	$self->add_predictions_log(0, "rejected", $self->{_prediction_filename}, "model_validation");
        return $result;
    }elsif(2 == $models_validation_status){
	my $message = sprintf($MESSAGES->{VALIDATION_WARN},$self->{_email}, $self->{_author}, $self->{_target}, $self->{_pfrmat});
	$self->notification_warn($message, \@messages, $self->{_prediction_filename});
    }
    
    ##################
    
    # SERVER VALIDATION should be performed for a few models separately
    # separate models we will get from models_validation -> Rearange.pm
    my @models = ();
    push(@models, @{$self->{_models}});
    
    my $models_counts = scalar(@models);
    
    for(my $index = 0; $index < $models_counts; $index++) {

	# check if the models TS and AL are not too short 
	if($self->{_pfrmat} eq 'TS'){
		if(! $self->short_3Dstr_validationTS(\@messages, $models[$index])){
		            my $message = sprintf($MESSAGES->{SEVERE_VALIDATION_FAILED}, $self->{_email}, $self->{_author}, $self->{_target}, $self->{_pfrmat}, $models[$index]);
       			    $self->notification_errors($message, \@messages, sprintf("%s\_%s", $self->{_prediction_filename}, $models[$index]));
		            $error_messages = \@messages;
        		    $self->add_predictions_log($models[$index], "rejected", sprintf("%s\_%s", $self->{_prediction_filename}, $models[$index]), "short 3D validation");
		            #We have to remove number from array if particular model has errors
			    $models[$index] = '';
		            @messages = ();            
			    next;
			    
		}
	}
        if($self->{_pfrmat} eq 'AL'){
                if(! $self->short_3Dstr_validationAL(\@messages, $models[$index])){
                            my $message = sprintf($MESSAGES->{SEVERE_VALIDATION_FAILED}, $self->{_email}, $self->{_author}, $self->{_target}, $self->{_pfrmat}, $models[$index]);
                            $self->notification_errors($message, \@messages, sprintf("%s\_%s", $self->{_prediction_filename}, $models[$index]));
                            $error_messages = \@messages;
                            $self->add_predictions_log($models[$index], "rejected", sprintf("%s\_%s", $self->{_prediction_filename}, $models[$index]), "short 3D validation");
                            #We have to remove number from array if particular model has errors
			    $models[$index] = '';
                            @messages = ();
                            next;
                }
        }
	
	# severe validation
        if(! $self->severe_validation(\@messages, $models[$index])) {
            my $message = sprintf($MESSAGES->{SEVERE_VALIDATION_FAILED}, $self->{_email}, $self->{_author}, $self->{_target}, $self->{_pfrmat}, $models[$index]);
            $self->notification_errors($message, \@messages, sprintf("%s\_%s", $self->{_prediction_filename}, $models[$index]));
            $error_messages = \@messages;
            $self->add_predictions_log($models[$index], "rejected", sprintf("%s\_%s", $self->{_prediction_filename}, $models[$index]), "severe validation");
            #We have to remove number from array if particular model has errors
	    $models[$index] = '';
            @messages = ();           
	    next; 
        }

	
	if($self->{_pfrmat} eq 'TS'){
	    # check for Bfactor: at least two different values have to be used
	    # reject model  
#	    if (! $self->Bfactor_validationTS(\@messages, $models[$index])){
#                            my $message = sprintf($MESSAGES->{SEVERE_VALIDATION_FAILED}, $self->{_email}, $self->{_author}, $self->{_target}, $self->{_pfrmat}, $models[$index]);
#                            $self->notification_errors($message, \@messages, sprintf("%s\_%s", $self->{_prediction_filename}, $models[$index]));
#                            $error_messages = \@messages;
#                            $self->add_predictions_log($models[$index], "rejected", sprintf("%s\_%s", $self->{_prediction_filename}, $models[$index]), "single value Bfactor validation");
#                            #We have to remove number from array if particular model has errors
#                            $models[$index] = '';
#                            @messages = ();
#                            next;
#                }
	    # warn 
	    if (! $self->Bfactor_validationTS(\@messages, $models[$index])){
			     my $message = sprintf($MESSAGES->{VALIDATION_WARN},$self->{_email}, $self->{_author}, $self->{_target}, $self->{_pfrmat});
		             $self->notification_warn($message, \@messages, $self->{_prediction_filename});
                }
	    # check HETATM records if any
	    if (! $self->HETATM_validationTS(\@messages, $models[$index])){
		my $message = sprintf($MESSAGES->{SEVERE_VALIDATION_FAILED}, $self->{_email}, $self->{_author}, $self->{_target}, $self->{_pfrmat}, $models[$index]);
                            $self->notification_errors($message, \@messages, sprintf("%s\_%s", $self->{_prediction_filename}, $models[$index]));
                            $error_messages = \@messages;
                            $self->add_predictions_log($models[$index], "rejected", sprintf("%s\_%s", $self->{_prediction_filename}, $models[$index]), "HETATM format");
			    $models[$index] = '';
			    @messages = ();
			    next;
	    }

	}
    }    
        
    if(scalar(@models) <= 0 ) {
        # all are not accepted because of severe_validation
        # we have send all error notifications before so we need just exit
        return $result;
    }    
    # end SERVER VALIDATION
    
    # IF all part of validation is successed we can save predictions as accepted
    
    for(my $i = 0; $i < scalar(@models); $i++) {
        if (defined($models[$i])) {
            if ($models[$i] ne '') {
               $result = $self->submit($models[$i]);
            }
        }
    }
        

   if ($self->{_target} =~ m/^(H|O)/ || $self->{_heteromer_target} == 1) { # assembly/oligomeric target 
	if($self->{_pfrmat} eq "TS"){
		my $multi_manager = new MultimerTargetVerificationManager($self->{_target}, $self);
		$multi_manager->process();		
	}
   }

    # if target is CASPROL and group is CASPROL; and prediction is TS or RR
    # copy predictions to casprol file staructure and database 
    #my $targets_manager = new TargetsManager();

    if($targets_manager->is_casprol_by_name($self->{_target})){
	my $groups_manager = new GroupsManager();
	if($groups_manager->is_casprol($self->{_groups_id})){
	   if($self->{_pfrmat} eq "TS" or $self->{_pfrmat} eq "RR"){
		my $copy_manager = new CopyPredictionsManager($self);
		if(1 == $copy_manager->process()){ # if ok
			$logger->info(sprintf("%s%s%03d_*", $self->{_target},$self->{_pfrmat}, $self->{_groups_code}),"all predictions have been copied  to CASPROL");
		}else{
			$logger->warning(sprintf("%s%s%03d_*", $self->{_target},$self->{_pfrmat}, $self->{_groups_code}),"some (or all) predictions haven't  been copied  to CASPROL");
			#$self->notification_casprol_copy_error("problem copying to CASPROL", sprintf("%s%s%03d_* : %s", $self->{_target},$self->{_pfrmat}, $self->{_groups_code}, "some (or all) predictions haven't  been copied  to CASPROL"));
		}
		
	   }
	}
    }

    return $result;
}

sub register_prediction {
    my ($self) = @_;
    
    if(open(PREDICTION_LOGFILE, sprintf(">> %s", $LOCAL_CONFIG->{PREDICTIONS_LOGFILE}))) {
        printf(PREDICTION_LOGFILE "%-30s%-50s%s\n", strftime("%Y/%m/%d %H:%M:%S", localtime()), $self->{_email}, $self->{_prediction_filename});
        close(PREDICTION_LOGFILE);
    }
    
    return;
}

sub author_validation {
    my ($self, $messages) = @_;
    my $result = 0;
    my $handle = $self->{_FILEHANDLE};
    
    seek($handle, 0, 0);
    while(<$handle>) {
        chomp;
        my $line = $_;        
        # AUTHOR or REMARK_AUTHOR XXXX-XXXX-XXXX or GROUP_NAME for servers possible too
        if(($line =~ /^AUTHOR\s+(\d{4}-\d{4}-\d{4})/) && ($self->{_author} eq '') || ($line =~ /^AUTHOR\s+(\S+)\s*/) && ($self->{_author} eq '') || ($line =~ /^REMARK\s+AUTHOR\s+(\d{4}-\d{4}-\d{4})/) && ($self->{_author} eq '') || ($line =~ /^REMARK\s+AUTHOR\s+(\S+)\s*/) && ($self->{_author} eq '')) {
            $self->{_author} = $1;
            $result = 1;
        }         
    }
    if ($result < 1) {     
        push(@{$messages}, $MESSAGES->{AUTHORIZATION_VALIDATION_FAILED});
    }
    
    return $result;
    
}


        

sub rough_validation {
    my ($self, $messages) = @_;

    my $pfrmat = '';
    my $method = '';
    my $author = '';
    my $target = '';
    my $model = '';
    my $parent = '';
    my $end = 0;
    
    my $required_field_count = 0;
    my $REQUIRED = 5; # if author please set 5
    
    my $handle = $self->{_FILEHANDLE};
    seek($handle, 0, 0);
    while(<$handle>) {
        chomp;
        my $line = $_;
        #print $line;
        #if(($line =~ /^PFRMAT\s+(\S{2})\s+/) && ($pfrmat eq '')) {
        # PFRMAT XX
        if(($line =~ /^PFRMAT\s*(\S*)\s*/) && ($pfrmat eq '')) {
            if (($1 eq 'TS') ||
                ($1 eq 'DR') ||
                ($1 eq 'AL') ||
                ($1 eq 'RR') ||
                #($1 eq 'DP') ||
                #we are not using this type any more ($1 eq 'SS') ||
                ($1 eq 'FN') ||
                ($1 eq 'QA') ||
		($1 eq 'IA')
		) { 
                $required_field_count++;
                $pfrmat = $1;
            }
        }        
        
        # TODO to remove - this field was moved to authorization procedure
        # AUTHOR XXXX-XXXX-XXXX
        #if(($line =~ /^AUTHOR\s+(\d{4}-\d{4}-\d{4})/) && ($author eq '')) {
        #    $required_field_count++;
        #    $author = $1;
        #}
        #
        #if ($self->{_is_server} != 0) {
        #    if(($line =~ /^AUTHOR\s+(\d{4}-\d{4}-\d{4})/) && ($self->{_author} eq '') || ($line =~ /^AUTHOR\s+(\S+)\s*/) && ($self->{_author} eq '') || ($line =~ /^REMARK_AUTHOR\s+(\d{4}-\d{4}-\d{4})/) && ($self->{_author} eq '') || ($line =~ /^REMARK_AUTHOR\s+(\S+)\s*/) && ($self->{_author} eq '')) {
        #    $required_field_count++;
        #    $author = $1;
        #}
            
        
        # TARGET T0XXX
        if(
#         	(  ($line =~ /^TARGET\s+(R0\S{3})/) || ($line =~ /^TARGET\s+(T9\S{3})/) || ($line =~ /^TARGET\s+(T0\S{3})/) || ($line =~ /^TARGET\s+(TR\S{3})/)  )
		($line =~ /^TARGET\s+([a-zA-Z][0-9]{4,4}[0-9a-zA-Z\-]{0,3})/)
         	&& ($target eq '')
         ) {
            $required_field_count++;
            $target = $1;
        }
        
        # MODEL  N  [REFINED|UNREFINED]
        if(($line =~ /^MODEL\s+([1-5]{1})/) && ($model eq '')) {
            $required_field_count++;
            $model = $1;
        }

        
        # METHOD XX
        if ($self->{_is_server} == 0) {
            if(($line =~ /^METHOD\s+(\S+)/) && ($method eq '')) {
                $required_field_count++;
                $method = $1;
            }
            $REQUIRED = $REQUIRED + 1;
        }
        
        # PARENT XX
        if ($pfrmat eq 'TS' || $pfrmat eq 'AL') {
            if(($line =~ /^PARENT\s*(\S*)\s*/) && ($parent eq '')) {
                $required_field_count++;
                $parent = $1;                
            }
            $REQUIRED = $REQUIRED + 1; # if aothor please set 7
        }
        
        
        # END
        if(($line =~ /^END/) && ($end == 0)) {
            $required_field_count++;
            $end = 1;
        }
        
        if($required_field_count == $REQUIRED) {
            last;
        }    
    }    
    $self->{_pfrmat} = $pfrmat;
    # TODO to remove $self->{_author} = $author;
    $self->{_target} = $target;
    $self->{_model} = $model;
    push(@{$self->{_models}}, $model);
    $self->{_parent} = $parent;
    
    if(!defined($pfrmat) || ($pfrmat eq '')) {my $predictors_manager = new PredictorsManager();
        push(@{$messages}, $MESSAGES->{FIELD_PFRMAT_ERROR});
    }
    if ($self->{_is_server} == 0) {
        if(!defined($method) || ($method eq '')) {
            push(@{$messages}, $MESSAGES->{FIELD_METHOD_ERROR});
        }
    }
    #TODO to remove 
    #if(!defined($author) || ($author eq '')) {
    #    push(@{$messages}, $MESSAGES->{FIELD_AUTHOR_ERROR});
    #}
    
    if(!defined($target) || ($target eq '')) {
        push(@{$messages}, $MESSAGES->{FIELD_TARGET_ERROR});
    }
    
    if(!defined($model) || ($model eq '')) {
        push(@{$messages}, $MESSAGES->{FIELD_MODEL_ERROR});
    }
    
    if ($pfrmat eq 'TS' || $pfrmat eq 'AL') {
        if(!defined($parent) || ($parent eq '')) {
            push(@{$messages}, $MESSAGES->{FIELD_PARENT_ERROR});
        }
    }
    
    if(!defined($end) || ($end == 0)) {
        push(@{$messages}, $MESSAGES->{FIELD_END_ERROR});
    }
    
    #for(my $i = 0; $i <= scalar(@{$messages}); $i++) {
    #    printf("%s", scalar($$messages[$i]));
    #}
        
    return ((scalar(@{$messages}) == 0) ? 1 : 0);
}

sub verify {
    my ($self, $verifier, $notes_count, $warnings_count, $errors_count, $model_number) = @_;
    
    my $result = '';
    
    if(open(VERIFIER, sprintf("cd %s; ./%s %s_%s |", $VERIFICATORS_DIR, $verifier, $self->{_prediction_file}, $model_number))) {
        while(<VERIFIER>) {
            my $line = $_;
            
            #we will not write more error masseges if error count more then 10
            if ($$errors_count < 10) {
                $result .= $line;
            }
            
            if($line =~ /^# IMPORTANT NOTE!/) {
                $$notes_count++;
                next;
            }
            
            if($line =~ /^# WARNING!/) {
                $$warnings_count++;
                next;
            }
            
            if($line =~ /^# ERROR!/) {
                $$errors_count++;
                next;
            }
        }
        close(VERIFIER);
    }
    
    if ($$errors_count >= 10) {
                $result .= "Too many ERRORS ...";
    }
    
    return $result;
}


sub al2ts{
    my ($self, $file) = @_;
    
    my $result = '';
    
    if(open(VERIFIER, sprintf("cd %s; ./%s %s |", $VERIFICATORS_DIR, $AL2TS, $file))) {
        while(<VERIFIER>) {
            my $line = $_;            
            $result .= $line;
        }
        close(VERIFIER);
    }    
    return $result;
}


sub severe_validation {
    my ($self, $messages, $model_number) = @_;
    
    my $result = 0;
    my $content = '';
    
    my $notes_count = 0;
    my $warnings_count = 0;
    my $errors_count = 0;
    
    if($self->{_pfrmat} eq 'TS') {
	if ($self->{_target} =~ m/^(H|O)/ || $self->{_heteromer_target} == 1) {
          $content = $self->verify($QS_VER, \$notes_count, \$warnings_count, \$errors_count, $model_number);
	} else {
          if($self->{_is_server}) {
              $content = $self->verify($TS_VER_SERV, \$notes_count, \$warnings_count, \$errors_count, $model_number);
          } else {
              $content = $self->verify($TS_VER, \$notes_count, \$warnings_count, \$errors_count, $model_number);
          }    
	}
    } elsif($self->{_pfrmat} eq 'AL') {
        $content = $self->verify($AL_VER, \$notes_count, \$warnings_count, \$errors_count, $model_number);
    } elsif($self->{_pfrmat} eq 'DP') {
        $content = $self->verify($DP_VER, \$notes_count, \$warnings_count, \$errors_count, $model_number);
    } elsif($self->{_pfrmat} eq 'DR') {
        $content = $self->verify($DR_VER, \$notes_count, \$warnings_count, \$errors_count, $model_number);
    } elsif($self->{_pfrmat} eq 'RR') {
        $content = $self->verify($RR_VER, \$notes_count, \$warnings_count, \$errors_count, $model_number);
    } elsif($self->{_pfrmat} eq 'QA') {
        $content = $self->verify($QA_VER, \$notes_count, \$warnings_count, \$errors_count, $model_number);
    } elsif($self->{_pfrmat} eq 'FN') {
        $content = $self->verify($FN_VER, \$notes_count, \$warnings_count, \$errors_count, $model_number);
    } elsif($self->{_pfrmat} eq 'IA') {
        $content = $self->verify($IA_VER, \$notes_count, \$warnings_count, \$errors_count, $model_number);
    }  
    
    #TODO we have to chack if validaters work correct or crashed  
    
    #TODO check if errors count mo then 10 count mo
    
    if($errors_count > 0) {
        push(@$messages, sprintf("%s\n\n# Number of Warnings:\t%d\n# Number of Errors:\t%d\n", $content, ($notes_count + $warnings_count), $errors_count));
        $result = 0;
    } else {
        $result = 1;
    }
    
    return $result;
}

sub database_validation {
    my ($self, $messages) = @_;
    
    my $result = 0;
    
    my $groups_manager = new GroupsManager();
    
    my $groups_id = $groups_manager->get_id_by_pin($self->{_author});
    
    if($groups_id > 0) {
        $self->{_groups_id} = $groups_id;
    } else {
        $groups_id = $groups_manager->get_id_by_name($self->{_author});
        #do not chack if this group is HUMAN - do not allove them use group name insteg of id 
        $self->{_is_server} = $groups_manager->is_server($groups_id);
        if($groups_id > 0 && $self->{_is_server} != 0) {
            $self->{_groups_id} = $groups_id;
        } else {
            push(@$messages, sprintf("Group with name or registration code: '%s' isn't registered\n", $self->{_author}));
            return $result;    
        }
        
    }
    
    $self->{_is_server} = $groups_manager->is_server($self->{_groups_id});
    my $predictions_manager = new PredictionsManager();
    my $predictors_manager = new PredictorsManager();
    my $account_manager = new Core::Account();
    my $members_manager = new MembersManager();
    if ($self->{_is_server} == 0) {
        my $predictor_id = $self->{_predictor_id};
        
        if(($self->{_type} eq 'email') or ($predictor_id == 0)) {
            $predictor_id = $predictors_manager->predictor_id($account_manager->get_id_by_email($self->{_email}));
        }
        if($predictor_id <= 0) {
            push(@$messages, sprintf("Predictor with email: '%s' is not registered\n", $self->{_email}));
            return $result;
        }
    
        my $role_id = $members_manager->role_id($self->{_groups_id}, $predictor_id);
	my $is_group_member = $members_manager->is_group_member($groups_id, $predictor_id);
	if ($is_group_member <= 0) {
            $logger->warning("predictor not in group", sprintf("email: %s, predictor id: %s, group id: %s", $self->{_email}, $predictor_id, $groups_id));
	    push(@$messages, sprintf("Predictor '%s' is not registered as a member of the group '%s' and has no submitter permissions\n\nIf you want to have submitter permissions then ask the group leader to visit http://predictioncenter.org/casp13/groups.cgi and change permission by clicking icons under the \"Review\" column.", $self->{_email}, $groups_manager->name($groups_id)));
            return $result;
	}
        if(($role_id > 2) || ($role_id < 1)) {
            push(@$messages, sprintf("Predictor '%s' doesn't have submitter permissions for group '%s'\n\nIf you want to have submitter permissions then ask your group leader to visit http://predictioncenter.org/casp13/groups.cgi and change permission by clicking icons under the \"Review\" column.",$self->{_email}, $groups_manager->name($groups_id)));
            return $result;
        } else {
            $result = 1;
        }
    } else {
	my $predictor_id = $predictors_manager->predictor_id($account_manager->get_id_by_email($self->{_email}));
	if ($groups_manager->is_http_server($self->{_groups_id})) {
		  my %server = $groups_manager->info_server($groups_id);
		  my $pattern_domain = $server{EMAIL_DOMAIN};
		  if (exists $server{REQUEST_EMAIL}){
			if (($server{REQUEST_EMAIL} eq $self->{_email}) && ($server{REQUEST_EMAIL} ne '')) {
		    		$result = 1;
			}
		  } 
		  if (exists $server{EMAIL}){
		  	if (($server{EMAIL} eq $self->{_email}) && ($server{EMAIL} ne '')) {
		    		$result = 1;
			}
		  }
		  if (exists $server{RESPONSE_EMAIL}){
		  if (($server{RESPONSE_EMAIL} eq $self->{_email}) && ($server{RESPONSE_EMAIL} ne '')) {
		    		$result = 1;
			}
		  }
		if($predictor_id > 0) {
			my $is_group_member = $members_manager->is_group_member($groups_id, $predictor_id);
			if ($is_group_member > 0) {
				$result = 1;
			}	       
		}
		if ($result == 0) {
			my $actual_email = $self->{_email};
	    		my $index_of_at = index($actual_email, "\@");
			my $email_domain = substr $actual_email, $index_of_at;
			if ('' eq $pattern_domain) {
				$groups_manager->edit_http_server_domain($groups_id, $email_domain);
				$result = 1;	
			} else {
				#if ($email_domain eq $pattern_domain) {
				if (grep {$_ eq $email_domain} split(/,/, $pattern_domain)) {
					$result = 1;
				} else {
					$self->{_email} = $server{EMAIL};
					push(@$messages, sprintf("The prediction has been received from the Internet domain (%s) not linked to your server. Currently we are expecting predictions for this server to come from the domain (%s). \nPlease contact the CASP organizers if you want to have an extra domain to be added to the list of allowed domains for your server.", $email_domain, $pattern_domain));
	        			return $result;
    				}
    			}
		}
	} else { 
		    my %server = $groups_manager->info_server($groups_id);
		    if (exists $server{REQUEST_EMAIL}){
			if (($server{REQUEST_EMAIL} eq $self->{_email}) && ($server{REQUEST_EMAIL} ne '')) {
		    		$result = 1;
			}
		    } 
		    if (exists $server{EMAIL}){
			if (($server{EMAIL} eq $self->{_email}) && ($server{EMAIL} ne '')) {
		    		$result = 1;
			}
		    }
		    if (exists $server{RESPONSE_EMAIL}){
			if (($server{RESPONSE_EMAIL} eq $self->{_email}) && ($server{RESPONSE_EMAIL} ne '')) {
		    		$result = 1;
			}
		    }
		if ($result == 0) {
			if($predictor_id <= 0) {
			        push(@$messages, sprintf("Predictor with email: '%s' is not registered\n", $self->{_email}));
	        		return $result;
			}
			my $is_group_member = $members_manager->is_group_member($groups_id, $predictor_id);
			if ($is_group_member <= 0) {
				push(@$messages, sprintf("Predictor '%s' doesn't have submitter permissions for group '%s'\n\nIf you want to have submitter permissions then ask the group leader to visit http://predictioncenter.org/casp13/groups.cgi and change permission by clicking icons under the \"Review\" column.", $self->{_email}, $groups_manager->name($groups_id)));
	        		return $result;
			}
		}
		$result = 1;
	}
    }
    my %group_info = $groups_manager->info($self->{_groups_id});
    $self->{_groups_name} =$group_info{GROUPNAME} ;
    $self->{_groups_code} = $group_info{CODE}; #BM
    return $result;
}

sub models_validation {
    my ($self, $messages) = @_;
    
    my $result = 0;
    
    #1) Split Models to different files 
    
    #Classes/Utils
    my $path = $self->{_prediction_file};
    
    my $rearange = new Rearange($self->{_prediction_file}, $self->{_prediction_file});
    
    @{$self->{_models}} = ();
    my @models = $rearange->process();
    push(@{$self->{_models}}, @models);    

    # remove models others than 1-5    
    my $index = 0;
    while($index <= $#{$self->{_models}}){
	if(${$self->{_models}}[$index] =~ m/^[1-5]$/){
	   $index++;
	}else{
	   splice @{$self->{_models}}, $index, 1;
	}
    }
    
    if(scalar(@{$self->{_models}})<=0){
	push(@{$messages}, $MESSAGES->{FIELD_MODEL_ERROR});
	push(@{$messages}, $MESSAGES->{MODELS_REARANGE_ERROR});
	return $result;
    }



    # check number of models
    # for predictions DR, RR, FN only 1 model is accepted
    if($self->{_pfrmat} eq 'DR' || $self->{_pfrmat} eq 'RR' || $self->{_pfrmat} eq 'FN' ){
	my $is_1model = 0;
	my $is_others = 0;
	for(my $i = 0; $i < scalar(@{$self->{_models}}); $i++){
		if(${$self->{_models}}[$i]=~ m/^[1]$/){
			$is_1model = 1;
		}else{
			$is_others = 1;
			delete ${$self->{_models}}[$i];
		}
	}
	if(1 == $is_1model){
		$result = 1;
		$#{$self->{_models}} = 0; # set the last idndex of array to 0, i.e. we have 1-element array
		${$self->{_models}}[0] = 1; # set the only element of array value 1, i.e. model '1'
#		if(1 == $is_others){
#			$result = 2;
#			push(@{$messages}, $MESSAGES->{MODEL_ONLYONE_WARN});	
#		}	
	}else{
		push(@{$messages}, $MESSAGES->{FIELD_MODEL_ERROR});
	}
	return $result;
    }elsif($self->{_pfrmat} eq 'QA'){
	my $targets_manager = new TargetsManager();
        my $target_id = $targets_manager->get_id_by_name($self->{_target});
	# if resubmit skip checking dates
	if($self->{_skip}  eq "target_validation"){
               my $is_2model = 0;
               my $is_1model = 0;
               for(my $i = 0; $i < scalar(@{$self->{_models}}); $i++){
                 if(${$self->{_models}}[$i]=~ m/^[2]$/){
                       $is_2model = 1;
                 }elsif(${$self->{_models}}[$i]=~ m/^[1]$/){
                      $is_1model = 1;
                 }else{
                        delete ${$self->{_models}}[$i];
                 }
               }
               if(1 == $is_2model){ # if there exists model 2
                        ${$self->{_models}}[0] = 2;
                        $#{$self->{_models}}=0;
                        my $looks_like = $self->QA_prediction_looks_like($messages, 2);
                        if(2 == $looks_like ){ # if model 2 looks like model 2 should look
                                $result = 1;
                        }else{
                                push(@$messages, sprintf($MESSAGES->{SHORT_QA_MODEL_ERROR}, $self->{_target}, '2'));
                        }

              }elsif(1 == $is_1model){ # if there exists model1 only 
                        my $looks_like = $self->QA_prediction_looks_like($messages, 1);
                        if(1 == $looks_like ){ # model 1 looks like model1 should look 
                          ${$self->{_models}}[0] = 1;
                          $#{$self->{_models}}=0;
                          $result = 1;
                        }
               }else{
                        push(@{$messages}, $MESSAGES->{FIELD_MODEL_ERROR});
                        push(@{$messages}, sprintf($MESSAGES->{MODEL_QA_ERROR}, '1 or 2', $self->{_target}));
                }
               return $result;
	}
	## check if prediction is submitted during stage 1  
	if(0 == $targets_manager->is_expired_QA($target_id,1)){ # target is in stage 1 for QA prediction
	    my $is_1model = 0;
	    my $is_others = 0;
            for(my $i = 0; $i < scalar(@{$self->{_models}}); $i++){
               if(${$self->{_models}}[$i]=~ m/^[1]$/){
                       $is_1model = 1;
                 }else{
                       $is_others = 1;
                       delete ${$self->{_models}}[$i];
                 }
            }
	    if(1 == $is_1model){
                  $#{$self->{_models}} = 0; # set the last index of array to 0, i.e. we have 1-element array
                  ${$self->{_models}}[0] = 1; # set the only element of array value 1 - model '1'
	          if(1 == $self->QA_prediction_looks_like($messages, 1)){ # if model 1 looks like 1
			$result = 1;
		  }else{
			push(@$messages, sprintf($MESSAGES->{SHORT_QA_MODEL_ERROR}, $self->{_target}, '1'));
		  }
	    }else{
		push(@{$messages}, $MESSAGES->{FIELD_MODEL_ERROR});
		push(@{$messages}, sprintf($MESSAGES->{MODEL_QA_ERROR}, '1', $self->{_target}));
	    }
	    return $result;
	## check if prediction is submitted during stage 2
	}elsif(0 == $targets_manager->is_expired_QA($target_id,2)){ # target is in 2nd stage for QA prediction
               my $is_2model = 0;
               my $is_1model = 0;
               for(my $i = 0; $i < scalar(@{$self->{_models}}); $i++){
                 if(${$self->{_models}}[$i]=~ m/^[2]$/){
                       $is_2model = 1;
                 }elsif(${$self->{_models}}[$i]=~ m/^[1]$/){
                      $is_1model = 1;
                 }else{
			delete ${$self->{_models}}[$i];
		 }
               }
               if(1 == $is_2model){ # if there exists model 2
                        
                        ${$self->{_models}}[0] = 2;
                        $#{$self->{_models}}=0;
			my $looks_like = $self->QA_prediction_looks_like($messages, 2);
	                if(2 == $looks_like ){ # if model 2 looks like model 2 should look
        	                $result = 1;
                	}else{
				push(@$messages, sprintf($MESSAGES->{SHORT_QA_MODEL_ERROR}, $self->{_target}, '2'));
			}	
					
              }elsif(1 == $is_1model){ # if there exists model1 only 
			my $looks_like = $self->QA_prediction_looks_like($messages, 1);
			if(2 == $looks_like ){ # model 1 looks like model2 and was submitted during 2nd stage: rename
			  ${$self->{_models}}[0] = 2;
			  $#{$self->{_models}}=0;
			  # rename model 1 to model 2
			  system(sprintf("sed \'s:\\(^MODEL\\).*:\\1  2:\' < %s > %s", $self->{_prediction_file}."_1", $self->{_prediction_file}."_2"));
			  system(sprintf("rm -f %s",$self->{_prediction_file}."_1"));
		 	
			  $result = 2;
			  push(@{$messages}, sprintf($MESSAGES->{MODEL_QA_1TO2_WARN}, $self->{_target}));
			}elsif(1 == $looks_like){
			   push(@{$messages}, sprintf($MESSAGES->{TARGET_EXPIRED_FOR_QA},  $self->{_target}), '1');
			}
	       }else{
			push(@{$messages}, $MESSAGES->{FIELD_MODEL_ERROR});	
			push(@{$messages}, sprintf($MESSAGES->{MODEL_QA_ERROR}, '2', $self->{_target}));
		}
               return $result;

	}else{ # target between stage 1 nad stage 2 : there is one day of break to avoid overlapping since release is at 8:00 and expiration at 12:15
		push(@{$messages}, sprintf($MESSAGES->{TARGET_EXPIRED_FOR_QA},$self->{_target},'1')) ;
		return $result;
	}

    }elsif($self->{_pfrmat} eq 'TS' || $self->{_pfrmat} eq 'AL' || $self->{_pfrmat} eq 'IA'){
    
    	#for(my $i = 0; $i < scalar(@{$self->{_models}}); $i++) {
	#      if (${$self->{_models}}[$i] eq '' || !defined(${$self->{_models}}[$i])) {      
        # 	delete ${$self->{_models}}[$i];        
	#      }
	#}
	$result =1;
   	#return $result; 


    }

    $index = 0;
    while($index <= $#{$self->{_models}}){
        if(${$self->{_models}}[$index] =~ m/^[1-5]$/){
           $index++;
        }else{
           splice @{$self->{_models}}, $index, 1;
        }
    }

       

       #WE SHOULD NOT get error on this step - it is very strange in case of error.
       # if(scalar(@{$self->{_models}}) <= 0) {
       #         push(@{$messages}, $MESSAGES->{MODELS_REARANGE_ERROR});
	#	$result = 0;
        #        $logger->warning("Submission.pm -> Rearange.pm", sprintf("Rearange Procedure is failed!: %s, File: %s", $self->{_email}, $self->{_prediction_file}));
        #        #TODO:  SEND EMAIL TO administrator in case of error.
        #} else {
        #        #$result = 1;
        #}    

        
    #TODO: Check if new files exist and notify
    #file path generation $self->{_prediction_file}.
     for (my $i = 0; $i <scalar(@{$self->{_models}}); $i++ ) {
     my $filepath = sprintf("%s_%s",$self->{_prediction_file}, ${$self->{_models}}[$i]);
     if (-e  $filepath) { }
    	
     } 
    
    return $result;
}


sub target_validation {
    my ($self, $messages) = @_;
    
    my $result = 0;
    
    my $targets_manager = new TargetsManager();
	my $groups_manager = new GroupsManager();
    
    my $target_id = $targets_manager->get_id_by_name($self->{_target});
    
    if($target_id > 0) {        
        $self->{_target_id} = $target_id;
        if($targets_manager->is_published($target_id)) {
#	    if ($self->{_pfrmat} eq 'IA'){
#		return 1;
#	    }
            my $type = '';
            if ($self->{_is_server} != 0) {
                #(($self->{_is_server} != 0)?'server':'human'));
                #$type = ($self->{_pfrmat} eq 'QA')?'QA':'server';
		$type = 'server';
            } else {
                $type = 'human';
            }
	    my $cancellation_status = $targets_manager->is_canceled($target_id);
	    if (($cancellation_status == 1) or (($cancellation_status == 2 or $cancellation_status == 4) and $type eq 'human')
			or ($cancellation_status == 3 and $self->{_is_server} != 0)) {
			push(@$messages, sprintf("Target '%s' has been cancelled for %s prediction\n", $self->{_target}, (($cancellation_status == 1)?'all':'human')));
			return $result;
	    } 

	   if($self->{_pfrmat} eq 'QA'){
		if($targets_manager->is_expired_QA($target_id)){
			push(@$messages, sprintf("Target '%s' has expired for prediction in category \'QA\'\n", $self->{_target}));
			return $result;
		}elsif(! $targets_manager->is_expired_QA($target_id, 1)){ # target in stage 1 
			if($targets_manager->is_canceled_QA($target_id, 1)){ # target canceled for stage 1
				push(@$messages, sprintf("Target '%s' has been cancelled for QA prediction\n", $self->{_target}));
				return $result;
			}
			$result = 1;
		}elsif(! $targets_manager->is_expired_QA($target_id, 2)){ # target in stage 2
                        if($targets_manager->is_canceled_QA($target_id, 2)){ # target canceled for stage 2
                                push(@$messages, sprintf("Target '%s' has been cancelled for QA prediction at stage 2\n", $self->{_target}));
                                return $result;
                        }
			$result = 1;
		}else{
			$result = 1;
		}
	   } else {
		if ($groups_manager->is_extended($self->{_groups_id})) {
			if($targets_manager->is_extended_expired($target_id )) {
				push(@$messages, sprintf("Target '%s' has expired for %s prediction\n", $self->{_target}, 'extended'));
				return $result;
			} else {
				$result = 1;
			}
		} elsif($targets_manager->is_expired($target_id, $type)) {
			push(@$messages, sprintf("Target '%s' has expired for %s prediction\n", $self->{_target},(($self->{_is_server} != 0)?'server':'human')));
                	return $result;
		} else {
			$result = 1;
		}        
	   }
        } else {
            push(@$messages, sprintf("Target '%s' hasn't been published\n", $self->{_target}));
            return $result;    
        }    
    } else {
        push(@$messages, sprintf("Target '%s' doesn't exist\n", $self->{_target}));
        return $result;
    }
    return $result;
}

sub is_heteromer_target{
   my ($self) = @_;
   my $seq_file = sprintf("%s/templates/%s.seq.txt", $LOCAL_CONFIG->{TARGETS_DIR}, $self->{_target});
   open S, "< $seq_file";
   my $count = 0;
   while(defined (my $l = <S>)){
     if ($l =~ m/^>/) {
	$count++;
	if ($count == 2) {
		last;
	}
     }
   }
   close S;
   if ($count >=2 ) {
	$self->{_heteromer_target} = 1;
   } else {
	$self->{_heteromer_target} = 0;
   }
}


sub short_3Dstr_validationTS{
    my ($self, $messages, $model) = @_;
    my $command = sprintf("grep ATOM %s_%1d | grep ' CA ' -c", $self->{_prediction_file}, $model);
    my $n_aa = `$command `;    

    if($n_aa < 20){
	push(@$messages, sprintf($MESSAGES->{SHORT_TSAL_MODEL_ERROR}, $model, $self->{_target}));
	return 0;
    }

    return 1;
}

sub Bfactor_validationTS{
    my ($self, $messages, $model) = @_;
    my $inFile = sprintf("%s_%1d", $self->{_prediction_file}, $model);
    my %hash; # tmp hash to store b-factors 
    open INFILE, "< $inFile ";
        while(defined(my $line = <INFILE>)){
		if ($line !~ m/^ATOM/){next;}
                my $tm_f = substr($line, 60, 6);
                $tm_f =~ s/\s+//g;  # remove spaces
                if ($tm_f =~ /\d+\.*\d*/){
                  $tm_f = sprintf("%6.3f",  $tm_f); # unify the format
                  $tm_f =~ s/\s+//g;  # remove spaces
                  $hash{$tm_f} = 1;
                  if (scalar(keys %hash) > 1){
                        close INFILE;
                        return 1; # ok the test is passed successfully
                  }
		}
        }
    close INFILE; 
    push(@$messages, sprintf($MESSAGES->{BFACTOR_SINGLEVALUE_ERROR}, $model, $self->{_target}));
    return 0;
}

sub HETATM_validationTS{
    my ($self, $messages, $model) = @_;
    my $inFile = sprintf("%s_%1d", $self->{_prediction_file}, $model);
    my $result = 1;
    open INFILE, "< $inFile ";
	while(defined(my $line = <INFILE>)){
		if ($line !~ m/^HETATM/){next;}
		my ($check, $output) = reformat_HETATM_line($line, 0);
		if ($check == 0){
			push(@$messages, sprintf($MESSAGES->{HETATM_FORMAT_ERROR}, $output));
			$result = 0;
		}
	}
    close INFILE;
    return $result;
}

sub short_3Dstr_validationAL{
    my ($self, $messages, $model) = @_;
    my $PFRMAT = 'PFRMAT';
    my $AUTHOR = 'AUTHOR';
    my $TARGET = 'TARGET';
    my $MODEL = 'MODEL';
    my $METHOD = 'METHOD';
    my $REMARK = 'REMARK';
    my $SCORE = 'SCORE';
    my $PARENT = 'PARENT';
    my $END = 'END';
    my $TER = 'TER';
    my $command = sprintf("grep %s %s_%1d -v | grep %s -v | grep %s -v | grep %s -v | grep %s -v | grep %s -v | grep %s -v | grep %s -v | grep %s -v | grep %s -v | grep [0-9] -c", $PFRMAT, $self->{_prediction_file},$model,$AUTHOR,$TARGET,$MODEL,$METHOD,$REMARK,$SCORE,$PARENT,$END,$TER);
    my $n_aa = `$command`;
    if($n_aa < 20){
        push(@$messages, sprintf($MESSAGES->{SHORT_TSAL_MODEL_ERROR}, $model, $self->{_target}));
        return 0;
    }

    return 1;
}

# check number of estamates for servers predictions in QA
# for stage 1 it should be 30 models; for stage 2 - 150 these parameters are set in LocalConfiguration.pm
# to pass test at least 80% of models should be in QA prediction
sub number_models_estimated_QA_validation{
    my ($self, $messages, $model) = @_;
}

# return 1 if prediction looks like for stage1: has 80% of estimates for serverpredictions released at stage1 (30)
# return 2 if prediction looks like for stage2: has 80% of estimates for serverpredictions released at stage2 (150)
# return 0 otherwise
sub QA_prediction_looks_like{
    my ($self, $messages, $model)  =@_;
    my $result = 0;
    my $command = sprintf("grep \"_TS\"  %s_%1d -c", $self->{_prediction_file}, $model);
    my $n = `$command`;
    if(1 == $model){
      if($n >= (0.8 * $LOCAL_CONFIG->{NUMBER_MODELS_QA_STAGE1}) and ($n <= $LOCAL_CONFIG->{NUMBER_MODELS_QA_STAGE1} + 3)){
	return 1;
      }elsif($n >= (0.8 * $LOCAL_CONFIG->{NUMBER_MODELS_QA_STAGE2}) and ($n <= $LOCAL_CONFIG->{NUMBER_MODELS_QA_STAGE2} + 3)){
        return 2;
      }else{
	return 0;
      }
    }
    if(2 == $model){
	if($n >= (0.8 * $LOCAL_CONFIG->{NUMBER_MODELS_QA_STAGE2}) and $n <= $LOCAL_CONFIG->{NUMBER_MODELS_QA_STAGE2} + 3){ 
		return 2;
	}else{
		return 0;
	}
    }
}


sub submit {
    my ($self, $model_number) = @_;
    
    if(!defined($model_number)) {
        $model_number = $self->{_model};    
    }
    my $result = 0;
    
    my $predictions_manager = new PredictionsManager();
    my $predictors_manager = new PredictorsManager();
    
    my $account_manager = new Core::Account();
    my $predictor_id = $self->{_predictor_id};
    
    #TODO WE NED IT BUT CHECK BY ID NOT BY EMAIL
    #TODO need check if it is needed
    #DONE
    if($self->{_type} eq 'email') {
        if ($self->{_is_server} == 0) {
            $predictor_id = $predictors_manager->predictor_id($account_manager->get_id_by_email($self->{_email}));
        } else {
            $predictor_id = $predictors_manager->server_predictor_id($self->{_groups_id});        
        }
    }
    
    $self->{_predictor_id} = $predictor_id;
    
    if($predictions_manager->add($self->{_email}, $self->{_type}, $self->{_pfrmat}, $self->{_target}, $self->{_groups_id}, $model_number, $predictor_id)) {
        $result = 1;
        
        my $groups_manager = new GroupsManager();
        my $accepted_name = $predictions_manager->build_prediction_name($self->{_target}, $self->{_pfrmat}, $model_number, $groups_manager->code($self->{_groups_id}));
        my $accepted_file = sprintf("%s/%s", $LOCAL_CONFIG->{ACCEPTED_PREDICTIONS_DIR}, $accepted_name);

	# RIGHT HERE THE FILE WITH OLIGOMERIC STRUCTURE IS BEING RECOGNIZED AND SAVED (FOR CASP9)
	my $input_model_path = $self->{_prediction_file} . "_" . $model_number;
	my $previous_chain = "none";
	my @MODEL_DATA=();
	my $is_oligomeric = 0;
    	if(open(FILE, $input_model_path)) {
		while(<FILE>){
			my $line = $_;
            
			if($line =~ /^ATOM/) {
				my @atom_line = split(//, $line);
            
				my $chain = trim($atom_line[21]);
            
				if(($chain eq $previous_chain) || ("none" eq $previous_chain)) {
					$previous_chain = $chain;
				} else {
					$is_oligomeric = 1;
		      			if($#MODEL_DATA > 0 && $MODEL_DATA[$#MODEL_DATA] !~ m/^TER/) {push(@MODEL_DATA, "TER\n")};
			      		push(@MODEL_DATA, "END\n");
					last;
				}
		      		push(@MODEL_DATA, $_);
			} else {
				push(@MODEL_DATA, $_);
			}
	        }
	        close FILE;    
	}
	if ($is_oligomeric == 1 && $self->{_target} !~ m/^(H|O)/ && $self->{_heteromer_target} == 0) {
		my $out_model_path = $self->{_prediction_file} . "_" . $model_number . "o";
		system(sprintf("cp -p %s_%s %s", $self->{_prediction_file}, $model_number,  $out_model_path));
		system(sprintf("chgrp users %s", $out_model_path));
		system(sprintf("chmod ug+rw %s", $out_model_path));
        	if(open(FILE_OUT, sprintf("> %s", $input_model_path))) {
        	        print FILE_OUT @MODEL_DATA;
        	close FILE_OUT;
		}		
	}

        #TODO rewrite files AL and TS 
        system(sprintf("cp -p %s_%s %s", $self->{_prediction_file}, $model_number,  $accepted_file));
	system(sprintf("chgrp users %s", $accepted_file));
        system(sprintf("chmod ug+rw %s", $accepted_file));
	if ($is_oligomeric == 1 && $self->{_target} !~ m/^(H|O)/ && $self->{_heteromer_target} == 0) {
		my $tmp_accepted_file = $accepted_file . "o";
		my $tmp_source_file = $self->{_prediction_file} . "_" . $model_number . "o";
	        system(sprintf("cp -p %s %s", $tmp_source_file,  $tmp_accepted_file));
		system(sprintf("chgrp users %s", $tmp_accepted_file));
	        system(sprintf("chmod ug+rw %s", $tmp_accepted_file));
	}
        
        my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);        
        my $date = sprintf("%s_%s_%s-%s-%s",($mon+1), $mday, $hour, $min, $sec);        
        $accepted_file = sprintf("%s_all/%s__%s", $LOCAL_CONFIG->{ACCEPTED_PREDICTIONS_DIR}, $predictions_manager->build_prediction_name($self->{_target}, $self->{_pfrmat}, $model_number, $groups_manager->code($self->{_groups_id})), $date);
        system(sprintf("cp -p %s_%s %s", $self->{_prediction_file}, $model_number, $accepted_file));
	system(sprintf("chgrp users %s", $accepted_file));
        system(sprintf("chmod ug+rw %s", $accepted_file));        
        
	if ($is_oligomeric == 1 && $self->{_target} !~ m/^(H|O)/ && $self->{_heteromer_target} == 0) {
		my $tmp_accepted_file = $accepted_file . "o";
		my $tmp_model_number = $model_number . "o";
		my $tmp_source_file = $self->{_prediction_file} . "_" . $tmp_model_number;
      		system(sprintf("cp -p %s %s", $tmp_source_file, $tmp_accepted_file));
		system(sprintf("chgrp users %s", $tmp_accepted_file));
	    	system(sprintf("chmod ug+rw %s", $tmp_accepted_file));
	        $self->create_clean_model($tmp_model_number,$tmp_accepted_file, "o");
	}

        $self->add_predictions_log($model_number, "accepted", $accepted_name, "save prediction");
	if ($self->{_target} =~ m/^(H|O)/ || $self->{_heteromer_target} == 1) {
	        $self->create_clean_model($model_number,$accepted_file, "");
	} else {
		$self->create_clean_model($model_number,$accepted_file, "");
	}
        
        $self->notification_success(
            sprintf($MESSAGES->{FORMAT_SUCCESS_SUBJECT}, $self->{_author}, $self->{_target}, $self->{_pfrmat}, $model_number),
            sprintf($MESSAGES->{FORMAT_SUCCESS_BODY}, $self->{_email}, $self->{_author}, $self->{_target},$self->{_pfrmat}, $model_number),
            $accepted_name
        );
    }
    
    return $result;
}

sub add_predictions_log {
    my ($self, $model_number, $status, $file_name, $return_name) = @_;
        $status_manager->add_predictions_log($self->{_groups_id},
        $self->{_author}, $self->{_target_id}, $self->{_target},
        $model_number, $self->{_pfrmat}, $status, $file_name,
        $self->{_case_id}, $self->{_email}, $return_name, $self->{_predictor_id}, $self->{_type});    
    
}

sub create_clean_model {
    my ($self, $model_number, $input_file_path, $add_to_folder_name) = @_;
    my $new_dir = sprintf("%s/%s", $LOCAL_CONFIG->{CLEAN_PREDICTIONS_DIR}, $self->{_target} . $add_to_folder_name);
    if(!(-e $new_dir)) {
        system(sprintf("mkdir %s", $new_dir));
	system(sprintf("chgrp users %s", $new_dir));
        system(sprintf("chmod ug+rwx %s", $new_dir));
    }    
    #my $new_file = sprintf("%s/%s_%s%s", $new_dir, $self->{_groups_name}, $self->{_pfrmat}, $model_number);
    my $new_file = sprintf("%s/%s%s%03d_%s", $new_dir, $self->{_target}, $self->{_pfrmat}, $self->{_groups_code},$model_number);
    if($add_to_folder_name eq 'o' || $self->{_target} =~ m/(H|O)/ || $self->{_heteromer_target} == 1){
       clean_model($input_file_path, $new_file, 1); # keep chain (third arg=1)
    }else{
       clean_model($input_file_path, $new_file); # remove chain
    }
    system(sprintf("chgrp users %s", $new_file));
    system(sprintf("chmod ug+rw %s", $new_file));
    
    if($self->{_pfrmat} eq 'AL') {
        my $al2ts_results = $self->al2ts($new_file);
	system(sprintf("chgrp users %s.pdb", $new_file));
        system(sprintf("chmod ug+rw %s.pdb", $new_file));
	#open FILEPDB, "> $new_file.pdb"	;
	#print FILEPDB $al2ts_results."\n" ;
	#close (FILEPDB);


	    if($add_to_folder_name eq 'o' || $self->{_target} =~ m/(H|O)/ || $self->{_heteromer_target} == 1 ){
	       	clean_model($new_file.".pdb", $new_file.".tmp", 1); # keep chain (third arg=1)
	    }else{
	       clean_model($new_file.".pdb", $new_file.".tmp"); # remove chain
	    }

	system(sprintf("mv $new_file.tmp $new_file")); # substitute original file with prediction AL  by file with pdb structure
	system(sprintf("chgrp users %s", $new_dir));
	system(sprintf("chmod ug+rw %s", $new_file));
	system(sprintf("rm $new_file.pdb ")); 

	# Commented to suppress messages about AL2TS conversion
        # Email::send_email('casp@predictioncenter.org', 'casp@predictioncenter.org', 'casp@predictioncenter.org', "", "AL2TS", $al2ts_results . 'FILE: ' . $new_file);
        
    }
    
}

sub notification_errors {
    my ($self, $subject, $messages, $notification_email_file) = @_;
    
    my $body = sprintf("%s\n\n", $MESSAGES->{FORMAT_ERROR_HEADER});
    for(my $i = 0; $i < @{$messages}; $i++) {
        $body .= $$messages[$i] . "\n\n";
    }
    
    $body .= $MESSAGES->{FORMAT_ERROR_FOOTER};
    
    $self->notification($subject, $body, $notification_email_file);
    
    return;
}

sub notification_warn {
    my ($self, $subject, $messages, $notification_email_file) = @_;

    my $body = sprintf("%s\n\n", $MESSAGES->{FORMAT_WARN_HEADER});
    for(my $i = 0; $i < @{$messages}; $i++) {
        $body .= $$messages[$i] . "\n\n";
    }

    $body .= $MESSAGES->{FORMAT_WARN_FOOTER};

    $self->notification($subject, $body, $notification_email_file);

    return;
}

sub notification_casprol_copy_error{
    my ($self, $subject, $body) = @_;
    Email::send_email($CONFIG->{SUPPORT_EMAIL}, $CONFIG->{SUPPORT_EMAIL_ADMIN}, $CONFIG->{SUPPORT_EMAIL_ADMIN}, $CONFIG->{SUPPORT_EMAIL_ADMIN}, $subject, $body);
}

sub notification_success {
    my ($self, $subject, $body, $notification_email_file) = @_;    
    $body = sprintf("%s\n%s", $MESSAGES->{SUCCES_TMP_NOTIFICATION}, $body);    

################ Send to curators (comment the line in the next section)
# FOR TESTING BEFORE CASP SEASON
#
#	$self->notification($subject, $body, $notification_email_file);
#    
################ Send only to admins (and comment the line above)
# DURING CASP SEASON
#
####	$self->notification_tmp($subject, $body, $notification_email_file);
	$self->notification_tmp($subject, '', $notification_email_file);
#
################
#
    return;
}

sub notification {
    my ($self, $subject, $body, $notification_email_file) = @_;
    $body = sprintf("%s\n\nCase number is: %s", $body, $self->{_case_id});
    
    #Change email to Curator email if server
    my $email_to = $self->{_email};
    if ($self->{_is_server} != 0) {
        $subject = sprintf("%s - SERVER", $subject);
        my $groups_manager = new GroupsManager();        
        my $email_to_tmp = $groups_manager->get_curator_email_by_id($self->{_groups_id});
        if(defined($email_to_tmp) && $email_to_tmp ne 0 && $email_to_tmp ne '') {
            $email_to = $email_to_tmp;        
        }
    }
    
    my $notification_file = sprintf("%s/%s", $LOCAL_CONFIG->{NOTIFICATION_EMAIL_DIR}, $notification_email_file);
        
    if(open(OUT_FILE ,">" . $notification_file)) {
    	print (OUT_FILE sprintf("%s\n\n%s",$subject,$body));
    	close (OUT_FILE);        
    	system(sprintf("chmod a+r %s", $notification_file));
    }
    
    Email::send_email($CONFIG->{SUPPORT_EMAIL}, $email_to, 'casp@predictioncenter.org', 'casp@predictioncenter.org', $subject, $body);
#    Email::send_email($CONFIG->{SUPPORT_EMAIL}, $email_to, 'bmonast@gmail.com', "", $subject, $body. 'FILE: ' . $notification_file); #for debug
#    Email::send_email($CONFIG->{SUPPORT_EMAIL}, 'casp@predictioncenter.org', 'casp@predictioncenter.org', $CONFIG->{SUPPORT_EMAIL_ADMIN}, $subject, $body);
}

sub notification_tmp {
    my ($self, $subject, $body, $notification_email_file) = @_;
    $body = sprintf("%s\n\nCase number is: %s", $body, $self->{_case_id});
    
    #Change email to Curator email if server
    my $email_to = $self->{_email};
    if ($self->{_is_server} != 0) {
        $subject = sprintf("%s - SERVER", $subject);
        my $groups_manager = new GroupsManager();        
        my $email_to_tmp = $groups_manager->get_curator_email_by_id($self->{_groups_id});
        if(defined($email_to_tmp) && $email_to_tmp ne 0 && $email_to_tmp ne '') {
            $email_to = $email_to_tmp;        
        }
    }
    
    my $notification_file = sprintf("%s/%s", $LOCAL_CONFIG->{NOTIFICATION_EMAIL_DIR}, $notification_email_file);
        
    if(open(OUT_FILE ,">" . $notification_file)) {
    	print (OUT_FILE sprintf("%s\n\n%s",$subject,$body));
    	close (OUT_FILE);        
    	system(sprintf("chmod a+r %s", $notification_file));
    }
    
    
   
   # Email::send_email($CONFIG->{SUPPORT_EMAIL}, 'casp@predictioncenter.org', 'casp@predictioncenter.org', $CONFIG->{SUPPORT_EMAIL_ADMIN}, $subject, $body);
    
   Email::send_email($CONFIG->{SUPPORT_EMAIL}, $CONFIG->{SUPPORT_EMAIL_ADMIN}, $CONFIG->{SUPPORT_EMAIL_ADMIN}, $CONFIG->{SUPPORT_EMAIL_ADMIN}, $subject, $body); 
}



1;
