#!/usr/bin/perl
package ProteinPage;
use strict;

######################################################################
# Author: Stan Dong
# Date:   April, 2002
# Comment: Contains all necessary methods for display of protein info
#          page
######################################################################
 
use DBI;
use CGI qw/:all :html3/;
use CGI::Carp qw(fatalsToBrowser);
use lib "/usr/local/dicty/www_dictybase/db/lib/common";
use Login qw (ConnectToDatabase);
use lib "/usr/local/dicty/www_dictybase/db/lib/dictyBase";
use dictyBaseObject;
use dictyBaseCentralMod qw (:formatPage);
use lib "/usr/local/dicty/www_dictybase/db/lib/dictyBase/Objects";
use ConfigURLdictyBase; 

$| = 1;
 
######################################################################
# Class Globals
######################################################################

my $dbh;

my $seperator;

my $configUrl = ConfigURLdictyBase->new; 

my $db;
 
if (!(user_agent() =~/Mac/i)) { # if it's not MAC IE
    $seperator = br; # need a seperator
}
    
######################################################################
sub new {
######################################################################

    my ($self, %args) = @_;

    $self = {};

    bless $self;

    $self->{'_help'}     = $args{'help'};
    $self->{'_database'} = $args{'database'};

    $dbh = &ConnectToDatabase($self->database);

    if ($args{'database'} eq 'dictyBase') {
        $db = 'dictyBase';
    }
    else {
        $db = 'dictyBaseDEV';
    }

    return $self;
}

sub help { $_[0]->{_help} }
sub database { $_[0]->{_database} }
sub featNm { $_[0]->{_featNm} }
sub locusNm { $_[0]->{_locusNm} }
sub dictyBaseid { $_[0]->{_dictyBaseid} }
sub query { $_[0]->{_query} }
sub queryType { $_[0]->{_queryType} }

######################################################################
sub DESTROY {   ############ destructor ##############################
######################################################################
    if (defined $dbh) {
        $dbh->disconnect;
        exit;
    }
}

######################################################################
sub print {
######################################################################
# This method prints out everything required for the the locus page

    my ($self) = @_;

    my $query;
    my $queryType;

    if (param('locus')) {
        $query = param('locus');
        $queryType = 'locus';
    }
    elsif (param('dictyBaseid')) {
        $query = param('dictyBaseid');
        $queryType = 'dictyBaseid';
    }
    elsif (param('search')) {
        $query = param('search');
        $queryType = 'search';
    }

#    my $query = param('locus') || param('dictyBaseid');

    $self->{'_query'} = $query;
    $self->{'_queryType'} = $queryType;

    if (!$query) {
        $self->SearchForm;
    }
    #validate search
    elsif ($query =~/\w+/) {     
        #wildcard search
        if ($query =~ /\*/) {
            $self->wildCardSearch;
        }
        else {
            $self->ProteinPage;
        }
    }
    #invalid search 
    else { 
        my $mssg = "\'".$query."\' is an invalid input. Please include at least one character or digit in your query\n";
        $self->SearchForm($mssg);    
    }

    $self->DESTROY;
}

#######################################################################
sub SearchForm {
#######################################################################

    my ($self, $mssg) = @_;

    my $title = "Search for Protein Info";

    &printStartPage($self->database, $title, $self->help);

    print center(h2($mssg)) if ($mssg);

    print p,p;

    print center(table({-border=>3, -cellpadding=>4,-cellspacing=>4},
      Tr({-align=>'LEFT'}, [
         td({-bgcolor=>"#b7d8e4", -width=>350},
            "Enter a locus name (ACT1), ORF name (YFL039C) or dictyBaseID (S0001855). The search is case insensitive. Include a ".b("wildcard character"). " (*) at any position of the search item for a broader search.".br.
            table({-border=>0},
               Tr({align=>'LEFT'}, [
                  td(start_form, "Search item : ").
                  td(textfield(-name=>'search', -size=>'25')),
                  td("&nbsp;").td(submit,reset,end_form)
                 ]))
               )
      ])));

    print p,p;

    &printEndPage;

    $self->DESTROY;
}

########################################################################
sub ProteinPage {
########################################################################
# This method prints out a protein page for a given query

    my ($self) = @_;

    $self->getIDs;

    #If the locus have no feature, no protein info
    if (!($self->featNm)) {

        my $message = "Your search for \'".$self->query."\' did not return any hits. Please modify your query and try again!";

        $self->SearchForm($message);
    }

    my @data = $self->getData;

    my $showNm = $self->locusNm.'/'.$self->featNm;

    if (!$self->locusNm) {

        $showNm = $self->featNm;
    }

    my $title = "$showNm Protein Page";

    my $Locus = $self->locusNm || $self->featNm;

#    my $locus_url = "http:///usr/local/dicty/www_dictybase/db/lib/cgi-bin/gene_page.pl?gene_name=$Locus";

    my $locus_url = $configUrl->dictyBaseCGIRoot ."gene_page.pl?gene_name=$Locus";
    my $locus_info = a({-href=>$locus_url},$Locus." Locus Page");

    my $proseqUrl = $configUrl->dictyBaseCGIRoot."$db/getSeq?seq=$Locus&flankl=0&flankr=0&map=p3map";

    my $proseqInfo = a({-href=>$proseqUrl}, "Retrieve Protein Sequence");

    my $redNm = lc($Locus).'p';
    my $first = substr( $redNm, 0, 1);   
    substr( $redNm, 0, 1) = uc($first);

    #for those ORF without a gene name
    if (!$self->locusNm) {

        $redNm = uc($Locus);    
    }

    #construct  rows for the structure and comparison resources
    my @rightRows = $self->formRightRows($redNm);

    &printStartPage($self->database, $title, $self->help);

    my $aaUrl = $configUrl->dictyBaseCGIRoot."$db/protein/aa.pl?locus=".$self->locusNm."&feat=".$self->featNm;
 
    # Here's the javascript code that we include in the document.
    my $javascript =  "
      <SCRIPT language=\"JavaScript\"> 
      <!--
         if (document.layers)
            isNS = true
         else
            isNS = false
         if (document.all)
            isIE = true
         else
            isIE = false
         if (isNS)
            var gBorder = 20; //Minimum image border to avoid scrollbars in NS
         else
            var gBorder = 55; //Minimum image border to avoid scrollbars in IE 
         
         function newwindow() { 
            window.open('$aaUrl','Composition','toolbar=no,location=no,directories=no,status=no,menubar=yes,scrollbars=no,resizable=yes,width=200,height=680,screenX=0,screenY=40,top=40,left=450'); 
         } 

         function switchAddress(list ){	
	    location.href = list.options[list.selectedIndex].value;
         }
      //--> 
      </SCRIPT> "
    ;
   
    print $javascript;

    print center(
        table({-border=>0,-width=>'100%', -cellpadding=>3, -cellspacing=>2, -align=>'center'},

            Tr(
                td({-align=>'right', -colspan=>2},
                    table( {-border=>0, -cellpadding=>2, -cellspacing=>4},
                        Tr(
                            td({-bgcolor=>'#b7d8e4',-align=>'center'},
                                font({-size=>3},$locus_info))
                        )
                    )
                )
            ),

            Tr(
                td({-align=>'center', -colspan=>2},    
                    table( {-border=>0, -width=>'100%', -cellpadding=>2, -cellspacing=>4},
                        Tr(
			    th({-align=>'left'}, 
                                font({-size=>"+1", -color=>'red'}, $redNm ).
			        font({-size=>"+1"}, ' PROTEIN INFORMATION')
                            ),
                            th({-align=>'right'}, 
                                font({-size=>'+1', -color=>'red'}, $redNm ).
			        font({-size=>'+1'},' STRUCTURE AND COMPARISON RESOURCES')
                            )
                          
                        )
                    ) 
                )
            ) #Tr
    ));

    #the table of sequence calculation and pulldown menus.
    print center(
        table({-border=>0,-width=>'95%', -cellpadding=>3, -cellspacing=>2, -align=>'center'},

            Tr(
                td({-align=>'left', -valign=>'top', -rowspan=>'10'},
                
                    table({-border=>2, -width=>325, -cellpadding=>3, -cellspacing=>0},
			Tr({-bgcolor=>"a4abc2"},

			    td({-align=>'center', -colspan=>2},
                                b('Protein Sequence Calculations').
                                br.
                                font({-size=>"-1"}, 'from Predicted Full length Translation')                               
                            )
                        ),

			Tr({-align=>'center'}, 
			   th({-bgcolor=>'#d8d8d8'}, 'N-term'),
                           td($data[3])
                        ),

                        Tr({-align=>'center'}, 
			   th({-bgcolor=>'#d8d8d8'}, 'C-term'),
                           td($data[4])
                        ),
     
                        Tr({-align=>'center'}, 
			   th({-bgcolor=>'#d8d8d8'}, 'Length'),
                           td($data[2])
                        ),

                        Tr({-align=>'center'}, 
			   th({-bgcolor=>'#d8d8d8'}, 'MW'),
                           td($data[0])
                        ),
   
                        Tr({-align=>'center'}, 
			   th({-bgcolor=>'#d8d8d8'}, 'pI'),
                           td($data[1])
                        ),

                        Tr({-align=>'center'},
                           th({-colspan=>2}, font({-size=>'-1'},a({-href=>"javascript:newwindow()"},'Amino Acid Composition (full length)')))
                        ),

                        Tr({-align=>'center'},
                           th({-colspan=>2}, font({-size=>'-1'},$proseqInfo))
                        ) 
                        
                    ), p, #table contain the seq calculation table

                    table({-border=>2, -width=>325, -cellpadding=>3, -cellspacing=>0},
			Tr({-bgcolor=>"a4abc2"},
			    td({-align=>'center', -colspan=>2},
                                b('Transcript Translation Calculations')
                            )
                        ),

                        Tr({-align=>'right'}, 
			   th({-bgcolor=>'#d8d8d8'}, 'Codon Bias'),
                           td($data[5]."&nbsp"."&nbsp")
                        ),

                        Tr({-align=>'right'}, 
			   th({-bgcolor=>'#d8d8d8'}, 'Codon Adaptation Index'),
                           td($data[6]."&nbsp"."&nbsp")
                        ),

                        Tr({-align=>'right'}, 
			   th({-bgcolor=>'#d8d8d8'}, 'Frequency of Optimal Codons'),
                           td($data[7]."&nbsp"."&nbsp")
                        ),

                        Tr({-align=>'right'}, 
			   th({-bgcolor=>'#d8d8d8'}, 'Hydropathicity of Protein'),
                           td($data[8]."&nbsp"."&nbsp")
                        ),

                        Tr({-align=>'right'}, 
			   th({-bgcolor=>'#d8d8d8'}, 'Aromaticity Score'),
                           td($data[9]."&nbsp"."&nbsp")
                        )
                    ) #table for codon usage
               
                ), #td on the left

	        td({-bgcolor=>'#d8d8d8'},

                    table({-border=>0, -width=>'80%', -align=>'center'},
 
                        [@rightRows]
                    )

                )  #td contain structure and comparison resources

            ) #Tr Info and Structure
        ) 
    );

    &printEndPage;
}

########################################################################
sub getIDs {
########################################################################

    my ($self) = @_;

    my $search = $self->query;

    my $searchType = $self->queryType;

    #parameter 'dictyBaseid' only accept dictyBaseid. parameter 'locus' cannot accept dictyBaseid
    my $object;

    if ($searchType eq 'dictyBaseid') {
        $object = dictyBaseObject->new(database=>$self->database, dictyBaseid=>$search); 
    }
    elsif (($searchType eq 'locus') && ($search =~/^[SsLl]\d{7}/)) {

        my $mssg = "Your search for \'".$self->query."\' did not return any hits. Please modify your query and try again!";

        $self->SearchForm($mssg); 
    }
    else {
        $object = dictyBaseObject->new(database=>$self->database, query=>$search);
    }

    if ($object->isMultiple){ 
        $self->wildCardSearch;
        $self->DESTROY;
    }

    $self->{'_featNm'} = $object->featureName;
    $self->{'_locusNm'} = $object->locusName;
    $self->{'_dictyBaseid'} = $object->primarydictyBaseID;

    return;
}

########################################################################
sub getData {
########################################################################

    my ($self) = @_;
    
    my $sth = $dbh->prepare ("
        SELECT p.molecular_weight, p.pi, p.protein_length, 
               p.n_term_seq, p.c_term_seq, p.codon_bias,
               p.cai, p.fop_score, p.gravy_score, p.aromaticity_score
        FROM CGM_DDB.feature f, CGM_DDB.protein_info p
        WHERE f.feature_name = ? and
              f.feature_no = p.feature_no 
    ");

    $sth->execute($self->featNm);

    my @data = $sth->fetchrow;

    $sth->finish;

    if (!@data) {
        my $message = "No Protein Info available for \'".$self->query."\'. Please modify your query and try again!";

        $self->SearchForm($message);
    }

    #trim codonW results
    for (my $i=5; $i<10; $i++) {
    
        $data[$i] = sprintf("%.3f", $data[$i]);
    }

    return @data;
}

########################################################################
sub formRightRows {
########################################################################

    my ($self, $redNm) = @_; 

    my @row;

    my $dictyBase = dictyBaseObject->new(database=>$self->database , dictyBaseid=>$self->dictyBaseid);

    #have to initialize first to get URL.
    $dictyBase->_initURLs;

    #structure and motifs
    my $pdb = $dictyBase->pdbInfo;

    my $motif = $dictyBase->motifInfo;

    my @StrVal;

    push (@StrVal, $pdb) if $pdb;
    push (@StrVal, $motif) if $motif;

    my %Str = ($pdb => 'PDB Homolog Structures',
               $motif => 'Motifs');

    push(@row, Tr(td(
            start_form.
                li(b("Structure and Motifs")).$seperator.
                    popup_menu(-name=>'prot',
                               -values=>\@StrVal,
                               -labels=>\%Str).
                              button(-onClick=>'switchAddress(this.form.prot)',
                                          -name=>'Go').
                                              end_form

    ))) if (@StrVal);

    #Secondary Structure Prediction
    my $secStrbaseURL = $configUrl->dictyBaseCGIRoot."$db/protein/secStructure?Feat=".$self->featNm."&Locus=".$redNm;

    my $heli = $secStrbaseURL."&Type=HW";

    my $pepplot = $secStrbaseURL."&Type=PP";

    my $pepStr = $secStrbaseURL."&Type=PS";

    my @SecVal = ($pepplot, $pepStr, $heli);

    my %Sec = ($heli => 'Helical Wheel',
               $pepplot => 'GCG: PepPlot',
               $pepStr => 'GCG: PepStruct');

    push(@row, Tr(td(
            start_form.
                li(b("Secondary Structure Prediction")).$seperator.
                    popup_menu(-name=>'sec',
                               -values=>\@SecVal,
                               -labels=>\%Sec).
                              button(-onClick=>'switchAddress(this.form.sec)',
                                          -name=>'Go').
                                              end_form

    )));

    #literature
    my $litGuide = $dictyBase->litGuide;

    my $pubMed = $dictyBase->pubMed;

    my @litval;

    push (@litval, $litGuide) if $litGuide;
    push (@litval, $pubMed) if $pubMed;

    my %lit = ($litGuide => "Gene_Info Lit. Guide",
               $pubMed => "PubMed Search");

    push(@row, Tr(td(
        start_form.
            li(b("Literature")).$seperator.
                popup_menu(-name=>'lit',
                           -values=>\@litval,
                           -labels=>\%lit).
                               button(-onClick=>'switchAddress(this.form.lit)',
                                      -name=>'Go').
                                          end_form


    )));

    #Homologs
    my $candidaComp = $dictyBase->candidaComp;
    my $wormComp = $dictyBase->wormComp;
    my $mamComp = $dictyBase->mamComp;

    my @compVal;

    push (@compVal, $candidaComp) if $candidaComp;
    push (@compVal, $wormComp) if $wormComp;
    push (@compVal, $mamComp) if $mamComp;

    my %comparisons = (
                       $candidaComp=>"Candida homologs (CandidaDB)",
                       $mamComp=>"Mammalian Homologs",
                       $wormComp=>"Worm Homologs"
    );

    push(@row, Tr(td(
        start_form.
                li(b("Comparison Resources")).$seperator.
                    popup_menu(-name=>'comp',
                               -values=>\@compVal,
                               -labels=>\%comparisons).
                              button(-onClick=>'switchAddress(this.form.comp)',
                                          -name=>'Go').
                                              end_form

    )));

    return @row;
}

##########################################################
sub printErrMssg {
##########################################################

    my ($self, $message) = @_;

    &printStartPage($self->database, 'Protein Info' , $self->help);

    print p, p, b($message), p, p;

    &printEndPage;

    $self->DESTROY;
}

##########################################################
sub wildCardSearch{
##########################################################

    my ($self) = @_;

    my (@hits, %seenF, %seenL, %name);

    my $query = $self->query;
    my $queryType = $self->queryType;

    $query=~s/\*/\%/g;
    
    $query = uc($query);

    my $sth;

    if ($queryType ne 'dictyBaseid') {
    # first check the features
    $sth = $dbh->prepare("SELECT FEATURE_NAME, FEATURE_NO
                                 from CGM_DDB.feature
                                 WHERE UPPER(FEATURE_NAME) LIKE ?");
    
    $sth->execute($query);
    
    while (my @data = $sth->fetchrow_array){

	$seenF{$data[1]}=uc($data[0]); # remember waht we've seen
	
	push (@data, "featureNo");

        push (@hits, \@data);
    }
    
    $sth->finish;
    
    # now check the locus name - locus name is always upper case
    # however, we have to remember that a sigle locus name can
    # match more than one feature (eg. HXT12), so need to handle
    # this
    
    $sth = $dbh->prepare("SELECT LOCUS_NAME, l.LOCUS_NO, FEATURE_NO
                                    FROM CGM_DDB.LOCUS l, CGM_DDB.FEATURE f
                                    WHERE UPPER(LOCUS_NAME) LIKE ?
                                    AND l.LOCUS_NO = f.LOCUS_NO (+)");
    
    $sth->execute($query);
    
    while (my @data = $sth->fetchrow_array){

	$seenL{$data[1]} = 1;

        # don't want in the table twice if orf is same as gene
	next if ($seenF{$data[2]} && $data[0] eq $seenF{$data[2]}); 

	if ($data[2]){ # it's has a feature, so use that

	    $data[1] = $data[2];
	    $data[2] = "featureNo";

	}else{

	    $data[2] = "locusNo";

	}
  	push (@hits, \@data);
    }
    
    $sth->finish;

    # for the aliases want to get either associated feature no, or locus number
    # so that the resulting link is unambiguous as it is the case that an 
    # alias may map to many loci
    
    $sth = $dbh->prepare("SELECT ALIAS_NAME, FEATURE_NO
                                 FROM CGM_DDB.alias 
                                 WHERE UPPER(ALIAS_NAME) LIKE ?
                                 AND FEATURE_NO IS NOT NULL");
    
    $sth->execute($query);
    
    while (my @data = $sth->fetchrow_array){

	next if ($seenF{$data[1]});
	
	push (@data, "featureNo");

        push (@hits, \@data);
    }
    
    $sth->finish;

    $sth = $dbh->prepare("SELECT ALIAS_NAME, LOCUS_NO
                                 FROM CGM_DDB.alias a, CGM_DDB.locus_alias la
                                 WHERE UPPER(ALIAS_NAME) LIKE ?
                                 AND a.ALIAS_NO = la.ALIAS_NO");
    
    $sth->execute($query);
    
    while (my @data = $sth->fetchrow_array){
	
	next if ($seenL{$data[1]});

	push (@data, "locusNo");

        push (@hits, \@data);
    }
    
    $sth->finish;

    } #end of if 

    # parameter locus does not accept dictyBaseid
    if ($queryType ne 'locus') {

    #check for primarydictyBaseID
    $sth = $dbh->prepare("SELECT dictyBaseid, dictyBaseid
                                 FROM CGM_DDB.dictyBaseid
                                 WHERE UPPER(dictyBaseID) LIKE ?
                                 AND dictyBaseid_type = ?");
    
    $sth->execute($query, "Primary");
    
    while (my @data = $sth->fetchrow_array){
	
	next if ($seenL{$data[1]});

	push (@data, "dictyBaseid");

        push (@hits, \@data);
    }
    }
    
    $sth->finish;

    #exclude non-coding features.
    my @newHits = $self->checkCodingFeature(@hits);

    $self->printWildSearchResultTable("hits"=>\@newHits);
}


# This subroutine prints out the results of a wild card search
###########################################################################
sub printWildSearchResultTable{
###########################################################################
# This subroutine returns a table of the results from a wild card search
# want to have the name in the first column, systematic name in the second, 
# aliases in the third chromosome + coordinate in the next, function in the last

    my ($self, %args) = @_;

    my $hitsRef = $args{'hits'};
    my $string = "<B style=\"color:black;background-color:#ffff66\">";

    my ($hit, $gene, $orf, $alias, $pos, $match, $function, $orig, $functionRef, $object);

    my $show;

    my $query = $self->{'_query'};
    $query =~ s/\*//g; # get rid of the wild cards when doing the regex

    if (@{$hitsRef}){

        my $count = @{$hitsRef};

        &printStartPage($self->database, 'Protein Info Search' , $self->help);

	print h4("Your query returned $count hits:");

	print "<CENTER><TABLE BORDER=\"3\">\n",

	Tr({-align=>'center'},
	   th("Match").th("Name").th("Systematic Name").th("Alias(es)").th("Position Info").th("Function"));
	
	foreach $hit (sort by_Dictyostelium @{$hitsRef}){

	    $object = dictyBaseObject->new($$hit[2]=>$$hit[1],
				     database=>$self->{'_database'});

	    $gene = $object->gene;
	    $orf  = $object->orf;
	    $alias = $object->alias;
	    
            $orf=~s/($query)/$string$1<\/B>/i;
	    $orf ||= "&nbsp;";
	    $gene =~s/($query)/$string$1<\/B>/i;
	    $gene ||= "&nbsp;";
            $alias=~s/($query)/$string$1<\/B>/i;
	    $alias ||="&nbsp;";
	    $pos = $object->positionalInfo || "&nbsp;";
	    ($functionRef) = $object->molFunction;
	    $function = $$functionRef[0] || "&nbsp;";

	    if ($object->primarydictyBaseID){

		$$hit[0] = a({-href=>url."?dictyBaseid=".$object->primarydictyBaseID},
			     $$hit[0]);

	    }else{

		$$hit[0] = a({-href=>url."?featureNo=".$object->featureNo},
			     $$hit[0]);

	    }
	    
	    print Tr(td(b($$hit[0])).td($gene).td($orf).td($alias).td($pos).td($function));
	    
	}
	
	print "</TABLE></CENTER>\n";
	
    }else{	
        my $mssg = "Your search for \'".$self->query."\' did not return any hits. Please modify your query and try again!";
        print $self->SearchForm($mssg);
    }

    &printEndPage;
    
}

####################################################################
sub by_Dictyostelium{
####################################################################
# used for sorting of Dictyostelium ORFs/genes

    my ($worda1, $worda2, $wordb1, $wordb2, $number1, $number2);

    if ($$a[0]=~/(\D+)(\d*)(.*)/){

	$worda1=uc($1);

	$number1=$2;

	$worda2=uc($3);

    }

    if ($$b[0]=~/(\D+)(\d*)(.*)/){

	$wordb1=uc($1);

	$number2=$2;

	$wordb2=uc($3);

    }

    return $worda1 cmp $wordb1 || $number1 <=> $number2 || $worda2 cmp $wordb2;

}

################################################################
sub checkCodingFeature {
################################################################
    my ($self, @hits) = @_;

    my $count = @hits;

    my @newHits = ();

    if ($count > 200) {
        my $msg = "Your search \'".$self->query."\' has returned too many hits. Please refine your query and try again!";
        $self->SearchForm($msg);
    }

    my $sth = $dbh->prepare("
        SELECT feature_no
        FROM CGM_DDB.protein_info 
        WHERE feature_no = ?
        ");

    foreach my $hit (@hits) {
        my $object = dictyBaseObject->new($$hit[2]=>$$hit[1],
				     database=>$self->{'_database'});
        my $featureNo = $object->featureNo;

        $sth->execute($featureNo);

        my $result = $sth->fetchrow();    

        $sth->finish;

        push (@newHits, $hit) if ($result);
    }

    return @newHits;
}

################################################################
1; # to keep the program executable
################################################################
