#!/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;

my %domainColor;
 
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';
    }

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

    #printable version of predicted domains.
    if (param('print')) {
	$self->printableDomainPrediction;
        $self->DESTROY;
    }

    if (!$query) {
        $self->SearchForm;
    }
    #validate search
    elsif ($query =~/\w+/) {     
        #wildcard search
        if ($query =~ /\*/) {
            $self->wildCardSearch;
        }
        else {
            $self->ProteinPage;
        }
    }
    #invalid search 
    else { 
        my $mssg = "\'".font({-color=>'red'}, $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 printableDomainPrediction {
########################################################################
    my ($self) = @_;

    $self->getIDs;

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

    if (!$self->locusNm) {

        $showNm = $self->featNm;
    }

    my $title = 'Predicted Features for '. $showNm;

    &printStartPage($self->database, $title, $self->help);
    my $table = $self->showSequenceDomain;
    print p,p, $table ,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 \'".font({-color=>'red'},$self->query)."\' did not return any hits. Wild cards were prepended and appended to your query.";
        $self->{'_query'} = '*'.$self->query.'*';
        $self->{'_append'} = $message;

        $self->wildCardSearch;

        $self->DESTROY;
    }

    my @data = $self->getData;

    #put ',' in long integer
    my $mw = $self->formatNumber($data[0]);
    my $prlen = $self->formatNumber($data[2]);

    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 = $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 $domainUrl = $configUrl->dictyBaseCGIRoot."$db/protein/getDomain?dictyBaseid=" . $self->dictyBaseid;

    my $printUrl = $configUrl->dictyBaseCGIRoot."$db/protein/protein?dictyBaseid=" . $self->dictyBaseid . "&print=1";

    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 @compResourceRows = $self->compResourceRows($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;

    my $predictedDomain = $self->showSequenceDomain;

    #the table of sequence calculation and pulldown menus.
    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(
			    th({-align=>'left'}, 
                                font({-size=>"+1", -color=>'red'}, $redNm ).
			        font({-size=>"+1"}, ' Protein Information')
                            ),
                            th({-align=>'left'}, 
                                font({-size=>'+1', -color=>'red'}, $redNm ).
			        font({-size=>'+1'},' Protein Sequence and Predicted Features' )
                            )
                          
            ),

            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(aa)'),
                           td($prlen)
                        ),

                        Tr({-align=>'center'}, 
			   th({-bgcolor=>'#d8d8d8'}, 'MW(Da)'),
                           td($mw)
                        ),
   
                        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))
                        ) 
                        
                    ), #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")
                        )
                    ),p, #table for codon usage		
                    
		    table({-border=>0},
 
                        [@compResourceRows]
                    )
                ),
                #td on the left, incluing two calculation tables and comparision resources.
	        td( {-valign=>'top'},
                   ul(li("The Signal Peptide Cleavage Site(s)(". $self->getRedArrow .") and Transmembrane Domain(s) (". $self->getTranDomainLengend. ") were predicted using " . a({-href=>"http://www.hgmp.mrc.ac.uk/Software/EMBOSS/"}, "EMBOSS") . " software."), 
                      li("There may be additional motifs in ". font({-color=>'red'}, $redNm) . ". To see those found by sequence comparisons with motifs in the " . a({href=>"http://fold.stanford.edu/emotif/"}, "emotifs database") . ", please click ". a({-href=>$domainUrl}, "here") . "."),
                      li(a({-href=>$proseqUrl}, "Retrieve Protein Sequence")),
                      li(a({-href=>$printUrl, -target=>'pwin'}, "Printer-friendly version of predicted features"))
                   ),

		   $predictedDomain 
                )  #td contain structure and comparison resources

            ) #Tr Info and Structure
        ) 
    );

    &printEndPage;

    return;
}

########################################################################
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 \'".font({-color=>'red'},$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;

    #the query is a feature, however have no protein info.
    if (!@data) {
        my $message = "No Protein Info available for \'".font({-color=>'red'},$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 formLeftRows {
########################################################################
    my ($self, @data) = @_;


    return;
}

########################################################################
sub compResourceRows {
########################################################################

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

    my @row;

    push(@row, Tr(th({-align=>'left'}, 
                      font({-size=>'+1', -color=>'red'}, $redNm ).
		      font({-size=>'+1'},' STRUCTURE AND COMPARISON RESOURCES')))
	 );

    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

    )));

    #interaction
    my $grid = $dictyBase->grid;
    my $bind = $dictyBase->bind;
    my $curagen = $dictyBase->curagen;
    my $dip = $dictyBase->dip;

    my @intval;

    push (@intval, $grid) if $grid;
    push (@intval, $bind) if $bind;
    push (@intval, $curagen) if $curagen;
    push (@intval, $dip) if $dip;

    my %int = ($grid => "Interactions DB (GRID)",
	       $bind=>"Interactions DB ( BIND )",
               $curagen => "Two Hybrid (Portal PathCalling)",
	       $dip=>"DB of Interacting Proteins (DIP)"
    );

    push(@row, Tr(td(
        start_form.
            li(b("Interactions")).$seperator.
                popup_menu(-name=>'inter',
                           -values=>\@intval,
                           -labels=>\%int).
                               button(-onClick=>'switchAddress(this.form.inter)',
                                      -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 => "Literature 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 $syntenyViewer = $dictyBase->syntenyViewer;
    my $fungalAlign = $dictyBase->fungalAlign;

    my @compVal;

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

    my %comparisons = (
                       $syntenyViewer=>'Synteny Viewer',
                       $fungalAlign=>"Fungal alignments",
                       $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

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

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

    my ($hit, $gene, $orf, $alias, $property, $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);

        my $summaryLine = "Your query ".font({-color=>'#FF0000'},$self->query
)." returned ".font({-color=>'#FF0000'},$count)." hits to the following gene names:";
        my $oldQuery = $self->query;
        $oldQuery =~ s/\*//g;

        if ($self->{'_append'}) {
            print center(h2("Your search for ".font({-color=>'red'}, $oldQuery)." did not return any hits."), h2("Wild cards were prepended and appended to your query."));
        }

	print h4($summaryLine);

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

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

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

	    $gene = $object->gene;
	    $orf  = $object->featureName;
	    $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;";
            $property = $self->getProperty($orf);
#	    $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($property).td($function));
	    
	}
	
	print "</TABLE></CENTER>\n";
	
    }
    else{	
        my $mssg = "Your search for \'".font({-color=>'red'},$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 \'".font({-color=>'red'},$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;
}

################################################################
sub getProperty {
################################################################
    my ($self, $featNm) = @_;
    
    my $sth = $dbh->prepare ("
        SELECT p.molecular_weight, p.pi, p.protein_length
        FROM CGM_DDB.feature f, CGM_DDB.protein_info p
        WHERE f.feature_name = ? and
              f.feature_no = p.feature_no 
    ");

    $sth->execute($featNm);

    my ($mw, $pi, $prlen) = $sth->fetchrow;

    $sth->finish;

    $mw = $self->formatNumber($mw);
    $prlen = $self->formatNumber($prlen);

    my $displayStr = "Length(aa): $prlen".p."MW(Da): $mw".p."pI: $pi";

    return $displayStr;
}

################################################################
sub formatNumber {
################################################################
    my ($self, $data) = @_;
    my @data = split(//, $data);
    my $length = length($data);

    my $formattedStr;
    my $count=0;

    for (my $i = $length-1; $i>=0; $i--) {
        $count++;
        $formattedStr .= $data[$i];

        if (($count == 3) && ($i != 0)){
            $formattedStr .= ',';
            $count = 0;
        }
    }    
    return reverse($formattedStr);
}

######################################################################
sub showSequenceDomain {
######################################################################
    my ($self) = @_;

    my ($tranStart, $tranStop, $sigStart, $sigStop);
   
    my $locusNm = $self->locusNm;
    my $featNm = $self->featNm;

    #set the maximum blob size
    $dbh->{LongReadLen} = 10000;

    #retrieve protein sequence from DB
    my $seqSth = $dbh->prepare("
        SELECT r.display_seq, r.seq_length 
        FROM CGM_DDB.display_seq r, CGM_DDB.feature f   
        WHERE f.feature_name = ?  and 
              r.feature_no = f.feature_no and
              r.display_seq_type = 'Protein'
    ");

    $seqSth->execute($featNm);

    my ($sequence, $seqlength) = $seqSth->fetchrow;

    $seqSth->finish;

    #get all protein detail data and categorize them
    my $proteindetailSth = $dbh->prepare("
        SELECT pd.protein_detail_type, pd.start_coord, pd.stop_coord
        FROM CGM_DDB.protein_detail pd, CGM_DDB.protein_info p, CGM_DDB.feature f
        WHERE f.feature_name = ? and
              f.feature_no = p.feature_no and 
              p.protein_info_no = pd.protein_info_no
    ");

    $proteindetailSth->execute($featNm);

    #get all protein detail types
    my $pdtype = $dbh->prepare("
        SELECT distinct protein_detail_type
        FROM CGM_DDB.protein_detail
    ");

    my %domain4disp;
    my $domainRows;  #the predicted domain table
    my %domainDisplaySeq;  #predicted domain sequence

    while ( my ($type, $start, $stop) = $proteindetailSth->fetchrow ) {
        my $coordinate = $start .' - '. $stop;
	$domain4disp{$type}{$coordinate} = $start;
    }
    $proteindetailSth->finish;

    $pdtype->execute;
    
    my @pdType;
    while (my $type = $pdtype->fetchrow) {
        push(@pdType, $type);
    }
    $pdtype->finish;

    foreach my $type (@pdType) {
	if (! $domain4disp{$type} ) {
	    $domain4disp{$type}{'none'} = '1';
        }
    }

    my $colorAref = $self->getColor;

    foreach my $type (sort keys %domain4disp) {
        #pop color scheme
        my $tempColor = shift(@$colorAref) || 'red';
        $domainColor{$type} = $tempColor;

	my %subHash = %{$domain4disp{$type}};
        my $count = 0;
        
        my $domainNm = $type;
        $domainNm =~ s/^(\w)/\U$1/;
        my $symbol = uc($1);  #symbol for displaying this domain

	if ($domainNm eq 'Signal peptide') {
	    $domainNm = 'Signal Peptide Cleavage Site(s)('. $self->getRedArrow . ')';
        }
        elsif ($domainNm eq 'Transmembrane domain') {
	    $domainNm = 'Transmembrane Domain';
        }

        my $domainSeq = '.' x $seqlength;
        
	my $cRows;
        my $bgcolor = $domainColor{$type};
        my $rowNo = keys %subHash;

        #sort coordinates based on value

        foreach my $coord (sort { $subHash{$a} <=> $subHash{$b} } keys %subHash) {
            
            $count++;

            if ($domainNm =~ /^Signal Peptide/) {
		$coord =~ /^(\d+) - \d+/;
                $coord = $1;
	    }

            my $bgcolor = $domainColor{$type};
            if ($count == 1) {
		$domainRows .= Tr({-bgcolor=>$bgcolor},
			      th({-align=>'left', -rowspan=>$rowNo}, $domainNm),
			      td({-align=>'center'}, $coord)
                             ), "\n";
	    }
            else {
		$domainRows .= Tr({-bgcolor=>$bgcolor}, td({-align=>'center'}, $coord)), "\n";
            }

            #when there is no predicted domain, coord = 'none';
            if ($coord eq 'none') {
		$domainSeq = '';   #don't display for this type
            }
            #handle the signal peptide,replace one char (cleavage site)
	    elsif ($domainNm =~ /^Signal Peptide/) {
		substr($domainSeq, $coord - 1, 1) = $symbol;
            } 
            else {
		#replace dot with symbol in domain display seq
		$coord =~ /^(\d+)\D+(\d+)$/;
		my $repLen = $2 - $1 + 1;
		substr($domainSeq, $1 - 1, $repLen) = $symbol x $repLen;
	    }
        }

        if ($domainSeq) {
	    my @dSeq = split(//, $domainSeq);
	    $domainDisplaySeq{$type} = \@dSeq;
        }
    }

    my $seqForDisplay = $self->ConstructDisplaySeq($sequence, $seqlength, %domainDisplaySeq);

    my  $rows =
	    Tr({-bgcolor=>"#a4abc2"},
	       th({-align=>'center'}, "Predicted Feature"),
	       th({-align=>'center'}, "Amino Acid Coordinate(s)")
	    ). "\n".
	    $domainRows. "\n";

    $rows .=
	Tr(
          td({-colspan=>'2', -align=>'center'}, "\n", $seqForDisplay)     
	);
    
    return table({-border=>2 ,-width=>'100%', -cellpadding=>3, -cellspacing=>0, -align=>'center'}, $rows);
}

#######################################################################
sub ConstructDisplaySeq {
#######################################################################
    my ($self, $sequence, $seqlength, %domainDisplayHref) = @_;
    
    my @sequenceChar = split(//, $sequence); 

    #how many aa per row
    my $segment = 50;

    #display in the format of multiple line (50 char per line)
    my $seqCount = 0;
    my $Rows;
    while (@sequenceChar) {
        my $seqLine;
        my $beg = $seqCount+1;
	for (my $i = 0; $i < $segment; $i++) {
            my $char = shift (@sequenceChar);
            last if (!$char);
            $seqCount++;
	    $seqLine .= td(tt( $char )); 
	}
	$Rows .= Tr(td(br));
        $Rows .= Tr(td(font({-size=>'-1'}, 'Sequence')),
                    td("&nbsp"), 
                    td(font({-size=>'-1'}, $beg)), td("&nbsp"),
                    $seqLine);
        
        foreach my $type (sort keys %domainDisplayHref) {
	    my $oneLine;
            my $arrayRef = $domainDisplayHref{$type};
            for (my $i = 0; $i < $segment; $i++) {
		my $char = shift ( @$arrayRef );
                last if (!$char);
                my $bgcolor = $domainColor{$type};
                if ( $char =~ /\./ ) {
		    $oneLine .= td(tt( '.' ));
                }
                elsif ( $type =~ /^signal/ ) {
		    $oneLine .= td(tt( $self->getRedArrow ));
                }
                else {
		    $oneLine .= td({-bgcolor=>$bgcolor}, tt( '.' ));
		}
	    }
            if (length($type) > 15) {
		$type =~ s/^(\S+)\s.*/$1/;
            }

            my $mytype = $type;
            if ($mytype =~ /^signal peptide/) {
		$mytype = 'cleavage site';
	    }
            my $first = substr( $mytype, 0, 1);   
	    substr( $mytype, 0, 1) = uc($first); 
            $Rows .= Tr(td(font({-size=>'-1'}, $mytype)),
                        td("&nbsp"), td("&nbsp"), td("&nbsp"),
                        $oneLine);
        }
    }
    $Rows .= Tr(td(br));

    return table({-align=>'center',
                  -border=>'0',
                  -cellspacing=>'0',
                  -cellpading=>'0'}, $Rows);
#    return;
}

################################################################
sub getRedArrow {
################################################################
    my ($self) = @_;
    return img({-src=>$configUrl->dictyBaseImages.'s_ar_up_red.gif'});
}

################################################################
sub getTranDomainLengend {
################################################################
    my ($self) = @_;
    return "<span style ='background:#CCCC66'>..........</span style>";
}

################################################################
sub getColor {
################################################################
    my ($self) = @_;
    my @color = ('#99cc99', '#cccc66', '#FFCCCC', '#99CCFF');
#    my @color = ('tan', 'silver', 'aqua', 'olive', 'lime', 'maroon', 'red');
    return \@color;
}

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