package ResultsTargetRefinementManager;
use strict;
use warnings;


use DBI;
use Digest::MD5 qw(md5 md5_hex md5_base64);
use DateTime;
use lib qw(Core);
use Database;
use PDBUtils;
use Configuration;
use LocalConfiguration;
use ResultsManager;
use TargetsManager
my $r_m = new ResultsManager();
use CGI qw(:all);
use BO;
our @ISA = qw(BO);
sub new {
    my ($class) = @_;
    my $self = $class->SUPER::new("casp13.refinement_target_results");

    bless $self, $class;
    return $self;
}


sub get_new_model {
    my ($self) = @_;
    my %model = (
########################### system
	id => '',
	targets_id => '',
	domain => 0,
        date => '',
########################## file name
        TARGET => '',
####################### LGA 4
################# SUMMARY
	#n1_4 => '',
	#n2_4 => '',
	#dist_4=> '',
	#nres_4 => '',
	rmsd_4 => '',
	gdt_ts_4 => '',
	#lga_s_4 => '',
	#lga_q_4 => '',
	#gdt_ca_percentage_4 => '',
	#asgn_4 => '',
	#np_p_4 => '',
	gdt_ha_4 => '',
	alignment_4 => '',
	rmsd_all => '',
	lga_4_tr => '',
	INDEX => 0,
########################## ACE
	ace_rms_ca => '',
	ace_rms_all => '',
########################## MAMMOTH TR
	z_score_m => '',
	ln_e_m => '',
########################## DALI TR
	dali_z_score => '',
	dali_align_residues => '',
	dali_rmsd => '',
	dali_raw => '',
########################## LDDT TR
	lddt => '',
########################## CADscore TR
	cad_aa => '',
	cad_ss => '',
########################## RPF
	rpf => '',
########################## SPHERE GRINDER LVR
	sg_lvr_6_2 => '',
	sg_py => '',
########################## MOLPROBITY
	mp_rot_out => '',
	mp_ram_out => '',
	mp_ram_fv => '',
	mp_clash => '',
	mp_score => '',
########################## QCS
	qcs => '',
	conts => '',
########################## SOV
	sov => '',
########################## CE
	ce => '',
########################## TM_score
	tm_score => '',
	tm_align => '',
########################## BK
	codm => '',
	dfm => '',
	handedness => '',
########################## FlexE
	flexe => ''
    );
    return %model;
}

sub is_table_column {
my ($self, $colunm_name) = @_;
my $result = 0;
if(	$colunm_name eq 'id' ||
	$colunm_name eq 'targets_id' ||
	$colunm_name eq 'domain' ||
	$colunm_name eq 'date' ||
	########################### results
	####################### LGA 4
	################# SUMMARY
	#$colunm_name eq 'n1_4' ||
	#$colunm_name eq 'n2_4' ||
	#$colunm_name eq 'dist_4' ||
	#$colunm_name eq 'nres_4' ||
	$colunm_name eq 'rmsd_4' ||
	$colunm_name eq 'gdt_ts_4' ||
	#$colunm_name eq 'lga_s_4' ||
	#$colunm_name eq 'lga_q_4' ||
	$colunm_name eq 'gdt_ha_4' ||
	$colunm_name eq 'alignment_4' ||
	$colunm_name eq 'rmsd_all' ||
	$colunm_name eq 'lga_4_tr' ||
	$colunm_name eq 'ace_rms_ca' ||
	$colunm_name eq 'ace_rms_all' ||
	$colunm_name eq 'z_score_m' ||
	$colunm_name eq 'ln_e_m' ||
	$colunm_name eq 'dali_z_score' ||
	$colunm_name eq 'dali_align_residues' ||
	$colunm_name eq 'dali_rmsd' ||
	$colunm_name eq 'dali_raw' ||
	$colunm_name eq 'lddt' ||
	$colunm_name eq 'cad_aa' ||
	$colunm_name eq 'cad_ss' ||
	$colunm_name eq 'rpf' ||
	$colunm_name eq 'sg_lvr_6_2' ||
	$colunm_name eq 'sg_py' ||
	$colunm_name eq 'mp_rot_out' ||
	$colunm_name eq 'mp_ram_out' ||
	$colunm_name eq 'mp_ram_fv' ||
	$colunm_name eq 'mp_clash' ||
	$colunm_name eq 'mp_score' ||
	$colunm_name eq 'qcs' ||
	$colunm_name eq 'conts' ||
	$colunm_name eq 'sov' ||
	$colunm_name eq 'ce' ||
	$colunm_name eq 'tm_score' ||
	$colunm_name eq 'tm_align' ||
	$colunm_name eq 'codm' ||
	$colunm_name eq 'dfm' ||
	$colunm_name eq 'handedness' ||
	$colunm_name eq 'flexe' 
  ) {
	$result = 1;
	}
    return $result;
}

sub exist_by_parameters {
    my ($self, %model) = @_;
    my $result = 0;
    my $query = sprintf("SELECT rt.id FROM %s rt JOIN casp13.targets tr ON (rt.targets_id = tr.id)
	WHERE tr.id=\'%s\' and  rt.domain =%s ", $self->{_table},
      	$model{targets_id}, $model{domain});
    my $sth = $self->{_database}->query($query);
    #print $query ."\n";
    if(defined($sth) && ($sth->rows() > 0)) {
        my ($id) = $sth->fetchrow_array();
	$result = $id;
    }
    return $result;
}


sub get_rows {
    my ($self, $params) = @_;
    my $field = $params->{field};
    my $order = $params->{order};
    #my $view_targets = $params->{view_targets};
    #my $view = $params->{view};
    #print "Content-Type: text/html; charset=ISO-8859-1\n\n";
    #foreach my $parameter (keys %{$params}) {
    #	print $parameter . " => " . $params->{$parameter}. "<br>";
    #}
    $field = (!defined($field) || ($field eq '')) ? 'tr.name' : $field;
    $order = (!defined($order) || ($order eq '')) ? 'DESC' : $order;

    #### DO MULTIPLE SORTING
    my $count_to_replace = 0;
	while ($field =~ s/, / $order,/ || $count_to_replace >20){
	$count_to_replace ++;
    }
    ####
    my $domain = 0;
    my $sub_query = "";

    if(defined($params->{id}) && ($params->{id} ne '')) {
 	$sub_query .= sprintf(" and rt.id=\'%s\' ", $params->{id});
    }
    ## NOTE DOMAINS NOT IMPLEMENTED FOR REFINEMENT TARGETS
    if(defined($params->{target}) && ($params->{target} ne '')) {
	if ($params->{target} =~ /^R/ && $params->{target} !~ m/^R0957s2/) {
	    $sub_query .= sprintf(" and tr.name=\'%s\' ", $params->{target});
	} elsif ($params->{target} =~ /^(\S+)-D(\S+)/) {
	    $sub_query .= sprintf(" and tr.name=\'%s\' ", $1);
	    $domain = $2;
	} else {
	    $sub_query .= sprintf(" and tr.name=\'%s\' ", $params->{target});
	}
    }
   ## domain defenition
   if(defined($params->{domain}) && ($params->{domain} ne '')) {
	$sub_query .= sprintf(" and rt.domain=\'%s\' ", $params->{domain});
   } elsif( $domain ne 0 ){
	$sub_query .= sprintf(" and rt.domain=\'%s\' ", $domain);
   }

    my @results = ();
    my $query = sprintf("SELECT rt.id, tr.name, tr.id, rt.domain, rt.gdt_ts_4, rt.gdt_ha_4, rt.rmsd_4, rt.alignment_4, ss.number_of_aa, rt.rmsd_all, rt.lga_4_tr, rt.ace_rms_ca, rt.ace_rms_all, rt.z_score_m, rt.ln_e_m, rt.dali_z_score, rt.dali_align_residues, rt.dali_rmsd, rt.dali_raw, rt.lddt, rt.cad_aa, rt.cad_ss , rt.sg_lvr_6_2, rt.mp_rot_out, rt.mp_ram_out, rt.mp_ram_fv, rt.mp_clash, rt.mp_score, rt.rpf, rt.qcs, rt.conts, rt.sov, rt.ce, rt.tm_score, rt.codm, rt.dfm, rt.handedness, rt.flexe, rt.tm_align, rt.sg_py
		FROM %s rt JOIN casp13.targets tr ON  (tr.id = rt.targets_id) JOIN casp13.submitted_sequences ss ON  (ss.id = tr.submitted_sequences_id)
		WHERE 1=1 %s ORDER BY %s %s, domain ASC LIMIT 2500", $self->{_table}, $sub_query, $field, $order);
    my $sth = $self->{_database}->query($query);

    #print $query;

    if(defined($sth) && ($sth->rows() > 0)) {
        my $index = 1;
        while(my($id, $target, $targets_id, $domain, $gdt_ts_4, $gdt_ha_4, $rmsd_4, $alignment_4, $number_of_aa, $rmsd_all ,$lga_4_tr, $ace_rms_ca, $ace_rms_all, $z_score_m, $ln_e_m, $dali_z_score, $dali_align_residues, $dali_rmsd, $dali_raw, $lddt, $cad_aa, $cad_ss, $sg_lvr, $mp_rot_out, $mp_ram_out, $mp_ram_fv, $mp_clash, $mp_score, $rpf, $qcs, $conts, $sov, $ce, $tm_score, $codm, $dfm, $handed, $flexe, $tm_align, $sg_py) = $sth->fetchrow_array()) {
	    push(@results, {
		INDEX => $index,
		ID => $id,
		TARGET => $target,
		TARGETS_ID => $targets_id,
		DOMAIN => $domain,
		gdt_ts => sprintf("%.2f", $gdt_ts_4),
		gdt_ha => sprintf("%.2f", $gdt_ha_4),
		rmsd => sprintf("%.2f", $rmsd_4),
		distances => $alignment_4,
		number_of_aa => $number_of_aa,
		rmsd_all => sprintf("%.2f",$rmsd_all),
		lga_4_tr => sprintf("%.2f",$lga_4_tr),
		ace_rms_ca => sprintf("%.2f",$ace_rms_ca),
		ace_rms_all => sprintf("%.2f",$ace_rms_all),
		z_score_m => sprintf("%.2f",$z_score_m),
		ln_e_m => sprintf("%.2f",$ln_e_m),
		dali_z_score => sprintf("%.2f",$dali_z_score),
		dali_align_residues => $dali_align_residues,
		dali_rmsd => sprintf("%.2f",$dali_rmsd),
		dali_raw => sprintf("%.2f",$dali_raw),
		lddt => sprintf("%.2f",$lddt),
		cad_aa => sprintf("%.2f",$cad_aa),
		cad_ss => sprintf("%.2f",$cad_ss),
		sg_lvr => sprintf("%.2f",$sg_lvr),
		sg_py => (defined($sg_py) && $sg_py ne '' ? sprintf("%.2f", $sg_py) : -1.0),
		mp_rot_out => sprintf("%.2f", $mp_rot_out),
		mp_ram_out => sprintf("%.2f", $mp_ram_out),
		mp_ram_fv => sprintf("%.2f", $mp_ram_fv),
		mp_clash => sprintf("%.2f", $mp_clash),
		mp_score => sprintf("%.2f", $mp_score),
		rpf => sprintf("%.2f", $rpf),
		qcs => sprintf("%.2f", $qcs),
		conts => sprintf("%.2f", $conts),
		sov => sprintf("%.2f", $sov),
		ce => sprintf("%.2f", $ce),
		tm_score => sprintf("%.2f", $tm_score),
		codm => sprintf("%.2f", $codm),
		dfm => sprintf("%.2f", $dfm),
		handedness => sprintf("%.2f", $handed),
		flexe => sprintf("%.2f", $flexe),
		tm_align => sprintf("%.2f", $tm_align),
		}
	    );
	    $index++;
        }
    }
    return @results;
}

sub get_ranges_array {
    my ($self, $full_target) = @_;
    my $range_str = "";
    my $tr_m = new TargetsManager();
    my %tr_info = $tr_m->info($tr_m->get_id_by_name($full_target));
    $range_str = $tr_info{NUMBER_OF_AA};
    my @ranges = ();
    my @subdomains = split(/,/, $range_str);
    #foreach my $subdomain (@subdomains) {
#	    $subdomain =~ /^(\d+)[-](\d+)$/;
#	    for (my $j = int($1); $j <= int($2); $j++) {
#		    push @ranges, $j;
#	    }
#    }
    foreach my $subdomain (@subdomains) {
	my $from = 0;
	my $to = 0;
	if ($subdomain =~ /^(\d+)[-](\d+)$/) {
	    $from = int($1);
	    $to = int($2);
	} elsif($subdomain =~ /^(\d+)$/) {
	    $from = int($1);
	    $to = $from;
	}
	for (my $j = $from; $j <= $to; $j++) {
	    push @ranges, $j;
	}
    }
    return @ranges;

}

sub add_alignment {
    my ($self, $results_id, $flag, $alignment) = @_;
    my $column = undef;
    if ( $flag eq "lddt" ){
        $column = "alignment_lddt";
    } elsif ($flag eq "sg_lvr"){
        $column = "alignment_sg_lvr";
    } elsif ($flag eq "sg_py"){
        $column = "alignment_sg_py";
    } elsif ($flag eq 'gdt_ts_4' || $flag eq 'lga_sda'){
        $column = "alignment_gdt";
    }
    if (!defined($column)){
        return undef; # do nothing
    }
    # check if there exists record with the given results_id
    my $id = $self->exist_alignment($results_id);
    if (!defined($id)) { # insert into
      my $query = sprintf("INSERT INTO casp13.refinement_target_alignment (refinement_target_results_id, %s) VALUES (%s, \'%s\')", $column, $results_id, $alignment);
      my $sth = $self->{_database}->query($query);
    } else { # update results
      my $query = sprintf("UPDATE casp13.refinement_target_alignment SET  %s=\'%s\' WHERE id=%d", $column, $alignment, $id);
      my $sth = $self->{_database}->query($query);
    }
}

sub exist_alignment {
    my ($self, $results_id) = @_;
    my $query = sprintf("SELECT id FROM casp13.refinement_target_alignment WHERE refinement_target_results_id=%d", $results_id);
    my $sth = $self->{_database}->query($query);
    my ($id) = $sth->fetchrow_array();
    if (!defined($id) || $id eq '' || $id <= 0) {
        return undef;
    }
    return $id;
}

sub get_alignment{
    my ($self, $param, $flag) = @_;
    unless (defined($param->{target}) ) {return undef;}
    my $column = undef;
    if (!defined($flag)){
        return undef;
    } elsif ( $flag eq "lddt" ){
        $column = "alignment_lddt";
    } elsif ($flag eq "sg_lvr"){
        $column = "alignment_sg_lvr";
    } elsif ($flag eq 'gdt_ts_4' || $flag eq 'lga_sda'){
        $column = "alignment_gdt";
    } else {
        return undef;
    }
    my $domain_ = 0;
    my $target_ = $param->{target};
    if (defined($param->{domain})){
        $domain_ = $param->{domain};
    }
    if ($target_ =~ m/(\S+)-D(\d+)/){
        $target_ = $1;
        $domain_ = $2;
    }
    my $query = sprintf(
        "SELECT ra.$column FROM casp13.refinement_target_alignment ra
        JOIN casp13.refinement_target_results re ON re.id=ra.refinement_results_id
        JOIN casp13.targets t ON t.id=re.targets_id
        WHERE t.name=\'%s\' AND re.domain=%d LIMIT 1",
        $target_ , $domain_ 
     );
    my $sth = $self->{_database}->query($query);
    if(defined($sth) && ($sth->rows() > 0)) {
       my ($al) = $sth->fetchrow_array();
       return $al;
    } else {
       return undef;
    }
}

sub get_results_alignment{
    my ($self, $param, $metric) = @_;
    my $field = $param->{field};
    my $order = $param->{order};
    if (!defined($param->{target})){
	my @results = ();
	return @results;
    }
    if ($metric eq 'gdt_ts' || $metric eq 'lga_sda'){
        $field = 'rr.gdt_ha_4';
        $order = (!defined($order) || ($order eq '')) ? 'DESC' : $order;
	my $domain_ = 0; my $target_ = $param->{target};
	if (defined($param->{domain})){
		$domain_ = $param->{domain};
	}
        if ($target_ =~ m/^R/ && $target_ !~ m/^R0957s2/) { # for refinement targets domain_index=0 becasuse if name is in format R1234-D1 "-D1" is a part of target name
            $domain_ = 0;
        } elsif ($target_ =~ m/(\S+)-D(\d+)/){
                $target_ = $1;
                $domain_ = $2;
        }
        my $sub_query = sprintf(" AND t.name=\'%s\' AND rr.domain=%d ", $target_, $domain_);
        my @results = ();
        my $query = sprintf("SELECT  t.name, rr.domain, rr.gdt_ha_4, ra.alignment_gdt
                FROM casp13.refinement_target_results rr JOIN casp13.targets t ON  (rr.targets_id = t.id) 
                JOIN casp13.refinement_target_alignment ra ON rr.id=ra.refinement_target_results_id
                WHERE 1=1 %s ORDER BY %s %s LIMIT 2500",  $sub_query, $field, $order);
        my $sth = $self->{_database}->query($query);
        if(defined($sth) && ($sth->rows() > 0)) {
          my $index = 1;
          while(my( $target, $domain, $gdt_ha_4, $alignment) = $sth->fetchrow_array()) {
            my @tokens = split(/\s+/, $alignment);
            my %hash_alignment;
            foreach my $token (@tokens){
                   if ($token =~ m/(\S+):(\S+)/){
                        $hash_alignment{$1} = $2;
                   }
            }
            push(@results, {
                INDEX => $index,
                TARGET => sprintf("%s%s", $target, ($domain == 0? '': "-D$domain")),
                GDT_HA => sprintf("%.2f", $gdt_ha_4),
                HASH_ALIGNMENT => \%hash_alignment,
                }
            );
            $index++;
          }
        }
        return @results;
    } elsif ($metric eq 'lddt') {
        $field = 'rr.lddt' ;
        $order = (!defined($order) || ($order eq '')) ? 'DESC' : $order;
	my $domain_ = 0; my $target_ = $param->{target};
        if (defined($param->{domain})){
                $domain_ = $param->{domain};
        }
        if ($target_ =~ m/^R/ && $target_ !~ m/^R0957s2/) { # for refinement targets domain_index=0 becasuse if name is in format R1234-D1 "-D1" is a part of target name
            $domain_ = 0;
        } elsif ($target_ =~ m/(\S+)-D(\d+)/){
                $target_ = $1;
                $domain_ = $2;
        }
        my $sub_query = sprintf(" AND t.name=\'%s\' AND rr.domain=%d ", $target_, $domain_);
        my @results = ();
        my $query = sprintf("SELECT t.name, rr.domain,  rr.lddt, ra.alignment_lddt
                FROM casp13.refinement_target_results rr JOIN casp13.targets t ON  (rr.targets_id = t.id) 
                JOIN casp13.refinement_target_alignment ra ON rr.id=ra.refinement_target_results_id
                WHERE 1=1 %s ORDER BY %s %s LIMIT 2500",  $sub_query, $field, $order);
        my $sth = $self->{_database}->query($query);
        if(defined($sth) && ($sth->rows() > 0)) {
          my $index = 1;
          while(my( $target, $domain, $lddt,  $alignment) = $sth->fetchrow_array()) {
            my @tokens = split(/\s+/, $alignment);
            my %hash_alignment;
            foreach my $token (@tokens){
                   if ($token =~ m/(\S+):(\S+)/){
                        $hash_alignment{$1} = $2;
                   }
            }
            push(@results, {
                INDEX => $index,
                TARGET => sprintf("%s%s", $target, ($domain == 0? '': "-D$domain")),
                LDDT => sprintf("%.2f", $lddt),
                HASH_ALIGNMENT => \%hash_alignment,
                }
            );
            $index++;
          }
        }
        return @results;
    } elsif ($metric eq 'sg_lvr') {
        $field = 'rr.sg_lvr_6_2';
        $order = (!defined($order) || ($order eq '')) ? 'DESC' : $order;
        my $domain_ = 0; my $target_ = $param->{target};
        if (defined($param->{domain})){
                $domain_ = $param->{domain};
        }
        if ($target_ =~ m/^R/ && $target_ !~ m/^R0957s2/) { # for refinement targets domain_index=0 becasuse if name is in format R1234-D1 "-D1" is a part of target name
            $domain_ = 0;
        } elsif ($target_ =~ m/(\S+)-D(\d+)/){
                $target_ = $1;
                $domain_ = $2;
        }
        my $sub_query = sprintf(" AND t.name=\'%s\' AND rr.domain=%d ", $target_, $domain_);
        my @results = ();
        my $query = sprintf("SELECT t.name, rr.domain, rr.sg_lvr_6_2, ra.alignment_sg_lvr
                FROM casp13.refinement_target_results rr JOIN casp13.targets t ON  (rr.targets_id = t.id) 
                JOIN casp13.refinement_target_alignment ra ON rr.id=ra.refinement_target_results_id
                WHERE 1=1 %s ORDER BY %s %s LIMIT 2500",  $sub_query, $field, $order);
        my $sth = $self->{_database}->query($query);
        if(defined($sth) && ($sth->rows() > 0)) {
          my $index = 1;
          while(my( $target, $domain, $sg_lvr_6_2,  $alignment) = $sth->fetchrow_array()) {
            my @tokens = split(/\s+/, $alignment);
            my %hash_alignment;
            foreach my $token (@tokens){
                   if ($token =~ m/(\S+):(\S+)/){
                        $hash_alignment{$1} = $2;
                   }
            }
            push(@results, {
                INDEX => $index,
                TARGET => sprintf("%s%s", $target, ($domain == 0? '': "-D$domain")),
                SG_LVR_6_2 => sprintf("%.2f", $sg_lvr_6_2),
                HASH_ALIGNMENT => \%hash_alignment,
                }
            );
            $index++;
          }
        }
        return @results;
    } elsif ($metric eq 'sg_py') {
        $field = 'rr.sg_py';
        $order = (!defined($order) || ($order eq '')) ? 'DESC' : $order;
        my $domain_ = 0; my $target_ = $param->{target};
        if (defined($param->{domain})){
                $domain_ = $param->{domain};
        }
	if ($target_ =~ m/^R/ && $target_ !~ m/^R0957s2/) { # for refinement targets domain_index=0 becasuse if name is in format R1234-D1 "-D1" is a part of target name
	    $domain_ = 0;
	} elsif ($target_ =~ m/(\S+)-D(\d+)/) {
            $target_ = $1;
            $domain_ = $2;
        }
        my $sub_query = sprintf(" AND t.name=\'%s\' AND rr.domain=%d ", $target_, $domain_);
        my @results = ();
        my $query = sprintf("SELECT t.name, rr.domain, rr.sg_py, ra.alignment_sg_py
                FROM casp13.refinement_target_results rr JOIN casp13.targets t ON  (rr.targets_id = t.id) 
                JOIN casp13.refinement_target_alignment ra ON rr.id=ra.refinement_target_results_id
                WHERE 1=1 %s ORDER BY %s %s LIMIT 2500",  $sub_query, $field, $order);
        my $sth = $self->{_database}->query($query);
        if(defined($sth) && ($sth->rows() > 0)) {
          my $index = 1;
          while(my( $target, $domain, $sg_py,  $alignment) = $sth->fetchrow_array()) {
            my @tokens = split(/\s+/, $alignment);
            my %hash_alignment;
            foreach my $token (@tokens){
                   if ($token =~ m/(\S+):(\S+)/){
                        $hash_alignment{$1} = $2;
                   }
            }
            push(@results, {
                INDEX => $index,
                TARGET => sprintf("%s%s", $target, ($domain == 0? '': "-D$domain")),
                SG_PY => sprintf("%.2f", $sg_py),
                HASH_ALIGNMENT => \%hash_alignment,
                }
            );
            $index++;
          }
        }
        return @results;
    }
}


1;
