#!/usr/local/bin/perl

###############################################################################
# Program     : Search
# $Id$
#
# Description : Searches the search_key table for matching elements
#
# SBEAMS is Copyright (C) 2000-2005 Institute for Systems Biology
# This program is governed by the terms of the GNU General Public License (GPL)
# version 2 as published by the Free Software Foundation.  It is provided
# WITHOUT ANY WARRANTY.  See the full description of GPL terms in the
# LICENSE file distributed with this software.
#
###############################################################################


###############################################################################
# Set up all needed modules and objects
###############################################################################
use strict;
use Getopt::Long;
use FindBin;

use lib "$FindBin::Bin/../../lib/perl";
use vars qw ($sbeams $sbeamsMOD $q $current_contact_id $current_username
             $PROG_NAME $USAGE %OPTIONS $QUIET $VERBOSE $DEBUG $DATABASE
             $TABLE_NAME $PROGRAM_FILE_NAME $CATEGORY $DB_TABLE_NAME
             @MENU_OPTIONS);

use SBEAMS::Connection qw($q $log);
use SBEAMS::Connection::Settings;
use SBEAMS::Connection::Tables;
use SBEAMS::Connection::TabMenu;

use SBEAMS::PeptideAtlas;
use SBEAMS::PeptideAtlas::Settings;
use SBEAMS::PeptideAtlas::Tables;

$sbeams = new SBEAMS::Connection;
$sbeamsMOD = new SBEAMS::PeptideAtlas;
$sbeamsMOD->setSBEAMS($sbeams);
$sbeams->setSBEAMS_SUBDIR($SBEAMS_SUBDIR);



###############################################################################
# Set program name and usage banner for command like use
###############################################################################
$PROG_NAME = $FindBin::Script;
$USAGE = <<EOU;
Usage: $PROG_NAME [OPTIONS] key=value key=value ...
Options:
  --verbose n         Set verbosity level.  default is 0
  --quiet             Set flag to print nothing at all except errors
  --debug n           Set debug flag

 e.g.:  $PROG_NAME [OPTIONS] [keyword=value],...

EOU

#### Process options
unless (GetOptions(\%OPTIONS,"verbose:s","quiet","debug:s")) {
  print "$USAGE";
  exit;
}

$VERBOSE = $OPTIONS{"verbose"} || 0;
$QUIET = $OPTIONS{"quiet"} || 0;
$DEBUG = $OPTIONS{"debug"} || 0;

if ($DEBUG) {
  print "Options settings:\n";
  print "  VERBOSE = $VERBOSE\n";
  print "  QUIET = $QUIET\n";
  print "  DEBUG = $DEBUG\n";
}



###############################################################################
# Set Global Variables and execute main()
###############################################################################
main();
exit(0);



###############################################################################
# Main Program:
#
# Call $sbeams->Authenticate() and exit if it fails or continue if it works.
###############################################################################
sub main {

  #### Do the SBEAMS authentication and exit if a username is not returned
  exit unless ($current_username = $sbeams->Authenticate(
      permitted_work_groups_ref=>['PeptideAtlas_user','PeptideAtlas_admin',
      'PeptideAtlas_readonly'],
      #connect_read_only=>1,
      allow_anonymous_access=>1,
  ));


  #### Read in the default input parameters
  my %parameters;
  my $n_params_found = $sbeams->parse_input_parameters(
      q=>$q,
      parameters_ref=>\%parameters);
  #$sbeams->printDebuggingInfo($q);

  #### Process generic "state" parameters before we start
  $sbeams->processStandardParameters(parameters_ref=>\%parameters);

  #### Decide what action to take based on information so far
  if ($parameters{action} eq "???") {
      # Some action

  } else {
      handle_request(ref_parameters=>\%parameters);
      $sbeamsMOD->display_page_footer();
  }


} # end main



###############################################################################
# Handle Request
###############################################################################
sub handle_request {

  my %args = @_;

  #### Process the arguments list
  my $ref_parameters = $args{'ref_parameters'}
      || die "ref_parameters not passed";

  my %parameters = %{$ref_parameters};


  #### Define some generic varibles
  my ($i,$element,$key,$value,$line,$result,$sql);


  #### Define some variables for a query and resultset
  my %resultset = ();
  my $resultset_ref = \%resultset;
  my (%url_cols,%hidden_cols,%max_widths,$show_sql);


  #### Read in the standard form values
  my $apply_action  = $parameters{'action'} || $parameters{'apply_action'};
  my $TABLE_NAME = $parameters{'QUERY_NAME'};


  #### Set some specific settings for this program
  my $CATEGORY="Search PeptideAtlas";
  my $PROGRAM_FILE_NAME = $PROG_NAME;
  my $base_url = "$CGI_BASE_DIR/$SBEAMS_SUBDIR/$PROGRAM_FILE_NAME";
  my $help_url = "$CGI_BASE_DIR/help_popup.cgi";


  #### If the apply action was to recall a previous resultset, do it
  my %rs_params = $sbeams->parseResultSetParams('q' => $q);
  my $n_params_found = 0;

  if ($apply_action eq "VIEWRESULTSET") {
    $sbeams->readResultSet(
      resultset_file=>$rs_params{set_name},
      resultset_ref=>$resultset_ref,
      query_parameters_ref=>\%parameters,
      resultset_params_ref=>\%rs_params,
    );
    $n_params_found = 99;
  }

  #### Get the passed parameters
  my $search_key = $parameters{"search_key"};
  my $organism_name = $parameters{"organism_name"};

  #### If a new search_key was supplied, store it
  if ($search_key) {
    $sbeams->setSessionAttribute(
      key => 'PeptideAtlas_search_key',
      value => $search_key,
    );

  #### Else see if we had one stored
  } else {
    $search_key = $sbeams->getSessionAttribute(
      key => 'PeptideAtlas_search_key',
    );
  }


  #### Build the list of organism_names
  my $organism_selection = getOrganismSelection(
    organism_name => $organism_name,
  );


  #### This is needed for displaying the page header
  my $project_id = $sbeamsMOD->getProjectID(
    atlas_build_id => $parameters{atlas_build_id}
  );


  #### Show current user context information
  #print "<BR>\n" if ($sbeams->output_mode() eq 'html');
  #$sbeams->printUserContext();

  #### Get the HTML to display the tabs
  my $tabMenu = $sbeamsMOD->getTabMenu(
    parameters_ref => \%parameters,
    program_name => $PROG_NAME,
  );



  #### If the output_mode is HTML, then display the form
  my $buffer = '';
  if ($sbeams->output_mode() eq 'html') {

      $buffer .= $q->start_form(-method=>"POST",
                           -action=>"$base_url",
                          );
      $buffer .= "<BR>".$tabMenu->asHTML();
      $buffer .= "<BR><BR><P>";
      $buffer .= qq~<nobr><CENTER><IMG SRC="$HTML_BASE_DIR/images/PeptideAtlas_Logo.png"><BR>~;
      #$buffer .= qq~<img src="$HTML_BASE_DIR/images/space.gif" height=1 width=30>~;
      $buffer .= $q->textfield(-name=>"search_key",
                          -default=>$search_key,
			  -size=>60,
			  -maxlength=>60,
                         );
      $buffer .= "&nbsp;&nbsp;&nbsp;";
      $buffer .= $q->submit(-name => "action",
                       -value => 'QUERY',
                       -label => 'GO');
      $buffer .= qq~<BR>
        (e.g.
          <A HREF="$base_url?search_key=ENSP00000222219&action=GO"><SPAN TITLE="Ensembl Protein Identifier" CLASS="popup">ENSP00000222219</SPAN></A>,
          <A HREF="$base_url?search_key=IPI00010348&action=GO">IPI00010348</A>,
          <A HREF="$base_url?search_key=NP_001366&action=GO">NP_001366</A>,
          <A HREF="$base_url?search_key=Hs.167531&action=GO">Hs.167531</A>,
          <A HREF="$base_url?search_key=%25BAT%25&action=GO">%BAT%</A>,
          <A HREF="$base_url?search_key=DNASE2&action=GO">DNASE2</A>,<BR>
          <A HREF="$base_url?search_key=%25helicase%25&action=GO">\%helicase\%</A>,
          <A HREF="$base_url?search_key=Q9HCC0&action=GO">Q9HCC0</A>,
          <A HREF="$base_url?search_key=MCCC2_HUMAN&action=GO">MCCC2_HUMAN</A>,
          <A HREF="$base_url?search_key=PAp00000097&action=GO">PAp00000097</A>,
          <A HREF="$base_url?search_key=AAVEEGIVLGGGCALLR&action=GO">AAVEEGIVLGGGCALLR</A>
        )<BR>
        Organism: <select name="organism_name">
        $organism_selection->{HTML_optionlist}
        </select>
        </CENTER></nobr>
        </P>
      ~;
      $buffer .= $q->endform;
  }



  #########################################################################
  #### Process all the constraints

  #### If search_key was not selected, stop here
  unless ($parameters{search_key}) {
    if ($sbeams->output_mode() eq 'html') {
      $sbeamsMOD->display_page_header(project_id => $project_id);
      print $buffer;
    } else {
      $sbeams->reportException(
          state => 'ERROR',
          type => 'INSUFFICIENT CONSTRAINTS',
          message => 'You must provide an search_key',
      );
    }
    return;
  }


  #### Build SEARCH_KEY constraint
  my $search_key_clause = $sbeams->parseConstraint2SQL(
      constraint_column=>"search_key_name",
      constraint_type=>"plain_text",
      constraint_name=>"Search Key",
      constraint_value=>$parameters{search_key} );
  return if ($search_key_clause eq '-1');


  #### Define the SQL statement to find the biosequence
  $sql = qq~
       SELECT search_key_name,search_key_type,organism_name,resource_name,
              resource_type,resource_n_matches,resource_url,O.organism_id
         FROM $TBAT_SEARCH_KEY SK
         JOIN $TB_ORGANISM O ON (O.organism_id = SK.organism_id)
        WHERE 1 = 1
          $search_key_clause
          AND O.organism_id IN ( $organism_selection->{organism_ids} )
       ORDER BY search_key_name
  ~;


  #### Define the hypertext links for columns that need them
  %url_cols = (
    	       'resource_name' => "$CGI_BASE_DIR/PeptideAtlas/%6V",
  );

  #### Define the hidden columns
  %hidden_cols = (
    	       'resource_url' => 1,
    	       'organism_id' => 1,
  );


  #########################################################################
  #### If QUERY or VIEWRESULTSET was selected, display the data
  if ($apply_action =~ /(QUERY|GO|VIEWRESULTSET)/) {

    #### Show the SQL that will be or was executed
    $sbeams->display_sql(sql=>$sql) if ($show_sql);

    #### If the action contained QUERY, then fetch the results from
    #### the database
    if ($apply_action =~ /(QUERY|GO)/i) {

      #### Fetch the results from the database server
      $sbeams->fetchResultSet(
        sql_query=>$sql,
        resultset_ref=>$resultset_ref,
      );

      #### Store the resultset and parameters to disk resultset cache
      $rs_params{set_name} = "SETME";
      $sbeams->writeResultSet(
        resultset_file_ref=>\$rs_params{set_name},
        resultset_ref=>$resultset_ref,
        query_parameters_ref=>\%parameters,
        resultset_params_ref=>\%rs_params,
        query_name=>"$SBEAMS_SUBDIR/$PROGRAM_FILE_NAME",
      );
    }


    #### Determine how many results came back
    my $n_results = scalar(@{$resultset_ref->{data_ref}});

    #### If exactly one result came back, then redirect to the one hit
    if ($n_results == 1) {
      print "Status: 302 Resource Temporarily Moved\n";
      print "Location: $CGI_BASE_DIR/PeptideAtlas/".
	$resultset_ref->{data_ref}->[0]->[6]."\n\n";
      exit;
    }

    #### Otherwise, display the page header to show the match results
    $sbeamsMOD->display_page_header(project_id => $project_id);

    if ($sbeams->output_mode() eq 'html') {
      print $buffer;
      print "<BR><BR>";
    }


    my $cleaned_search_key = $search_key;
    $cleaned_search_key =~ s/^%//;
    $cleaned_search_key =~ s/%$//;

    #### If 0 results came back, then inform the user
    if ($n_results == 0) {
      print "There were no matches in the index to match your search key '$search_key'<BR>";
      if ($search_key !~ /%/) {
        print qq~
          <BR>You can broaden the search by placing wildcards around your search key like this:
          <A HREF="$base_url?search_key=$cleaned_search_key%25&action=GO">$cleaned_search_key%</A>,
          <A HREF="$base_url?search_key=%25$cleaned_search_key%25&action=GO">%$cleaned_search_key%</A>
        ~;
      }
      return(0);
    }

    print qq~
      <P>
      Your search returned $n_results matches.  Please choose one from below.
      Or you can broaden the search by placing wildcards around your search key like this:
          <A HREF="$base_url?search_key=$cleaned_search_key%25&action=GO">$cleaned_search_key%</A>,
          <A HREF="$base_url?search_key=%25$cleaned_search_key%25&action=GO">%$cleaned_search_key%</A>
      </P>
    ~;

    #### Display the resultset
    $sbeams->displayResultSet(
      resultset_ref=>$resultset_ref,
      query_parameters_ref=>\%parameters,
      rs_params_ref=>\%rs_params,
      url_cols_ref=>\%url_cols,
      hidden_cols_ref=>\%hidden_cols,
      max_widths=>\%max_widths,
      #column_titles_ref=>\@column_titles,
      base_url=>$base_url,
    );

    #### Display the resultset controls
    $sbeams->displayResultSetControls(
      resultset_ref=>$resultset_ref,
      query_parameters_ref=>\%parameters,
      rs_params_ref=>\%rs_params,
      base_url=>$base_url,
    );


  #### If QUERY was not selected, then tell the user to enter some parameters
  } else {
    if ($sbeams->invocation_mode() eq 'http') {
      $sbeamsMOD->display_page_header(project_id => $project_id);
      print $buffer;
      print "Click [GO] to execute the search<BR>\n";
    } else {
      print "Set action=GO to execute the search\n";
    }
  }


} # end handle_request



###############################################################################
# getOrganismSelection
###############################################################################
sub getOrganismSelection {
  my $SUB_NAME = 'getOrganismSelection';
  my %args = @_;

  #### Decode the argument list
  my $organism_name = $args{'organism_name'};


  #### If none was supplied, see if it was cached for this session
  unless ($organism_name) {
    $organism_name = $sbeams->getSessionAttribute(
      key => 'PeptideAtlas_organism_name',
    );
  }

  #### Or default to Any
  unless ($organism_name) {
    $organism_name = 'Any';
  }


  #### Get a list of accessible project_ids
  my @accessible_project_ids = $sbeams->getAccessibleProjects();
  my $accessible_project_ids = join( ",", @accessible_project_ids ) || '0';

  #### Get a hash of available organisms via atlas builds
  my $sql = qq~
      SELECT DISTINCT O.organism_id,O.organism_name
        FROM $TBAT_ATLAS_BUILD AB
        JOIN $TBAT_BIOSEQUENCE_SET BS
             ON (BS.biosequence_set_id = AB.biosequence_set_id)
        JOIN $TB_ORGANISM O ON (O.organism_id = BS.organism_id)
       WHERE AB.project_id IN ( $accessible_project_ids )
         AND AB.record_status!='D'
       ORDER BY organism_name
  ~;
  my @organisms = $sbeams->selectSeveralColumns($sql);

  my @options = ('Any');
  my %options = ('Any'=>'Any');
  my %organism_ids;

  #### Build the list of available organisms
  foreach my $organism ( @organisms ) {
    my $each_organism_name = $organism->[1];
    push(@options,$each_organism_name);
    $options{$each_organism_name} = $each_organism_name;
    $organism_ids{$each_organism_name} = $organism->[0];
  }


  #### Build the option list HTML
  my $optionlist = '';
  my $matched_parameter = 0;
  foreach my $key ( @options ) {
    my $flag = '';
    if ($key eq $organism_name) {
      $flag = 'SELECTED';
      $matched_parameter++;
    }
    $optionlist .= "<OPTION VALUE=\"$key\" $flag>$options{$key}</OPTION>\n";
  };


  #### Also make sure the user selected a valid option
  unless ($matched_parameter) {
    $organism_name = 'Any';
  }


  #### Get the organism_ids
  my $organism_ids = $organism_ids{$organism_name};
  if ($organism_name eq 'Any') {
    $organism_ids = join(",",values(%organism_ids));
  }

  #### Build a data structure to return
  my %tmp = (
    HTML_optionlist => $optionlist,
    organism_name => $organism_name,
    organism_ids => $organism_ids,
  );

  #### Store the selected organism_name in the session cache
  if ($organism_name) {
    $sbeams->setSessionAttribute(
      key => 'PeptideAtlas_organism_name',
      value => $organism_name,
    );
  }

  return \%tmp;

} # end getOrganismSelection
