#!/usr/local/bin/perl 
##############################################################################
#   
#   Name:           unisearch           
#   
#   Description:    A universal searcher for ensembl - a passed string is used
#                   to look up all types of ensembl object.  If only one match
#                   is found, the user is redirected to that object.  If more 
#                   than one match is found, the user is presented with a page
#                   of matches, sorted by type.
#                   The number of matches/type is limited.
#
#   Author:         jws
#
#   History:        2000-10-05  jws:    initial version
#                   2000-10-20  jws:    improved portability
#		    2000-11-29	jws:	added Protein Feature searches
#		    2000-12-05	jws:	Added golden checking for clone|contig
#		    2001-02-12	jws:	Added Protein Family searches
#
##############################################################################
package unisearch;
use SiteDefs;
use CGI;
use DBI;
use EnsWeb;
use HelpView;
use Bio::EnsEMBL::ExternalData::GMAPAdaptor;
use GramenePage;
use Gramene::GetProteinData; 

#use DiseaseKwIndex;
use strict;

$|=1;

############################
# Retrieve the passed query
############################

my $q           = &CGI::param('q');
my $search_type = &CGI::param('type')||&CGI::param('idx');
my $table_only = &CGI::param('table') || 0;

print STDERR "unisearch:$q,$search_type,$table_only\n";

$search_type = lc ($search_type);
$search_type ||='all';

# clean up input
$q=~s/^\s*//;
$q=~s/\s*$//;

unless ($q ne ''){
    # Nothing to search with, so forget it.
    &output_results();
}

print STDERR "<$search_type>\n";

if($search_type eq "zaceobject") {
    print CGI::redirect("/gramene/searches/browser?class=aceobject&query=".CGI::escapeHTML($q));
    return;

}

##################
# Escape quotes
##################

#$q=~s/'/\\'/g;
$q=~s/'/''/g;	# For Oracle

my $offset  = 0;                            # offset from start of matches
my $limit   = 10;                           # max number of matches to return
unless ($search_type eq 'all'){$limit=30};

##########################
# Set up database handles
##########################
my %dbh;  # 'ensembl'=>$ensembl_dbh, etc.
#my ($ensembl_dbh,$disease_dbh,$family_dbh, $marker_dbh, $snp_dbh);
#my $sa;

my %problem;	# type of query => error message

eval {
    my $locator = &EnsWeb::get_locator();
    $dbh{'ensembl'} =  Bio::EnsEMBL::DBLoader->new($locator);

    $dbh{'ensembl'} or print STDERR "cannot open $locator\n"
     and die "cannot open $locator\n";

#    if ($ENSEMBL_MAP) {
#	$dbh{'marker'}=$dbh{'ensembl'}->mapdb;
#    }
     if ($ENSEMBL_GMAP) {
	$dbh{'marker'}= Bio::EnsEMBL::ExternalData::GMAPAdaptor->new(       
			-driver => $ENSEMBL_DRIVER,
			-user   => $ENSEMBL_DBUSER,
			-pass   => $ENSEMBL_DBPASS,
			-dbname => $ENSEMBL_GMAP,
			-host   => $ENSEMBL_HOST,
			-port   => $ENSEMBL_HOST_PORT,
			); 
     }

    if ($ENSEMBL_EMBL){
	my $emblext= Bio::EnsEMBL::DBSQL::DBAdaptor->new(       
			    -driver => $ENSEMBL_DRIVER,
			    -user   => $ENSEMBL_DBUSER,
			    -pass   => $ENSEMBL_DBPASS,
			    -dbname => $ENSEMBL_EMBL,
			    -host   => $ENSEMBL_HOST,
			    -port   => $ENSEMBL_HOST_PORT,
			    ); 
                        
	my $embldb= new Bio::EnsEMBL::DBSQL::ExternalWrapper($emblext);
	$dbh{'ensembl'}->add_ExternalFeatureFactory($embldb);
    }

    if ($ENSEMBL_DISEASE){
	$dbh{'disease'}= Bio::EnsEMBL::DBSQL::DBAdaptor->new(       
			    -driver => $ENSEMBL_DRIVER,
			    -user   => $ENSEMBL_DBUSER,
			    -pass   => $ENSEMBL_DBPASS,
			    -dbname => $ENSEMBL_DISEASE,
			    -host   => $ENSEMBL_HOST,
			    -port   => $ENSEMBL_HOST_PORT,
			    ); 
    }
    if ($ENSEMBL_FAMILY){
	$dbh{'family'}= Bio::EnsEMBL::DBSQL::DBAdaptor->new(       
			    -driver => $ENSEMBL_DRIVER,
			    -user   => $ENSEMBL_DBUSER,
			    -pass   => $ENSEMBL_DBPASS,
			    -dbname => $ENSEMBL_FAMILY,
			    -host   => $ENSEMBL_HOST,
			    -port   => $ENSEMBL_HOST_PORT,
			    ); 
    }

    if ($ENSEMBL_SNP){
	$dbh{'snp'} = Bio::EnsEMBL::ExternalData::SNPSQL::WebSNPAdaptor->new(   
			     -dbname => $ENSEMBL_SNP,
			     -user   => $ENSEMBL_DBUSER,
			     -pass   => $ENSEMBL_DBPASS,
			     -host   => $ENSEMBL_HOST,
			     -port   => $ENSEMBL_HOST_PORT,
			     );

	$dbh{'ensembl'}->add_ExternalFeatureFactory($dbh{'snp'});
    }

    if ($ENSEMBL_MOUSE){
	my $mouse = Bio::EnsEMBL::ExternalData::EXONERATESQL::DBAdaptor->new( 
			    -user   => $ENSEMBL_DBUSER,
			    -pass   => $ENSEMBL_DBPASS,
			    -dbname => $ENSEMBL_MOUSE,
			    -host   => $ENSEMBL_HOST,
			    -port   => $ENSEMBL_HOST_PORT,
			    ); 

	my $mouse_ext_feature_factory = $mouse->get_ExonerateAdaptor();
	$dbh{'ensembl'}->add_ExternalFeatureFactory($mouse_ext_feature_factory);
    }

    my $pro=Gramene::GetProteinData->new();
    $pro->connect_to_ora( );
    $dbh{'protein'}=$pro->db;

##########################################################################
# Set up Ensembl DB connection for golden-path checking on clones/contigs
##########################################################################

    $dbh{'ensembl'}->static_golden_path_type($ENSEMBL_GOLD);
    $dbh{'sa'} = $dbh{'ensembl'}->get_StaticGoldenPathAdaptor();

};

if ( $@ ){
    print STDERR "db eval error\n";
    print &ensembl_exception("An error occurred while loading the database",$@);
    &EnsWeb::ensembl_exit();
}
unless($dbh{'ensembl'}) { 
    print STDERR "cannot open EnsEMBL database\n";
    print &ensembl_exception("cannot open EnsEMBL database",'');
    &EnsWeb::ensembl_exit();
}

print STDERR "main db opened\n";

   $dbh{'marker'} or $problem{'marker'}='map database not available';
   $dbh{'snp'} or $problem{'snp'}='SNP database not available';
   $dbh{'disease'} or $problem{'disease'}='disease database not available'; 
   $dbh{'family'} or $problem{'family'}='family database not available'; 	
   $dbh{'protein'} or $problem{'protein'}='ontology database not available'; 	

print STDERR map { "$_\n" } values %problem;



######################
# Do all the searches
######################
# "All" = the keys of the following hash:
my %urls   =(   gene        => '/perl/geneview?gene=',
                contig      => '/perl/contigview?contig=',
                feature      => '/perl/contigview?fpos_context=50000&contig=',
                clone       => '/perl/contigview?clone=',
                marker      => '/perl/markerview?marker=',
                #transcript  => '/perl/geneview?transcript=',  #'/perl/transview?transcript=', since no supporting evidence yet
                #chromosome  => '/perl/mapview?chr=',
                #snp	    => '/perl/snpview?snp=',
                #disease     => '/perl/diseaseview?disease=',
		#domainentry => '/perl/domainview?domainentry=',  
		#family	    => '/perl/familyview?family=',  
		protein	    => '/perl/protein_search?acc=',
            );
        # Exons not searchable yet...
        #       exon        => '',
        #   );

my %matches;

my $match_count=0;

print STDERR "Type $search_type\n";

$problem{"protein"}='redundant' if  $table_only; #Added for browser (to get rid of the duplicate protein search results).

if ($search_type eq 'all'){
    foreach my $type(keys %urls){
	next if $problem{$type};
        no strict "refs";
        my $sub_name="search_$type";
        $matches{$type} = &$sub_name(\%dbh,$q,$offset,$limit);
        print STDERR (scalar @{$matches{$type}{'results'}})."results from $type\n";
        $match_count+=scalar @{$matches{$type}{'results'}};
    }
}
else {
    unless ($urls{$search_type} ){&output_results();}
    if($problem{$search_type}) { &output_results(undef,undef,$problem{$search_type});}
    				#abusing that third argument
    no strict "refs";
    my $sub_name="search_$search_type";
    $matches{$search_type} = &$sub_name(\%dbh,$q,$offset,$limit);
    $match_count+=scalar @{$matches{$search_type}{'results'}};
}

print STDERR "$match_count matches\n";

if ($match_count==0){
    #############
    # No matches
    #############
    &output_results();
}
elsif ($match_count==1 && !$table_only){
    #####################################################
    # find the result and jump to the correct page
    # unless we're a non-golden clone|contig
    #####################################################
    foreach my $type(keys %matches){
        if (scalar @{$matches{$type}{'results'}}==1){
	    print STDERR "one match type=$type\n";
	    if ($type eq 'clone' && 
		!($dbh{'sa'}->is_golden_static_clone($matches{$type}{'results'}[0][0]))){
		print STDERR $matches{$type}{'results'}[0][0], " not golden\n";
		&output_results(\%dbh,\%matches,\%urls);
	    }
	    elsif ($type eq 'contig' && 
		!($dbh{'sa'}->is_golden_static_contig($matches{$type}{'results'}[0][0]))){
		print STDERR $matches{$type}{'results'}[0][0], " not golden\n";
		&output_results(\%dbh,\%matches,\%urls);
	    }
	    elsif ($type eq 'feature') {
		my ($contig,$start,$end)=$matches{$type}{'results'}[0][2,3,4];
		if (!$dbh{'sa'}->is_golden_static_contig($contig)){
		    &output_results(\%dbh,\%matches,\%urls);
		} else {
		    &jump_to_result($urls{$type}.&CGI::escape($contig)."&fpos_start=$start&fpos_end=$end",'',$type);
		}
	    } 
            else { 
	      &jump_to_result($urls{$type},$matches{$type}{'results'}[0][0],$type);
	    } 
        }
    }
}
else {
    ##########################
    # display list of matches
    ##########################
    &output_results(\%dbh,\%matches,\%urls,$table_only);
}

# Go quietly...

###############################################################################
################################### SUBS ######################################
###############################################################################
sub search_feature {
    my ($pdbh,$keyword, $offset, $limit)=@_;
    my $comparator= '=';
    
    $keyword=uc($keyword);
    if ($keyword=~s/\*/\%/g){$comparator='LIKE';}


#    my $count_h=$pdbh->{'ensembl'}->prepare("
#                                SELECT COUNT(*) 
#				FROM feature 
#				WHERE hid $comparator '$keyword'
#				");
#    $count_h->execute;
#    
#    my ($result_count)=$count_h->fetchrow_array;
    
    my $result_ref = $pdbh->{'ensembl'}->selectall_arrayref("
                                SELECT feature.hid,contig.id,feature.seq_start,feature.seq_end,analysis.db
				FROM feature,contig,analysis
				WHERE hid $comparator '$keyword'
				AND feature.contig=contig.internal_id
				AND feature.analysis=analysis.id
				ORDER BY analysis.db,feature.hid
				");

    my @results= map { [$_->[4],"$_->[0] on $_->[1] at $_->[2] to $_->[3]",$_->[1],$_->[2],$_->[3] ] }
			@$result_ref;

    #################################
    # build data structure to return
    #################################
    my $hashref =   {
                    count   => scalar(@results),	#$result_count,
                    results => \@results,
                    };
    
    return $hashref;
}


sub search_gene {
    my ($pdbh,$keyword, $offset, $limit)=@_;
    my $comparator= '=';
    
    if ($keyword=~s/\*/\%/g){$comparator='LIKE';}

#    if ($offset||$offset == 0){$offset='LIMIT '.$offset;}
#    if($limit){$limit=','.$limit;}

    # look for HUGO genes first...

    ########################################################
    #changed this query because Oracle CONCAT takes only two arguments
#    my $count_h=$pdbh->{'ensembl'}->prepare("
#				SELECT COUNT(CONCAT(CONCAT(x.display_id,':'),tr.gene)) 
#				FROM	transcript tr,
#					Xref x,
#					objectXref oxr 
#				WHERE x.display_id $comparator '$keyword' 
#				AND oxr.xrefId = x.xrefId 
#				AND tr.translation = oxr.ensembl_id
#				");
#    $count_h->execute;
#    
#    my ($result_count)=$count_h->fetchrow_array;
    
    my $result_ref = $pdbh->{'ensembl'}->selectall_arrayref("
				SELECT x.display_id,tr.gene
				FROM	transcript tr,
					Xref x,
					objectXref oxr 
				WHERE x.display_id $comparator '$keyword' 
				AND oxr.xrefId = x.xrefId 
				AND tr.translation = oxr.ensembl_id
				ORDER BY x.display_id
                                 ");
    my @results= map { [$_->[1],"$_->[0] ($_->[1])"] } @$result_ref;
#$offset $limit
    
    ########################################################
    # Only look for ensembl genes if no hugo type...
    unless(scalar @results){
#        $count_h = $pdbh->{'ensembl'}->prepare("
#                                        SELECT COUNT(id) 
#                                        FROM gene 
#                                        WHERE id $comparator '$keyword' 
#                                        ");
#        $count_h->execute;
#    
#        ($result_count)=$count_h->fetchrow_array;
        
        my $result_ref2 = $pdbh->{'ensembl'}->selectall_arrayref("
                                        SELECT id 
                                        FROM gene 
                                        WHERE id $comparator '".SiteDefs::idfix($keyword)."'
                                        ");
#                                        $offset $limit
        
        my @results2= map {[$_->[0]]} @$result_ref2;

        push @results,@results2;
        
    }
    
    #################################
    # build data structure to return
    #################################
    my $hashref =   {
                    count   => scalar(@results),	#$result_count,
                    results => \@results,
                    };
    
    return $hashref;
}



sub search_contig {
    my ($pdbh,$keyword, $offset, $limit)=@_;
    my $comparator= '=';
    
    $keyword=uc($keyword);
    if ($keyword=~s/\*/\%/g){$comparator='LIKE';}

#    if ($offset||$offset == 0){$offset='LIMIT '.$offset;}
#    if($limit){$limit=','.$limit;}
    
#    my $count_h = $pdbh->{'ensembl'}->prepare("
#                                        SELECT COUNT(id) 
#                                        FROM contig 
#                                        WHERE id $comparator '$keyword'
#                                        ");
#    $count_h->execute;
#    
#    my ($result_count)=$count_h->fetchrow_array;
        
    my $result_ref = $pdbh->{'ensembl'}->selectall_arrayref("
                                        SELECT id 
                                        FROM contig 
                                        WHERE id $comparator '$keyword' 
                                        ");
#                                        $offset $limit
    my @results= map {[$_->[0]]} @$result_ref;
    
    #################################
    # build data structure to return
    #################################
    my $hashref =   {
                    count   => scalar(@results),	#$result_count,
                    results => \@results,
                    };
                
    return $hashref;
}


sub search_clone {
    my ($pdbh,$keyword, $offset, $limit)=@_;
    my $comparator= '=';
    
    $keyword =~ s/\..*//;	#in case they typed in a version 
    if ($keyword=~s/\*/\%/g){$comparator='LIKE';}
    my $keyworduc=uc($keyword);

#    if ($offset||$offset == 0){$offset='LIMIT '.$offset;}
#    if($limit){$limit=','.$limit;}
    
#    my $count_h = $pdbh->{'ensembl'}->prepare("
#                                        SELECT COUNT(id) 
#                                        FROM clone 
#                                        WHERE id $comparator '$keyworduc'
#					OR  name $comparator '$keyword'
#                                        ");
#    $count_h->execute;
#    
#    my ($result_count)=$count_h->fetchrow_array;

                                    
    my $result_ref = $pdbh->{'ensembl'}->selectall_arrayref("
                                        SELECT id,name
                                        FROM clone 
                                        WHERE id $comparator '$keyworduc'
					OR  name $comparator '$keyword'
                                        ");
                                        #$offset $limit
    
    my @results= map { [$_->[0], $_->[0]." ($_->[1])" ]  } @$result_ref;

    #################################
    # build data structure to return
    #################################
    my $hashref =   {
                    count   => scalar(@results),	#$result_count,
                    results => \@results,
                    };
                
    return $hashref;
}



sub search_marker {
    my ($pdbh,$keyword, $offset, $limit)=@_;
    my $comparator= '=';
    
    #$keyword .= '.*' unless $keyword =~ /[.*]/; # user is not expecting .3 and .5 suffixes #which are not there anymore
    if ($keyword=~s/\*/\%/g){$comparator='LIKE';}

    my $keyworduc=uc($keyword);

#    if ($offset||$offset == 0){$offset='LIMIT '.$offset;}
#    if($limit){$limit=','.$limit;}
    
#    my $count_h = $pdbh->{'marker'}->prepare("
#                                        SELECT COUNT(marker)
#                                        FROM marker_clone 
#                                        WHERE marker  $comparator '$keyword' 
#                                        ");
#    $count_h->execute;
#    
#    my ($result_count)=$count_h->fetchrow_array;

    # print STDERR "$result_count markers $comparator $keyword\n";

    my $query="SELECT distinct marker,marker_accession
		FROM marker_clone
		WHERE marker  $comparator '$keyword' 
		OR marker_accession $comparator '$keyworduc'";
    $query .= " OR marker $comparator '$keyworduc'" if $keyword ne $keyworduc;
    $query .= " OR marker $comparator '%-$keyworduc' " if $keyword !~ /-/ && 
						$keyword !~ /^%/;
		  # - have ssr names like RFjell-MRG0068
		  #  mwalton-MRG0032 myano-MRG0019 qifazh-MRG0003
		  #  zli-MRG6643.  Everything else is uppercase

    my $result_ref = $pdbh->{'marker'}->selectall_arrayref( $query);
                                        #$offset $limit
    # print STDERR "sa_a ",($result_ref?'ok':$pdbh->errstr),"\n";
    my @results= map { [$_->[0], $_->[0].(defined $_->[1]?"($_->[1])":"") ]} @$result_ref;
    # print STDERR join(",",@results),"\n";

    
#   -- this was correct for map database.
    ########################################################
    # Only look for synonyms if no results from RH markers
    ########################################################
#     unless(scalar @results && $pdbh->{'marker'}){
#         $count_h = $pdbh->{'marker'}->prepare("
#                                         SELECT COUNT(name) 
#                                         FROM MarkerSynonym 
#                                         WHERE name $comparator '$keyword'
#                                         ");
#         $count_h->execute;
#     
#         ($result_count)=$count_h->fetchrow_array;
#                                 
#         my $result_ref2 = $pdbh->{'marker'}->selectall_arrayref("
#                                         SELECT distinct name 
#                                         FROM MarkerSynonym 
#                                         WHERE name $comparator '$keyword' 
#                                         $offset $limit
#                                         ");
#         my @results2= map {$_->[0]} @$result_ref2;
# 
#         push @results,@results2;
#     }
    
    #################################
    # build data structure to return
    #################################
    my $hashref =   {
                    count   => scalar(@results),	#$result_count,
                    results => \@results,
                    };
                
    return $hashref;
}


sub search_transcript {
    my ($pdbh,$keyword, $offset, $limit)=@_;
    my $comparator= '=';
    
    if ($keyword=~s/\*/\%/g){$comparator='LIKE';}

    $keyword=SiteDefs::idfix($keyword);

    if ($offset||$offset == 0){$offset='LIMIT '.$offset;}
    if($limit){$limit=','.$limit;}

    my $count_h = $pdbh->{'ensembl'}->prepare("
                                        SELECT COUNT(id) 
                                        FROM transcript 
                                        WHERE id  $comparator '$keyword' 
                                        ");
    $count_h->execute;
    
    my ($result_count)=$count_h->fetchrow_array;

    my $result_ref = $pdbh->{'ensembl'}->selectall_arrayref("
                                        SELECT id
                                        FROM transcript 
                                        WHERE id  $comparator '$keyword' 
                                        $offset $limit
                                        ");
    my @results= map {[$_->[0]]} @$result_ref;
    
    #################################
    # build data structure to return
    #################################
    my $hashref =   {
                    count   => $result_count,
                    results => \@results,
                    };
                
    return $hashref;
}



sub search_chromosome {
    my ($pdbh,$keyword, $offset, $limit)=@_;
    
    $keyword=~s/\*//g;
    
    # There has got to be a simpler way to match this.... sorry!

    my $matchtest=join('|',reverse(1..23),'X','Y');
    my @results= map {[$_]} $keyword=~m/^(${matchtest})$/i;
    my $result_count=scalar @results;
    
    #################################
    # build data structure to return
    #################################
    my $hashref =   {
                    count   => $result_count,
                    results => \@results,
                    };
                
    return $hashref;
}



sub search_snp {
    my ($pdbh,$keyword, $offset, $limit)=@_;
    my $comparator= '=';
    
    if ($keyword=~s/\*/\%/g){$comparator='LIKE';}

    if ($offset||$offset == 0){$offset='LIMIT '.$offset;}
    if($limit){$limit=','.$limit;}

    my $count_h = $pdbh->{'snp'}->prepare("
                                        SELECT COUNT(id) 
                                        FROM RefSNP 
                                        WHERE id $comparator '$keyword'
                                        ");

    $count_h->execute;
    
    my ($result_count)=$count_h->fetchrow_array;

    my $result_ref = $pdbh->{'snp'}->selectall_arrayref("
                                        SELECT distinct id
                                        FROM RefSNP  
                                        WHERE id $comparator '$keyword' 
                                        $offset $limit
                                        ");
    my @results= map {[$_->[0]]} @$result_ref;
    
    #################################
    # build data structure to return
    #################################
    my $hashref =   {
                    count   => $result_count,
                    results => \@results,
                    };
                
    return $hashref;

}


sub search_domainentry {
    my ($pdbh,$keyword, $offset, $limit)=@_;
    my $comparator= '=';
    
    #############################################
    # If we're an Interpro id then just return -
    # let domainview work out if it exists...
    #############################################
    if ($keyword=~/IPR\d{6}/){
	my @temp_arr=($keyword);
	my $hashref =   {
			count   => 1,
			results => \@temp_arr,
			};
		    
	return $hashref;
    }
    
    if ($keyword=~s/\*/\%/g){$comparator='LIKE';}

    if ($offset||$offset == 0){$offset='LIMIT '.$offset;}
    if($limit){$limit=','.$limit;}
    
    
    my $count_h = $pdbh->{'ensembl'}->prepare("
					SELECT	idesc.interpro_ac 
					FROM interpro_description idesc 
					WHERE idesc.description 
					$comparator '$keyword'
					");
    
    $count_h->execute;
    
    my ($result_count)=$count_h->fetchrow_array;

    my $result_ref = $pdbh->{'ensembl'}->selectall_arrayref("
					SELECT	idesc.interpro_ac 
					FROM interpro_description idesc 
					WHERE idesc.description 
					$comparator '$keyword' 
                                        $offset $limit
					");
					
    my @results= map {[$_->[0]]} @$result_ref;
    
    #################################
    # build data structure to return
    #################################
    my $hashref =   {
                    count   => $result_count,
                    results => \@results,
                    };
                
    return $hashref;
}
   

sub search_family {
    my ($pdbh,$keyword, $offset, $limit)=@_;
    my $comparator= '=';
    
    if ($keyword=~s/\*/\%/g){$comparator='LIKE';}

    if ($offset||$offset == 0){$offset='LIMIT '.$offset;}
    if($limit){$limit=','.$limit;}
    
    
    my $count_h = $pdbh->{'family'}->prepare("
					SELECT count(family.id) 
					FROM family 
					WHERE family.id 
					$comparator '$keyword'
					");
    
    $count_h->execute;
    
    my ($result_count)=$count_h->fetchrow_array;

    my $result_ref = $pdbh->{'family'}->selectall_arrayref("
					SELECT family.id	
					FROM family 
					WHERE family.id 
					$comparator '$keyword' 
                                        $offset $limit
					");
					
    my @results= map {[$_->[0]]} @$result_ref;
    
    #################################
    # build data structure to return
    #################################
    my $hashref =   {
                    count   => $result_count,
                    results => \@results,
                    };
                
    return $hashref;
}


sub search_exon {
    my ($pdbh,$keyword, $offset, $limit)=@_;
    my $comparator= '=';
    
    if ($keyword=~s/\*/\%/g){$comparator='LIKE';}
    $keyword=SiteDefs::idfix($keyword);

    if ($offset||$offset == 0){$offset='LIMIT '.$offset;}
    if($limit){$limit=','.$limit;}
    
    
    my $count_h = $pdbh->{'ensembl'}->prepare("
                                        SELECT COUNT(id) 
                                        FROM exon 
                                        WHERE id  $comparator '$keyword' 
                                        ");
    
    $count_h->execute;
    
    my ($result_count)=$count_h->fetchrow_array;

    my $result_ref = $pdbh->{'ensembl'}->selectall_arrayref("
                                        SELECT id
                                        FROM exon 
                                        WHERE id  $comparator '$keyword' 
                                        $offset $limit
                                        ");
    my @results= map {[$_->[0]]} @$result_ref;
    
    #################################
    # build data structure to return
    #################################
    my $hashref =   {
                    count   => $result_count,
                    results => \@results,
                    };
                
    return $hashref;

}


sub search_protein {

    my ($pdbh,$word, $offset, $limit)=@_;

    $word=~s/\*/\%/g;
    $word = '%'.uc($word).'%';
    $word =~ s/%%+/%/g;
    
    my $sth1 = $pdbh->{'protein'}->prepare( "select 
		   gene_product_id,gene_product_name,swissprot_acc,swissprot_id 
				from gene_product_extra
                               where UPPER(gene_product_name) like ?
                               or UPPER(swissprot_acc) like ?
                               or UPPER(swissprot_id) like ?" );
    

    $sth1->bind_param( 1, $word );
    $sth1->bind_param( 2, $word );
    $sth1->bind_param( 3, $word );
    
    $sth1->execute();

    my %result;
    while( my( $id, $name, $acc, $sid ) = $sth1->fetchrow_array() ) {
        
		 #      0     1   2
        $result{$id}=[$name,$acc,$sid];
    
    }
    $sth1->finish;
    
    
    my @results=map {[$_->[2],
	$_->[1].($_->[2] ne $_->[1] ? " ($_->[2])":"" ).": $_->[0]" ] }
					values %result;

    #################################
    # build data structure to return
    #################################
    my $hashref =   {
                    count   => scalar(@results),
                    results => \@results,
                    };
                
    return $hashref;

}

sub search_disease {
#    my ($pdbh,$keyword, $offset, $limit)=@_;
#    my $comparator= '=';
#    my $re=0;
#
#    
#    #$keyword=~s/\*/\%/g;
#    
#    if ($keyword=~m/\*/){
#        $re=1;
#        };
#    
#    
#    my $index = DiseaseKwIndex->new({
#                                    dbh => $pdbh->{'disease'},
#                                    index_name => 'disease_index',
#                                    });
#    my $arr_ref;
#    
#    if ($re){
#        $arr_ref=$index->search({words  => $keyword,
#                                    re  => 1,
#                                });
#    }
#    else {
#        $arr_ref=$index->search({words  => $keyword,
#                                boolean => 'AND',
#                                });
#    }
#    
#    #######################################################################
#    # arr_ref should now be a reference to an array of disease id numbers, 
#    # so we need to pull the disease names out by these...
#    #######################################################################
#
#    if ($offset||$offset == 0){$offset='LIMIT '.$offset;}
#    if($limit){$limit=','.$limit;}
#    
#    my $result_count=scalar @$arr_ref;
#    
#    my @results=@$arr_ref;
#    
#    if (scalar(@$arr_ref)){
#        my $result_ref = $pdbh->{'disease'}->selectall_arrayref("
#                                        SELECT distinct disease
#                                        FROM disease 
#                                        WHERE disease.id in ("
#                                        .join(',', @$arr_ref).") 
#                                        $offset $limit 
#                                        ");
#        @results= map {[$_->[0]]} @$result_ref;
#        
#    }
#    
my $result_count=0;
my @results=();
    #################################
    # build data structure to return
    #################################
    my $hashref =   {
                    count   => $result_count,
                    results => \@results,
                    };
    
    return $hashref;

}   



sub output_results{
    #######################################################################
    # Get matches & urls, if passed.  If they aren't here, then we print a
    # "No Results" page...
    #######################################################################
    my ($pdbh,$match_hashref,$url_hashref,$table_only)=@_;
    my $q=&CGI::param('q');
    ####################
    # Print page header
    ####################
    my $grpg;
    unless($table_only) {
    if( defined( $ENV{'MOD_PERL'})){
        my $r = Apache->request();
        print CGI::header();
        $r->err_header_out('ensembl_headers_out'=>1);
	my ($head,$onload,$js_divs)=&EnsWeb::cgi_header_info(('initfocus'=>0,'menus'=>1));
	$grpg=GramenePage->new($r);
	print $head,$grpg->start_body(  -ensembl=>1, -bodyattr=>$onload, -bodyfirst=>$js_divs  );
	print "<br><br>\n";
        print EnsWeb::print_form($q||"",&CGI::param('type'));
        print "<br>";
    }
    
    #######################
    # Print Search Heading
    #######################
    print qq(
    <table cellspacing="0" cellpadding="0" border="0" width="100%" class="yellow1">
        <tr>
            <td colspan="4" class="black"><img src="/gfx/blank.gif" width="1" height="1"></td>
        </tr>   
        <tr>
            <td colspan="4"><img src="/gfx/blank.gif" height="6"></td>
        </tr>
        <tr>
            <td>&nbsp;</td>
            <td><span class="h4">Search for "$q"</span></td>
            <td><img src="/gfx/blank.gif" height="8" width="1">
            <td>&nbsp;</td>
        </tr>
        <tr>
            <td colspan="4"><img src="/gfx/blank.gif" height="6"></td>
        </tr>
        <tr>
            <td colspan="4" class="black"><img src="/gfx/blank.gif" width="1" height="1"></td>
        </tr>
    </table>
    );

    }	# end unless $table_only

    ##################################
    # Got matches, so display them...
    ##################################
    if($match_hashref){

        ######################
        # Print table heading
        ######################
        print( "&nbsp;" );
        print qq|<table border="0" width="100%" cellspacing="0" cellpadding="0">|;
	print STDERR "ub table !\n";
        #print( "end_here!\n" );

        my %matches=%$match_hashref;
        my %urls=%$url_hashref;

	#Distribute features into their own types
	if($matches{'feature'}{'count'}) {
	    foreach my  $f (@{$matches{'feature'}{'results'}}) {
		push @{$matches{"feature: $f->[0]"}{'results'}},$f;
	    }
	    delete $matches{'feature'};
	}

	my $spacer=qq(<td><img src="/gfx/blank.gif" width="5" height="22"></td>\n);
        
        foreach my $type(sort keys %matches){

            my $type_count=$matches{$type}{'count'} || scalar(@{$matches{$type}{'results'}}); # || because of the feature distribution above
	    next if($table_only && !$type_count) ;
            #####################
            # Print type
            #####################
	    my $countstring;
            my @values=@{$matches{$type}{'results'}};
	    if ($type eq 'disease'){
		$countstring = '('.scalar @values. 
				" of $type_count results shown)". 
				' (<a href="/perl/diseaseview?disease='.
				&CGI::escape($q).'">'. 
				"Browse all matching diseases</a>)";
	    }
	    else {
		$countstring =  "(".scalar @values. " result". (scalar(@values)==1?"":"s").")";
	    }

            print qq|<tr class="yellow2">\n|;
            print qq|$spacer<td><b>\u$type</b></td>\n|;
	    print qq(<td colspan=3 class="smarial">&nbsp;&nbsp;&nbsp;$countstring</td>);
            print "</tr>\n";

            #####################
            # Print Matches
            #####################
            if (scalar @values){

		my @td=map { 
		  	  qq(<td class="arial">&nbsp;&nbsp;&nbsp;).
			  &make_link($pdbh,$urls{$type},$_,$type).qq(</td>)
		       } @values;
		my @td2=splice(@td,$#td/2+1);
		push @td2,$spacer;
                foreach my $td(@td){
                    print qq(<tr class="yellow1">$spacer$td$spacer).(shift @td2).
			qq($spacer</tr>\n);
                }
	    }
            #####################
            # Print No Matches
            #####################
            else {
                print qq(
                    <tr class="yellow1">$spacer
                      <td colspan=3 class="smarial">&nbsp;&nbsp;&nbsp;No match for this search type</td>
                      $spacer
                    </tr>   
				);
            }

        }
        #########################
        # Close up results table
        #########################
        print qq(
        <tr>
            <td colspan="5" class="black"><img src="/gfx/blank.gif" width="1" height="1"></td>
        </tr>
        </table>
        <br>
		);
    }
    elsif($url_hashref) {	#excuse me, it's an error message
        print "<h3>$url_hashref</h3>/n";
    }
    else {
                my $SELF   = $ENV{'SCRIPT_NAME'};
                $SELF =~ s|.*/(.*)|$1|;
                my $help_link = "";
                eval{
                    $help_link = &HelpView::helplink($SELF);
                    #print STDERR "$help_link\n";
                };
                if ($@){
                    $help_link = "/perl/helpview";    
                    print STDERR "Error in helpview link creation: $@\n";
                }
        print qq|<h3>Your Search has Returned No Results</h3>\n|;
        print qq|<p>You can try another search by typing a string in the box above.|;
        print qq| Try adding a "*" character to do a wildcard search.</p>|;
        print qq|<p>Click <A HREF="$help_link"><img border="0" align="top" alt="Click for help" src="/gfx/helpview/help.gif"></A> for more help on Ensembl identifier searches.</p>|;
    }
    
    unless($table_only) {
	if($grpg) {
	    print $grpg->end_body;
	} else {
	    print EnsWeb::make_cgi_footer();
	}
    }
    Apache::exit;

}


sub jump_to_result {
    my ($url,$value,$type)=@_;
    $value=$value->[0] if($type eq 'protein');
    $url=$url.&CGI::escape($value);
    print STDERR "Redirecting to $url\n";
    &CGI::redirect($url);
    #Apache::Request->internal_redirect($url);
    #Apache->exit;
}



sub make_link {
    my ($pdbh,$url, $pvalue, $type)=@_;
    
    #print STDERR "make_link(,$url,$value,$type)\n";
    my ($value,$text)=@$pvalue;
    $text ||= $value;

    if ($type eq 'contig'){
	if ($pdbh->{'sa'}->is_golden_static_contig($value)){
	    $url=qq(<a href=").$urls{$type}.CGI::escape($value).qq(">$text</a>);
	}
	else {
	    $url = "$text (unavailable - not on golden path)";
	}
    }
    elsif ($type eq 'clone'){
	(my $clone=$value)=~ s/ .*//;
	if ($pdbh->{'sa'}->is_golden_static_clone($clone)){
	    $url=qq(<a href=").$urls{$type}.CGI::escape($clone).qq(">$text</a>);
	}
	else {
	    $url ="$text (unavailable - not on golden path)";
	}
    }
    elsif ($type =~ /^feature: / ) {
	my ($contig,$start,$end)=@{$pvalue}[2,3,4];
	if ($pdbh->{'sa'}->is_golden_static_contig($contig)){
	    $url=qq(<a href=").$urls{'feature'}.CGI::escape($contig)."&fpos_start=$start&fpos_end=$end".qq(">$text</a>);
	}
	else {
	    $url = "$text (unavailable - not on golden path)";
	}
    } 
    else {
	$url=qq(<a href=").$urls{$type}.CGI::escape($value).qq(">$text</a>);
    }
    return $url;
}


sub display_error_and_exit {
    my $error = shift;
    print STDERR "unisearch:$error\n";
    ####################
    # Print page header
    ####################
    if( defined( $ENV{'MOD_PERL'})){
        my $r = Apache->request();
        print header();
        $r->err_header_out('ensembl_headers_out'=>1);
        print EnsWeb::make_cgi_header(('initfocus'=>0, 'menus'=>0));
        print EnsWeb::print_form(&CGI::param('q')||"",&CGI::param('type'));

        print "<br>";
    }
    print &ensembl_exception($error);
    &ensembl_exit;
}

    
# Tidy up before you go...
END {
    foreach (values %dbh) { $_->disconnect if $_ };
    #$ensembl_dbh->disconnect if $ensembl_dbh;
    #$marker_dbh->disconnect if $marker_dbh;
    #$snp_dbh->disconnect if $snp_dbh;
    #$disease_dbh->disconnect if $disease_dbh;
}

1;


