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 StatusManager;

use Rearange;
use Logger;

my $VERIFICATORS_DIR = 'Core/bin';

my $AL_VER = 'al_ver';
my $TS_VER = 'ts_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 $AL2TS  = 'al2ts';



my @PREDICTION_TYPES = ('TS', 'DR', 'AL', 'RR', 'FN', 'QA', 'SS');
#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 => $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 => '',
        _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;
    }
    
    
    ##################
    
    if(! $self->models_validation(\@messages)) {
        #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;
        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;
        }
    }
    
    # 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 $i = 0; $i < $models_counts; $i++) {
        if(! $self->severe_validation(\@messages, $models[$i])) {
            my $message = sprintf($MESSAGES->{SEVERE_VALIDATION_FAILED}, $self->{_email}, $self->{_author}, $self->{_target}, $self->{_pfrmat}, $models[$i]);
            $self->notification_errors($message, \@messages, sprintf("%s\_%s", $self->{_prediction_filename}, $models[$i]));
            $error_messages = \@messages;
            $self->add_predictions_log(${$self->{_models}}[$i], "rejected", sprintf("%s\_%s", $self->{_prediction_filename}, $models[$i]), "severe validation");
            #return $result;
            #We have to remove number from array if particular model has errors
            delete ${$self->{_models}}[$i];
            @messages = ();            
        }
    }    
        
    if(scalar(@{$self->{_models}}) <= 0 ) {
        # all are not accepted becouse 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(@{$self->{_models}}); $i++) {
        if (defined(${$self->{_models}}[$i])) {
            if (${$self->{_models}}[$i] ne '') {
                $result = $self->submit(${$self->{_models}}[$i]);
            }
        }
    }
        
    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')) { 
                $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+(T0\S{3})/) || ($line =~ /^TARGET\s+(TR\S{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->{_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);
    }  
    
    #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/casp9/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/casp9/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) {
					$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/casp9/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} ;
    
    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);    
    
    for(my $i = 0; $i < scalar(@{$self->{_models}}); $i++) {
      #for $self->notification($i. " " . scalar(@{$self->{_models}}), ${$self->{_models}}[$i]);
      if (${$self->{_models}}[$i] =~/^[1-5]$/) {
      } else {
        #for debug $self->notification($i. " DELETE", ${$self->{_models}}[$i]);
        delete ${$self->{_models}}[$i];        
      }
    }
    # we dont have to use this shift it dosent help :( shift(@models);
    # we have to clere array from items whith dont follow the rule =~/^[1-5]$/
    
    for(my $i = 0; $i < scalar(@{$self->{_models}}); $i++) {
      if (${$self->{_models}}[$i] eq '' || !defined(${$self->{_models}}[$i])) {      
        delete ${$self->{_models}}[$i];        
      }
    }
    
    #WE SHOULD NOT TO gate error on this step - it is wery strange in casse of error.
    if(@{$self->{_models}} <= 0) {
        push(@{$messages}, $MESSAGES->{MODELS_REARANGE_ERROR});
        $logger->warning("Submission.pm -> Rearange.pm", sprintf("Rearange Procidure is filed!: %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 is exist and notify
    #file parh generation $self->{_prediction_file}.
    # for () {
    # $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)) {
            my $type = '';
            if ($self->{_is_server} != 0) {
                #(($self->{_is_server} != 0)?'server':'human'));
                $type = ($self->{_pfrmat} eq 'QA')?'QA':'server';
            } else {
                $type = 'human';
            }
		my $cancellation_status = $targets_manager->is_canceled($target_id);
		if (($cancellation_status == 1) or ($cancellation_status == 2 and $type == "human")
			or ($cancellation_status == 3 and $self->{_is_server} != 0)) {
			push(@$messages, sprintf("Target '%s' has been cancelled for %s prediction\n", $self->{_target}, 'all'));
			return $result;
		} elsif ($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 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;
		      			push(@MODEL_DATA, "TER\n");
			      		push(@MODEL_DATA, "END\n");
					last;
				}
		      		push(@MODEL_DATA, $_);
			} else {
				push(@MODEL_DATA, $_);
			}
	        }
	        close FILE;    
	}
	if ($is_oligomeric == 1) {
		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("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("chmod ug+rw %s", $accepted_file));
	if ($is_oligomeric == 1) {
		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("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("chmod ug+rw %s", $accepted_file));        
        
	if ($is_oligomeric == 1) {
		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("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");
        
        $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("chmod a+rwx %s", $new_dir));
    }    
    my $new_file = sprintf("%s/%s_%s%s", $new_dir, $self->{_groups_name}, $self->{_pfrmat}, $model_number);
    clean_model($input_file_path, $new_file);
    system(sprintf("chmod a+rw %s", $new_file));
    
    if($self->{_pfrmat} eq 'AL') {
        my $al2ts_results = $self->al2ts($new_file);
        system(sprintf("chmod a+rw %s.pdb", $new_file));

	# 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_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)
#
#	$self->notification($subject, $body, $notification_email_file);
#    
################ Send only to admins (and comment the line above)
#
	$self->notification_tmp($subject, $body, $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', "", $subject, $body);
    #for debug Email::send_email('okrysko@ucdavis.edu', 'okrysko@ucdavis.edu', 'okrysko@ucdavis.edu', "", $subject, $body. 'FILE: ' . $notification_file);
    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);
}



1;
