package dictyBaseObject;

##########################################################
#                                                        #
# dictyBase Extension of dictyBaseObject                 #
#                                                        #
##########################################################

use dictyBaseObject_base;

BEGIN { %dictyBaseObject:: = %dictyBaseObject_base:: }

use DictyBaseConfig;
use Data::Dumper;

our %num2name = ('1'=>'1', '2'=>'2', '3'=>'3',
               '4'=>'4', '5'=>'5', '6'=>'6', '7'=>'M',
               '8'=>'2F', '9'=>'3F', '10'=>'F');




#
# return 0
#
sub openBio{
   my ($self) = shift;
   return 0;
}

#
#  tweaked performance by taking out $self->isFeatureName unless no locus name and no alias name found
#
####################################################################
sub _resolveQuery{
####################################################################
# This subroutine resolves a query to the correct orf, gene and
# aliases

    my ($self) = shift;

    # first we simply check what we've got

    my ($isFeatureName, $isLocusName, $isAliasName);

    my $isdictyBaseID = $self->_isdictyBaseID;

    if (!$isdictyBaseID){ # only check the others if it's not an dictyBaseID

     #  $isFeatureName = $self->isFeatureName;
        $isLocusName =  $self->isLocusName;
        $isAliasName =  $self->isAliasName;

    }


   #
   # only check featurename if no locusname and no aliasname is found
   #  (this is for performance reasonse -EJ
   #
    $isFeatureName = ($isLocusName ||  $isAliasName) ? 0 : $self->isFeatureName;

    my $total = $isdictyBaseID + $isFeatureName + $isLocusName + $isAliasName;

    if ($total == 0){

        return; # can't fill out any object parameters, as it doesn't resolve

    }elsif ($total > 1){

        # need to cope here with the fact that something may resolve
        # as both a locus_name and a feature_name, simply because for
        # some features they have the identical name (bar casing) for
        # the locus, eg snR48

        # we don't want to treat these as multiples, but instead
        # treat them as resolvable to a single enntity

        if ($isFeatureName && $isLocusName == 1 && !$isAliasName){

            my $sth = $dbh->prepare("SELECT LOCUS_NO
                                            FROM CGM_DDB.FEATURE
                                            WHERE FEATURE_NO = ?");

            $sth->execute($self->{'_featureNo'});

            my $check = $sth->fetchrow;

            $sth->finish;

            if ($check != $self->{'_locusNo'}){
                $self->{'_isMultiple'} = 1; # it had more than one hit
                return; # can't correctly resolve
            }

        }else{

            $self->{'_isMultiple'} = 1; # it had more than one hit
            return; # can't correctly resolve

        }


    }

    # if we get here, it must resolve to a single type, so we can fill out
    # the rest of the object

    if ($isdictyBaseID){

        $self->_populateBydictyBaseID;

    }elsif ($isFeatureName){ # requires we have the feature number

        $self->_populateByFeature;

    }elsif ($isLocusName){ # requires we have the locus no

        $self->_populateByLocus;

    }elsif ($isAliasName){

        $self->_populateByAlias;

    }

}

#
#  changed to inner join to exclude aliases not associated with
#  a gene, should figure out why these exist though
#
#############################################################################
sub isAliasName{
#############################################################################
# This method determines whethher the passed in query is an alias_name

    my ($self) = @_;

    my $sth = $dbh->prepare("SELECT a.ALIAS_NO
                                    FROM CGM_DDB.ALIAS a
                                    INNER JOIN CGM_DDB.LOCUS_ALIAS la
                                       ON la.ALIAS_NO = A.ALIAS_NO
                                    WHERE UPPER(a.ALIAS_NAME) = ?");

    $sth->execute(uc($self->{'_query'}));

    $self->{'_aliasNo'} = $sth->fetchrow;

    $sth->finish;

    return (1) if $self->{'_aliasNo'}; # note we return here if we found nothing

    return (0);

}

#
#  dictyBase has no motifs so overrid with function which always returns false
#
######################################################################################################
sub motifInfo {
######################################################################################################
# This method returns a boolean to indicate whether the orf name has motif info associated with.
    my ($self) = shift;
    return undef;
}

#
#
# take out discoideum and use Locus::searchString to return "or" list of locus name and aliases;
#
sub pubMed {

    my ($self) = @_;
    my $ncbi = "http://www.ncbi.nlm.nih.gov/";


     if ($self->{'_locusName'}) {
        my $locusObj = Locus->new(        dbh => $dbh,
                                   locus_name => $self->{'_locusName'}
                                    );

        return $ncbi."entrez/query.fcgi?cmd=search&db=PubMed&term=%28".$locusObj->searchString."%5bTEXT%3anoexp%5d%20AND%20Dictyostelium%5bALL%5d%29"
     }
}


#
# want to leave out 'secondary' features ( a dictyBase thing)
#
#############################################################################
sub isLocusName{
#############################################################################
# this method determines if the passed in query is a locus_name
# however need to remember that a locus_name may correspond to multiple
# features - need to find how many

    my ($self) = @_;

    my $count;

    my $sth = $dbh->prepare("SELECT COUNT (*), l.LOCUS_NO
                                    FROM CGM_DDB.v_PRIMARY_feature f, CGM_DDB.locus l
                                    WHERE UPPER(LOCUS_NAME) = ?
                                    AND l.LOCUS_NO = f.LOCUS_NO (+)
                                    GROUP BY l.LOCUS_NO");

    $sth->execute(uc($self->{'_query'}));

    ($count, $self->{'_locusNo'}) = $sth->fetchrow_array;

    $sth->finish;

    return ($count);

}


#
#
#  the case where there is no feature attached to the locus was accounted for
#   in an extra query
#
#############################################################################
sub _populateByLocus{
#############################################################################
# This subroutine fleshes out the object.  It absolutely requires that the
# $self->{'_locusNo'} has been set

    my ($self) = shift;
    if (!$self->{'_locusNo'}){

        die '_populateByLocus called without having previously set $self->{\'_featureLocus\'}\n';

    }

    my $locusHolder = $self->{'_locusNo'};
    $self->_populateByNumber("l.LOCUS_NO", "l.LOCUS_NO = f.LOCUS_NO", $self->{'_locusNo'});

    #
    #   added next query for the case where there is no feature
    #   attached to the locus.  Used to have in _populate_ByNumber
    #   but realized that is was only valid for loci, so moved to
    #   this sub
    #
    #

    if (!$self->{'_featureNo'}) {

       my $sth = $dbh->prepare("
              SELECT FEATURE_NO, FEATURE_NAME,
                     f.CHROMOSOME, START_COORD,
                     STOP_COORD, STRAND, IS_ON_PMAP, s.dictyBaseID, BRIEF_ID,
                     l.LOCUS_NO, LOCUS_NAME, l.CHROMOSOME,
                     GENETIC_POSITION, ENZYME, DESCRIPTION
              FROM   CGM_DDB.v_primary_FEATURE f, CGM_DDB.LOCUS l, CGM_DDB.dictyBaseID s
              WHERE  l.LOCUS_NO         = ?
              AND    l.LOCUS_NO         = f.LOCUS_NO(+)
              AND    s.primary_key      = l.locus_no
              AND    s.tab_name         = 'LOCUS'
              AND    s.dictyBaseid_type = 'Primary'

       ");
       $sth->execute($locusHolder);

       ($self->{'_featureNo'}, $self->{'_featureName'}, $self->{'chr'}, $self->{'begCoord'},
       $self->{'endCoord'}, $self->{'_strand'}, $self->{'_isOnPMap'}, $self->{'_primarydictyBaseID'} , $self->{'_briefId'},
       $self->{'_locusNo'}, $self->{'_locusName'}, $self->{'_genChr'}, $self->{'_genPos'},
       $self->{'_enzyme'}, $self->{'_description'}) = $sth->fetchrow_array;

       $sth->finish;
    }
}


#
# want to leave out 'secondary' features ( a dictyBase thing)
#
################################################################################
sub _populateByNumber{
################################################################################
# This is a generic populator, that will populate an object using either a locus_no
# or a feature_no, depending on what was passed in

    my ($self, $column, $string, $number) = @_;

    my ($fdictyBaseid, $ldictyBaseid);

    my $sth = $dbh->prepare("
        SELECT FEATURE_NO, FEATURE_NAME,
               f.CHROMOSOME, START_COORD,
               STOP_COORD, STRAND, IS_ON_PMAP, BRIEF_ID,
               l.LOCUS_NO, LOCUS_NAME, l.CHROMOSOME,
               GENETIC_POSITION, ENZYME, DESCRIPTION
        FROM   CGM_DDB.V_PRIMARY_FEATURE f, CGM_DDB.LOCUS l
        WHERE  $column            = ?
        AND    $string(+)
   ");


   $sth->execute($number);

   ($self->{'_featureNo'}, $self->{'_featureName'}, $self->{'chr'}, $self->{'begCoord'},
   $self->{'endCoord'}, $self->{'_strand'}, $self->{'_isOnPMap'}, $self->{'_briefId'},
   $self->{'_locusNo'}, $self->{'_locusName'}, $self->{'_genChr'}, $self->{'_genPos'},
   $self->{'_enzyme'}, $self->{'_description'}) = $sth->fetchrow_array;



    my $sth = $dbh->prepare("
   SELECT DICTYBASEID FROM DICTYBASEID
    WHERE PRIMARY_KEY = ?
         AND TAB_NAME = ?
      AND DICTYBASEID_TYPE = 'Primary'
    ");

   my $id    = $self->{'_featureNo'} || $self->{'_locusNo'};
   my $table = $self->{'_featureNo'} ? 'FEATURE' : 'LOCUS';

   $sth->execute($id, $table);

   ($self->{'_primarydictyBaseID'}) = $sth->fetchrow_array;

   $sth->finish;

}


#
# CAN SHOW SECONDARY FEATURES, BUT ONLY WHEN CALLED EXPLICITLY BY DICTYBASEID
#  OR FEATURE_NAME, THIS IS A VERY SIMILAR METHOD TO THE GENERIC _POPULATEBYNUMBER
#   BUT IT SELECTS FROM V_NOTDELETED_FEATURE INSTEAD OF V_PRIMARY_FEATURE
#
################################################################################
sub _populateByFeature{
################################################################################
# This is a generic populator, that will populate an object using either a locus_no
# or a feature_no, depending on what was passed in


    my ($self) = shift;

    if (!$self->{'_featureNo'}){

        die '_populateByFeature called without having previously set $self->{\'_featureNo\'}\n';

    }

    my $sth = $dbh->prepare("
         SELECT FEATURE_NO, FEATURE_NAME,
                F.CHROMOSOME, START_COORD,
                STOP_COORD, STRAND, IS_ON_PMAP, BRIEF_ID,
                L.LOCUS_NO, LOCUS_NAME, L.CHROMOSOME,
                GENETIC_POSITION, ENZYME, DESCRIPTION
           FROM CGM_DDB.V_NOTDELETED_FEATURE F
LEFT OUTER JOIN CGM_DDB.LOCUS L
             ON F.LOCUS_NO = L.LOCUS_NO
          WHERE F.FEATURE_NO = ?
   ");

   $sth->execute( $self->{'_featureNo'} );

   ($self->{'_featureNo'}, $self->{'_featureName'}, $self->{'chr'}, $self->{'begCoord'},
   $self->{'endCoord'}, $self->{'_strand'}, $self->{'_isOnPMap'}, $self->{'_briefId'},
   $self->{'_locusNo'}, $self->{'_locusName'}, $self->{'_genChr'}, $self->{'_genPos'},
   $self->{'_enzyme'}, $self->{'_description'}) = $sth->fetchrow_array;



    my $sth = $dbh->prepare("
   SELECT DICTYBASEID FROM DICTYBASEID
    WHERE PRIMARY_KEY = ?
         AND TAB_NAME = ?
      AND DICTYBASEID_TYPE = 'Primary'
    ");

   my $id    = $self->{'_featureNo'} || $self->{'_locusNo'};
   my $table = $self->{'_featureNo'} ? 'FEATURE' : 'LOCUS';

   $sth->execute($id, $table);

   ($self->{'_primarydictyBaseID'}) = $sth->fetchrow_array;

   $sth->finish;

}
#
# dictyBase does not use fungal align
#
#

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

    return 0;
}



#
#  use num2name has instead of arab2rom
#   restrict subfeature query to only introns and exons
#    took out phygen map link
#
#
#######################################################################################################
sub positionalInfo{
#######################################################################################################
# This method returns a string that can be used in the locus page to indicate where the locus in
# question is

    my ($self) = @_;

    my ($string, $string2);

    my $featureType = $self->featureType;

    if ($self->{'chr'}){

        $string .= "Chr ".$num2name{$self->{'chr'}}.": ";

    }elsif ($self->{'_genChr'}){

        $string .= "Chr ".$num2name{$self->{'_genChr'}};

    }

    $string =~ s/ChrQ:/Mito:/;

    if ($self->{'begCoord'} && $self->{'endCoord'}){

        $string .= "coordinates ".$self->{'begCoord'}." to ".$self->{'endCoord'};
        if ($featureType !~ /Deleted/i){ # if it's not deleted, make it a link
            $string .= " [ ".a({-href=>$self->orfMap},
                        "ORF Map")." ]"; # only link it if we have coordinates
        }

    }

#
# added restriction to query to only get Exon and introns
#
#
    #### exon and intron info
    #Mira Aug 12 02 don't display subfeature info when subfeature is deleted
    my $sth = $dbh->prepare("
        SELECT SFT.subfeature_type, SF.start_coord, SF.stop_coord
        FROM   CGM_DDB.subfeature SF, CGM_DDB.subfeature_type SFT
        WHERE  SF.feature_no = ?
        AND    SF.subfeature_no = SFT.subfeature_no
        AND    SF.subfeature_no NOT IN
                  (SELECT subfeature_no FROM CGM_DDB.subfeature_type
                     WHERE subfeature_type = 'Deleted')
        AND    SFT.SUBFEATURE_TYPE IN ('Exon','Intron')
        ORDER BY SF.start_coord
    ");
    $sth->execute($self->featureNo);
    my $subFeatArrayRef = $sth->fetchall_arrayref();
    $sth->finish;

    if (@$subFeatArrayRef == 1) {
        my ($subtype, $beg, $end) = @{$$subFeatArrayRef[0]};
        $string .= br."Exon 1: ".$beg." - ".$end.br;
    }
    elsif (@$subFeatArrayRef > 1) {
        my $row;

        my ($exonCount, $intronCount);
        foreach my $rowRef (@$subFeatArrayRef) {
      my $thisrow;
           my ($subtype, $beg, $end) = @$rowRef;
           my ($subfeatBeg, $subfeatEnd);
           if ($self->strand =~ /^W/i) {
               $subfeatBeg = $self->{'begCoord'} + $beg - 1;
               $subfeatEnd = $self->{'begCoord'} + $end - 1;
           }
           else {
               $subfeatBeg = $self->{'begCoord'} - $beg + 1;
               $subfeatEnd = $self->{'begCoord'} - $end + 1;
           }
           if ($subtype =~ /^Exon/i) {
               $exonCount++;

                          $thisrow =  th("Exon $exonCount").
                                        td($beg." - ".$end);
                                      if ($self->{'begCoord'}) {
                                         $thisrow .= td($subfeatBeg." - ".$subfeatEnd);
                       }
           $thisrow = Tr({-align=>'right'},$thisrow);

           }
           else {
               $intronCount++;

                          $thisrow = th("Intron $intronCount").
                                     td($beg." - ".$end);
                                     if ($self->{'begCoord'}) {
                                        $thisrow .= td($subfeatBeg." - ".$subfeatEnd);
                      }
           $thisrow = Tr({-align=>'right'},$thisrow);

           }
      $row .= $thisrow;
   }

   my $headerRow = td(br).th("ORF Coord");
   if ($self->{'begCoord'}) {
            $headerRow .= th("Chromosomal Coord");
   }
   $headerRow = Tr($headerRow);
        $string .= br.table($headerRow.$row);
    }

    if ($self->strand =~ /^C/i && $featureType !~ /^(ARS|CEN)/i) {
        $string .= i(b("Note:")." this gene is encoded on the Crick strand.");
    }

    if ($self->{'_genPos'}){

#        if ($self->{'begCoord'}){
#            $string2 = "Genetic position: ".a({-href=>$self->{'physGen'}},
#                                              $self->{'_genPos'});
#        }else{
#            $string2 = "Genetic position: ".$self->{'_genPos'};
#        }

#  commented out the previous section because we don't hav physgen map (dictyBase)
#  added next line
   $string2 = "Genetic position: ".$self->{'_genPos'};

   if ($string) { $string2 = p.$string2 };

    }

    return $string.$string2;

}



#
#  new method to check if certain sequences exits
#
#############################################################################
sub getSequenceAvailable {
#############################################################################
    my ($self) = @_;

    my $getSeqCount = $dbh->prepare("

                   SELECT COUNT(*)
           FROM display_seq
          WHERE feature_no = ?
            AND display_seq_type = ?

    ");

    $getSeqCount->execute($self->{'_featureNo'},"DNA coding sequence");
    ($self->{'hasCodingSeq'}) = $getSeqCount->fetchrow_array;

    $getSeqCount->execute($self->{'_featureNo'},"Genomic DNA");
    ($self->{'hasGenomicSeq'}) = $getSeqCount->fetchrow_array;

    $getSeqCount->execute($self->{'_featureNo'},"Protein");
    ($self->{'hasProteinSeq'}) = $getSeqCount->fetchrow_array;

    $getSeqCount->finish;

}


#
#  get sequences Returns hash seq_type => seq
#
#############################################################################
sub allSequence_types {
#############################################################################
   my ($self) = @_;

   $dbh->{LongReadLen} = 2**25;

   if ( $self->{'_featureNo'} ) {
      my $getSequences = $dbh->selectcol_arrayref("
           SELECT DISPLAY_SEQ_TYPE
             FROM DISPLAY_SEQ
            WHERE FEATURE_NO = ".$self->{'_featureNo'}."
            ORDER BY DISPLAY_SEQ_TYPE DESC"
      );

      return $getSequences;
   }
   else {return;}
}

#
#  use num2name hash has instead of arab2Rom
#
#######################################################################################################
sub positionalInfoSinglePage {
#######################################################################################################
# This method returns a string that can be used in the locus page to indicate where the locus in
# question is

    my ($self) = @_;

    my ($string, $string2);

    my $featureType = $self->featureType;

    if ($self->{'chr'}){

        $string .= "Chr ".$num2name{$self->{'chr'}}.": ";

    }elsif ($self->{'_genChr'}){

        $string .= "Chr ".$num2name{$self->{'_genChr'}};

    }

    $string =~ s/ChrQ:/Mito:/;

    if ($self->{'begCoord'} && $self->{'endCoord'}){

        $string .= $self->{'begCoord'}." to ".$self->{'endCoord'} . br;
#        if ($featureType !~ /Deleted/i){ # if it's not deleted, make it a link
#            $string .= " [ ".a({-href=>$self->orfMap},
#                        "ORF Map")." ]"; # only link it if we have coordinates
#        }

    }

    ## exon and intron info
    #Mira Aug 12 02 don't display subfeature info when subfeature is deleted
    my $sth = $dbh->prepare("
        SELECT SFT.subfeature_type, SF.start_coord, SF.stop_coord
        FROM   CGM_DDB.subfeature SF, CGM_DDB.subfeature_type SFT
        WHERE  SF.feature_no = ?
        AND    SF.subfeature_no = SFT.subfeature_no
        AND    SF.subfeature_no NOT IN
                  (SELECT subfeature_no FROM CGM_DDB.subfeature_type
                     WHERE subfeature_type = 'Deleted')
        ORDER BY SF.start_coord
    ");
    $sth->execute($self->featureNo);
    my $subFeatArrayRef = $sth->fetchall_arrayref();
    $sth->finish;

    if (@$subFeatArrayRef == 1) {
        my ($subtype, $beg, $end) = @{$$subFeatArrayRef[0]};
        $string .= "Exon 1: ".$beg." - ".$end.br;
    }
    elsif (@$subFeatArrayRef > 1) {
        my $row;
        my ($exonCount, $intronCount);
        foreach my $rowRef (@$subFeatArrayRef) {
           my ($subtype, $beg, $end) = @$rowRef;
           my ($subfeatBeg, $subfeatEnd);
           if ($self->strand =~ /^W/i) {
               $subfeatBeg = $self->{'begCoord'} + $beg - 1;
               $subfeatEnd = $self->{'begCoord'} + $end - 1;
           }
           else {
               $subfeatBeg = $self->{'begCoord'} - $beg + 1;
               $subfeatEnd = $self->{'begCoord'} - $end + 1;
           }
           if ($subtype =~ /^Exon/i) {
               $exonCount++;
               $string .= "Exon $exonCount: " .$beg." - ".$end.br;

#               $row .= Tr({-align=>'right'},
#                          td("Exon $exonCount").
#                          td($beg." - ".$end));
#                          .td($subfeatBeg." - ".$subfeatEnd));
           }
           else {
               $intronCount++;
               $string .= "Intron $exonCount: " .$beg." - ".$end.br;
#               $row .= Tr({-align=>'right'},
#                          th("Intron $intronCount").
#                          td($beg." - ".$end).
#                          td($subfeatBeg." - ".$subfeatEnd));
           }
        }
#        $string .= br.table(Tr(td(br)).
#                               th("ORF Coord").
#                               th("Chromosomal Coord")).
#                            $row);
    }

#    if ($self->strand =~ /^C/i && $featureType !~ /^(ARS|CEN)/i) {
#        $string .= i(b("Note:")." this gene is encoded on the Crick strand.");
#    }

    if ($self->{'_genPos'}){

        if ($self->{'begCoord'}){
            $string2 = "Genetic position: ".a({-href=>$self->{'physGen'}},
                                              $self->{'_genPos'});
        }else{
            $string2 = "Genetic position: ".$self->{'_genPos'};
        }
#        if ($string) { $string2 = p.$string2 };

    }

    return $string.$string2;

}



#####################################################################
#
#  When code came from SGD, used to show one link to pubmed
#  corresponding to this feature.  Since we can have multilple
#  features asssociated with a locus, make one pubmed link
#  that links to all
#
#####################################################################
###############################################################################
sub genbankLinks{

   my ($self) = @_;
   my $id;
   my $featureid;
   my @nuc_gi_nums;
   my @prot_gi_nums;
   my $gi_string;

   if ($self->{'_featureNo'} and $self->{'_locusNo'}){


    #
    # first get things associated wth this feature
    #
    # first field : external Id (gi number)
    # second field: source (gi or protein gi number)
    # third field : 1 if the feature number is the same as is being displayed on the locus page
    #               0 if they are different.  This is so we can order them with the "current feature" first in the list
    #
    # why so complicated?  because this query is slow and wanted to combine nucleotide and protein into one query to
    #  maximize performance
    #
      my $sth = $dbh->prepare("
         SELECT DISTINCT EXTERNAL_ID, SOURCE,
                                      CASE WHEN FEATURE_NO = ? THEN 1
                                            ELSE 0
                                      END AS IS_CURRENT
             FROM  CGM_DDB.v_LOCUS_EXTERNAL_ID v
                    WHERE LOCUS_NO = ?
              AND (SOURCE = 'GI Number' OR SOURCE = 'Protein GI Number')
      ");

      $sth->execute($self->{'_featureNo'},$self->{'_locusNo'});

      while (($id,$source,$current)  = $sth->fetchrow_array){
         push (@nuc_gi_nums, $id)  if ($source eq 'GI Number');
         push (@prot_gi_nums, $id)  if ($source eq 'Protein GI Number');;
      }

      $sth->finish;

   }
   elsif ($self->{'_locusNo'}) {

        my $sth = $dbh->prepare("
           SELECT DISTINCT EXTERNAL_ID, SOURCE
             FROM v_LOCUS_EXTERNAL_ID
            WHERE (SOURCE = 'GI Number' OR SOURCE = 'Protein GI Number')
              AND LOCUS_NO = ?
        ");

        $sth->execute($self->{'_locusNo'});

        while (($id,$source)  = $sth->fetchrow_array){
           push (@nuc_gi_nums , $id)  if ($source eq 'GI Number');
           push (@prot_gi_nums, $id)  if ($source eq 'Protein GI Number');;
        }

        $sth->finish;

   }
   elsif ($self->{'_featureNo'}) {

      my $sth = $dbh->prepare("
                   SELECT DISTINCT EXTERNAL_ID, SOURCE
           FROM EXTERNAL_ID E2
          WHERE E2.TAB_NAME = 'FEATURE'
            AND (E2.SOURCE = 'GI Number' OR E2.SOURCE = 'Protein GI Number')
            AND E2.PRIMARY_KEY = ?
      ");

      $sth->execute($self->{'_featureNo'});
      while (($id,$source)  = $sth->fetchrow_array){
         push (@nuc_gi_nums, $id)  if ($source eq 'GI Number');
         push (@prot_gi_nums, $id)  if ($source eq 'Protein GI Number');;
      }
      $sth->finish;

   }


  return ($self->get_nucleotide_link(@nuc_gi_nums), $self->get_protein_link(@prot_gi_nums));


}


sub get_nucleotide_link {

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

   if (@gi_nums == 0) {
      return;
   }
   elsif (@gi_nums == 1) {
      return '<a href="http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?cmd=Retrieve&db=nucleotide&dopt=GenBank&list_uids='.$gi_nums[0].'">Entrez Nucleotide</a>';
   }
   else {
      $gi_string = join(',',@gi_nums);
      return '<a href="http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?cmd=Retrieve&db=nucleotide&dopt=Summary&list_uids='.$gi_string.'">Entrez Nucleotide</a>';
   }

}



sub get_protein_link {

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

   if (@gi_nums == 0) {
      return;
   }
   elsif (@gi_nums == 1) {
      return '<a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?val='.$gi_nums[0].'">Entrez Protein</a>';
   }
   else {
      $gi_string = join(',',@gi_nums);
      return '<a href="http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?cmd=Retrieve&db=protein&dopt=Summary&list_uids='.$gi_string.'">Entrez Protein</a>';
   }
}






#
#  changed to not show feature name if there is a locusname
#
###########################################################################################################
sub title{
###########################################################################################################
# This method returns a string that may be apropriate for use a at title

    my $self = shift;

    if (!$self->{'_title'}){

        if (($self->{'_featureName'} eq $self->{'_locusName'}) && $self->{'_featureName'}){
            $self->{'_title'} = $self->{'_locusName'};
        }elsif ($self->{'_locusName'}){
            $self->{'_title'} = $self->{'_locusName'};
        }elsif ($self->{'_featureName'}){
            $self->{'_title'} = $self->{'_featureName'};
        }else{
            $self->{'_title'} = "Search for : ".$self->{'_query'};
        }

    }

    return $self->{'_title'}

}




#####################################################################
#
#  Now we want a series of get methods
#
#####################################################################
###############################################################################
sub externalLinks{
###############################################################################
# This works out the urls for a links, and returns a single formatted string
# eg YPD, EC, Entrez Protein_ID, MIPS, PIR, SwissProt, YPD

    my ($self) = @_;

    my ($id, $url, $source, @links);

    my $featureType = $self->featureType;

    return if $featureType=~/Deleted/i; # no external links if it's been deleted



   #
   # first, get genbank links
   #
    push (@links, $self->genbankLinks);


    # first get the template url


    if ($self->{'_locusNo'}){
       my $sth = $dbh->prepare("
            SELECT DISTINCT V.EXTERNAL_ID, T.TEMPLATE_URL, T.SOURCE
              FROM CGM_DDB.v_LOCUS_EXTERNAL_ID v
        INNER JOIN CGM_DDB.EI_TU ET
                ON V.EXTERNAL_ID_NO = ET.EXTERNAL_ID_NO
        INNER JOIN CGM_DDB.TEMPLATE_URL T
                ON T.TEMPLATE_URL_NO = ET.TEMPLATE_URL_NO
             WHERE LOCUS_NO = ?
          ");

       $sth->execute($self->{'_locusNo'});

       while (($id, $url, $source)  = $sth->fetchrow_array){
          $url =~ s/_SUBSTITUTE_THIS_/$id/;
          push (@links, a({-href=>$url}, $source));
       }

       $sth->finish;
    }
    elsif ($self->{'_featureNo'}) {
       my $sth = $dbh->prepare("
            SELECT DISTINCT E.EXTERNAL_ID, T.TEMPLATE_URL, T.SOURCE
              FROM CGM_DDB.EXTERNAL_ID E
        INNER JOIN CGM_DDB.FEATURE F
                ON F.FEATURE_NO = E.PRIMARY_KEY
               AND E.TAB_NAME   = 'FEATURE'
        INNER JOIN CGM_DDB.EI_TU ET
                ON E.EXTERNAL_ID_NO = ET.EXTERNAL_ID_NO
        INNER JOIN CGM_DDB.TEMPLATE_URL T
                ON T.TEMPLATE_URL_NO = ET.TEMPLATE_URL_NO
             WHERE F.FEATURE_NO = ?
          ");

       $sth->execute( $self->{'_featureNo'} );

       while (($id, $url, $source)  = $sth->fetchrow_array){
          $url =~ s/_SUBSTITUTE_THIS_/$id/;
          push (@links, a({-href=>$url}, $source));
       }

       $sth->finish;

    }


    return join (" | ", @links);

}

#
#  generate our miniorfmap
#
#############################################################################
sub _initORFMapURLs{
#############################################################################
# This subroutine initializes the URLs required for making an ORF map link
# It has been abstracted to allow it's reuse

    my ($self) = @_;

   #
   # this logic will be configurable, or perhaps have a more systematic
   # mapping between feature type and name of gbrowse track
   #
   #  for now, the feature type key points to a named track in gbrowse
   #
    my %types  = (
                   'Curated Model'                          => 'dictyBase',
                   'Gene Prediction from Sequencing Center' => 'Predictions',
                   'External Gene Prediction'               => 'HMM_Gene_Predictions'
                 );

    # my $ORFMapBase = $configUrl->dictyBaseCGIRoot.$self->{'_linker'}."/ORFMAP/";

   #
   # unfortunately feature types are returned as a comma delimited list
   # assume that the first item is the one that we are interested in
   #
    my @feature_Types = split( ', ', $self->featureType);

    if (my $track = $types{ @feature_Types[0]  }) {
       $self->{'miniORFMap'} = $configUrl->dictyBaseCGIRoot."gbrowse_img2?source=dictyBase;name=".$self->{'_primarydictyBaseID'}.";type=$track;width=150;";
       $self->{'miniORFMap'} .= "abs=1" if ($self->begCoord);
    }
    $self->{'ORFMap'} = $configUrl->dictyBaseCGIRoot."gbrowse?name=".$self->{'_primarydictyBaseID'};

}

#
# This subroutine returns the section of the right hand cell on the locus page that contains links to
# retrieve various sequences associated with the locus
#
sub write_sequence_retreival_selector{

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


   my $seqtypes = $self->allSequence_types;

   my $dictybaseid = $self->{'_primarydictyBaseID'};
   my $url_base    = "/db/cgi-bin/dictyBase/getSeq?dictybaseid=$dictybaseid&sequence_type=";

   my @values = map { $url_base.$_             } @{ $seqtypes };
   my %labels = map { $url_base.$_, $_         } @{ $seqtypes };


        return
            start_form( -name    => 'seq').$header.
         popup_menu( -name    => 'seq',,
                     -values  => \@values,
                     -labels  => \%labels
                   ).
         button(     -onClick => 'switchAddress(this.form.seq)',
                     -name    => 'Retrieve'
               ).
            end_form if @{$seqtypes};

     return '';

}


#
# This subroutine returns the section of the right hand cell on the locus page that contains links to
# retrieve various analysis tools, right now, just blasts
# relies on javascript method: goToBlast
#
################################################################################
sub write_analysis_selector{
################################################################################
# This is a generic populator, that will populate an object using either a locus_no
# or a feature_no, depending on what was passed in


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

    my $blast_programs         = [ qw /blastn blastx tblastx/ ];
    my $protein_blast_programs = [ qw /blastp tblastn/ ];
    my $seqtypes               = $self->allSequence_types;

    my $has_protein_seq        = grep ( /Protein/, @{ $seqtypes });

    push (@{$blast_programs}, @{$protein_blast_programs}) if $has_protein_seq;

    my $dictybaseid = $self->{'_primarydictyBaseID'};
    my $url_base    = "/db/cgi-bin/blast.pl?dictybaseid=$dictybaseid&program=";

    my @values = map { $url_base.$_                 } @{ $blast_programs };
    my %labels = map { $url_base.$_, uc($_)         } @{ $blast_programs };

  #
  #  now add the options for ncbi blast
  #
    if ( $has_protein_seq ) {
      #
      # add CMD=PUT to the query line to submit the blast at NCBI
      #
       my $url_base2   = "/db/cgi-bin/dictyBase/go_to_ncbi_blast.pl?sequence_type=Protein&dictybaseid=$dictybaseid&program=blastp";
       push @values, $url_base2;
       %labels = (%labels, ($url_base2, 'BLASTP at NCBI'));
    }


    return
            start_form( -name    => 'analysis').$header.
         popup_menu( -name    => 'analysis',
                              -values  => \@values,
                              -labels  => \%labels).
         button(     -onClick => 'goToBlast(this.form.analysis,document.forms["seq"].seq)',
                     -name    => 'Analyze').
         end_form;

}





sub public_curator_notes {

    my ($self) = @_;

    my $locusObj, $featObj;

    my @noteArrayRef;
    my @return_array;

    if ($self->{'_locusName'}) {
       $locusObj = Locus->new( dbh        => $dbh,
                                                  locus_name => $self->{'_locusName'});
    }
    elsif ($self->{'_featureName'}) {
       $featObj = Feature->new( dbh          => $dbh,
                                     feature_name => $self->{'_featureName'});
    }
    if ($locusObj && @{$locusObj->curatorNoteInfoArrayRef}) {
        push(@noteArrayRef, @{$locusObj->curatorNoteInfoArrayRef});
    }
    if ($featObj && @{$featObj->curatorNoteInfoArrayRef}) {
        push(@noteArrayRef, @{$featObj->curatorNoteInfoArrayRef});
    }

   #
   # filter outpublic notes
   #

    foreach my $rowRef (@noteArrayRef) {
       my ($noteNo, $note, $isPublic) = @$rowRef;

       push (@return_array, $rowRef) if ($isPublic =~ /^Y/i);

    }

    return \@return_array;
}

#
# override and remove calls to $self->_initORFMapURLs and $self->_initCommonURLs
# which were causing errors after housekeeping chore of dropping a load of unused tables
#
####################################################################
sub _init{
####################################################################
# This method performs the initialization of the object

    my ($self, %args) = @_; # have to use named arguments

    $self->{'help'} = $args{'help'};

    if ($args{'query'}){ # a general query

	$self->{'_query'} = $args{'query'};

	$self->_resolveQuery; # grab all info we can

    }elsif ($args{'dictyBaseid'}){ # they know it's an dictyBaseid

	$self->{'_query'} = $args{'dictyBaseid'};

	my $isdictyBaseID = $self->_isdictyBaseID;

	if ($isdictyBaseID){ $self->_populateBydictyBaseID }else{ return };
	
    }elsif ($args{'locusName'}){ # they know it's a locus name

	$self->{'_query'} = $args{'locusName'};

	my $isLocusName =  $self->isLocusName;

	if ($isLocusName){ $self->_populateByLocus }else{ return };

    }elsif ($args{'featureName'}){ # they know it's a feature name

	$self->{'_query'} = $args{'featureName'};

	my $isFeatureName =  $self->isFeatureName;

	if ($isFeatureName){ $self->_populateByFeature }else{ return };

    }elsif ($args{'aliasName'}){ # they know it's an alias name

	$self->{'_query'} = $args{'aliasName'};

	my $isFeatureName =  $self->isAliasName;

	if ($isFeatureName){ $self->_populateByAlias }else{ return };

    }elsif ($args{'locusNo'}){ # they know the locus no

	$self->{'_locusNo'} = $args{'locusNo'};
	$self->_populateByLocus;

    }elsif ($args{'featureNo'}){ # they know the featureNo

	$self->{'_featureNo'} = $args{'featureNo'};
	$self->_populateByFeature;

    }elsif ($args{'aliasNo'}){ # they know the alias no

	$self->{'_aliasNo'} = $args{'aliasNo'};
	$self->_populateByAlias;

    }else{

	die "Unknown argument passed to dictyBaseObject constructor\n";

    }

    return if ($self->{'_isMultiple'} == 1); # if alias mapped to many loci

    $self->{'_standard name'} = $self->{'_locusName'}|| $self->{'_featureName'};

    # maybe want to move these out of the object intialization

#    $self->_initORFMapURLs; # will need these for locus page, and for wild card search
#    $self->_initCommonURLs;

    if ($self->{'_featureName'}){
	&GetProcessFunction; #### init process, function and component
    }

}

1; # to make require happy