/* Navigator.java
 *
 * created: Sun Jan 10 1999
 *
 * This file is part of Artemis
 *
 * Copyright (C) 1998,1999,2000  Genome Research Limited
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/pathsoft/artemis/uk/ac/sanger/artemis/components/Navigator.java,v 1.1 2004/06/09 09:47:10 tjc Exp $
 */

package uk.ac.sanger.artemis.components;

import uk.ac.sanger.artemis.sequence.*;
import uk.ac.sanger.artemis.*;

import uk.ac.sanger.artemis.util.StringVector;

import java.awt.*;
import java.awt.event.*;

import javax.swing.*;

/**
 *  This component allows the user to navigate around the Entry.
 *
 *  @author Kim Rutherford
 *  @version $Id: Navigator.java,v 1.1 2004/06/09 09:47:10 tjc Exp $
 **/

public class Navigator extends JFrame
    implements EntryGroupChangeListener {
  /**
   *  Create a new Navigator component.
   *  @param selection The Selection that the commands will operate on.
   *  @param goto_event_source The object the we will call gotoBase () on.
   *  @param entry_group The EntryGroup object used when searching for
   *    qualifier text in features.
   **/
  public Navigator (final Selection selection,
                    final GotoEventSource goto_event_source,
                    final EntryGroup entry_group) {
    super ("Artemis Navigator");

    this.selection = selection;
    this.entry_group = entry_group;
    this.goto_event_source = goto_event_source;

    final Font default_font = Options.getOptions ().getFont ();

    GridBagLayout gridbag = new GridBagLayout();
    getContentPane ().setLayout (gridbag);

    setFont (default_font);

    GridBagConstraints c = new GridBagConstraints();

    c.fill = GridBagConstraints.HORIZONTAL;
    c.anchor = GridBagConstraints.NORTH;
    c.weighty = 0;

    final int TEXT_FIELD_WIDTH = 25;

    final ButtonGroup button_group = new ButtonGroup ();

    goto_base_button = new JRadioButton ("Goto Base:", true);

    button_group.add (goto_base_button);

    final JPanel goto_base_panel = new JPanel ();
    goto_base_panel.setLayout (new FlowLayout (FlowLayout.LEFT));
    goto_base_panel.add (goto_base_button);
    c.gridwidth = 2;
    gridbag.setConstraints (goto_base_panel, c);
    getContentPane ().add (goto_base_panel);

    goto_base_text = new JTextField ("", TEXT_FIELD_WIDTH);
    c.gridwidth = GridBagConstraints.REMAINDER;
    gridbag.setConstraints (goto_base_text, c);
    getContentPane ().add (goto_base_text);

    goto_base_text.addKeyListener (new KeyAdapter () {
      public void keyTyped(final KeyEvent e) {
        goto_base_button.setSelected (true);
        if (e.getKeyChar () == '\n') {
          doGoto ();
        }
      }
    });


    goto_gene_name_button =
      new JRadioButton ("Goto Feature With Gene Name:", true);

    button_group.add (goto_gene_name_button);

    final JPanel goto_gene_name_panel = new JPanel ();
    goto_gene_name_panel.setLayout (new FlowLayout (FlowLayout.LEFT));
    goto_gene_name_panel.add (goto_gene_name_button);
    c.gridwidth = 2;
    gridbag.setConstraints (goto_gene_name_panel, c);
    getContentPane ().add (goto_gene_name_panel);

    goto_gene_name_textfield = new JTextField ("", TEXT_FIELD_WIDTH);
    c.gridwidth = GridBagConstraints.REMAINDER;
    gridbag.setConstraints (goto_gene_name_textfield, c);
    getContentPane ().add (goto_gene_name_textfield);

    goto_gene_name_textfield.addKeyListener (new KeyAdapter () {
      public void keyTyped(final KeyEvent e) {
        goto_gene_name_button.setSelected (true);
        if (e.getKeyChar () == '\n') {
          doGoto ();
        }
      }
    });


    goto_qualifier_button =
      new JRadioButton ("Goto Feature With This Qualifier Value:", true);
    button_group.add (goto_qualifier_button);

    final JPanel goto_qualifier_panel = new JPanel ();
    goto_qualifier_panel.setLayout (new FlowLayout (FlowLayout.LEFT));
    goto_qualifier_panel.add (goto_qualifier_button);
    c.gridwidth = 2;
    gridbag.setConstraints (goto_qualifier_panel, c);
    getContentPane ().add (goto_qualifier_panel);

    goto_qualifier_textfield = new JTextField ("", TEXT_FIELD_WIDTH);
    c.gridwidth = GridBagConstraints.REMAINDER;
    gridbag.setConstraints (goto_qualifier_textfield, c);
    getContentPane ().add (goto_qualifier_textfield);

    goto_qualifier_textfield.addKeyListener (new KeyAdapter () {
      public void keyTyped(final KeyEvent e) {
        goto_qualifier_button.setSelected (true);
        if (e.getKeyChar () == '\n') {
          doGoto ();
        }
      }
    });


    goto_key_button =
      new JRadioButton ("Goto Feature With This Key:", true);
    button_group.add (goto_key_button);

    final JPanel goto_key_panel = new JPanel ();
    goto_key_panel.setLayout (new FlowLayout (FlowLayout.LEFT));
    goto_key_panel.add (goto_key_button);
    c.gridwidth = 2;
    gridbag.setConstraints (goto_key_panel, c);
    getContentPane ().add (goto_key_panel);

    goto_feature_key_textfield = new JTextField ("", TEXT_FIELD_WIDTH);
    c.gridwidth = GridBagConstraints.REMAINDER;
    gridbag.setConstraints (goto_feature_key_textfield, c);
    getContentPane ().add (goto_feature_key_textfield);

    goto_feature_key_textfield.addKeyListener (new KeyAdapter () {
      public void keyTyped(final KeyEvent e) {
        goto_key_button.setSelected (true);
        if (e.getKeyChar () == '\n') {
          doGoto ();
        }
      }
    });


    goto_base_pattern_button =
      new JRadioButton ("Find Base Pattern:", true);
    button_group.add (goto_base_pattern_button);

    final JPanel goto_base_pattern_panel = new JPanel ();
    goto_base_pattern_panel.setLayout (new FlowLayout (FlowLayout.LEFT));
    goto_base_pattern_panel.add (goto_base_pattern_button);
    c.gridwidth = 2;
    gridbag.setConstraints (goto_base_pattern_panel, c);
    getContentPane ().add (goto_base_pattern_panel);

    goto_base_pattern_text = new JTextField ("", TEXT_FIELD_WIDTH);
    c.gridwidth = GridBagConstraints.REMAINDER;
    gridbag.setConstraints (goto_base_pattern_text, c);
    getContentPane ().add (goto_base_pattern_text);

    goto_base_pattern_text.addKeyListener (new KeyAdapter () {
      public void keyTyped(final KeyEvent e) {
        goto_base_pattern_button.setSelected (true);
        if (e.getKeyChar () == '\n') {
          doGoto ();
        }
      }
    });

    goto_aa_pattern_button =
      new JRadioButton ("Find Amino Acid String:", true);
    button_group.add (goto_aa_pattern_button);

    final JPanel goto_aa_pattern_panel = new JPanel ();
    goto_aa_pattern_panel.setLayout (new FlowLayout (FlowLayout.LEFT));
    goto_aa_pattern_panel.add (goto_aa_pattern_button);
    c.gridwidth = 2;
    gridbag.setConstraints (goto_aa_pattern_panel, c);
    getContentPane ().add (goto_aa_pattern_panel);

    goto_aa_pattern_text = new JTextField ("", TEXT_FIELD_WIDTH);
    c.gridwidth = GridBagConstraints.REMAINDER;
    gridbag.setConstraints (goto_aa_pattern_text, c);
    getContentPane ().add (goto_aa_pattern_text);

    goto_aa_pattern_text.addKeyListener (new KeyAdapter () {
      public void keyTyped(final KeyEvent e) {
        goto_aa_pattern_button.setSelected (true);
        if (e.getKeyChar () == '\n') {
          doGoto ();
        }
      }
    });


    goto_base_button.setSelected (true);

    final ButtonGroup start_position_button_group =
      new ButtonGroup ();

    final JPanel start_at_an_end_panel = new JPanel ();

    start_at_an_end_button =
      new JRadioButton ("Start search at beginning (or end)", true);

    start_position_button_group.add (start_at_an_end_button);

    c.gridwidth = GridBagConstraints.REMAINDER;

    start_at_an_end_panel.setLayout (new FlowLayout (FlowLayout.LEFT));
    start_at_an_end_panel.add (start_at_an_end_button);

    gridbag.setConstraints (start_at_an_end_panel, c);
    getContentPane ().add (start_at_an_end_panel);


    final JPanel start_at_selection_panel = new JPanel ();

    start_at_selection_button =
      new JRadioButton ("Start search at selection", false);
    start_position_button_group.add (start_at_selection_button);

    start_at_selection_panel.setLayout (new FlowLayout (FlowLayout.LEFT));
    start_at_selection_panel.add (start_at_selection_button);

    c.gridwidth = GridBagConstraints.REMAINDER;

    gridbag.setConstraints (start_at_selection_panel, c);
    getContentPane ().add (start_at_selection_panel);


    final JPanel option_button_panel = new JPanel ();

    option_button_panel.setLayout (new FlowLayout (FlowLayout.LEFT));

    search_backward_button = new JRadioButton ("Search Backward", false);
    ignore_case_button = new JRadioButton ("Ignore Case", true);
    partial_match_button = new JRadioButton ("Allow Substring Matches", true);

    option_button_panel.add (search_backward_button);
    option_button_panel.add (ignore_case_button);
    option_button_panel.add (partial_match_button);

    c.gridwidth = GridBagConstraints.REMAINDER;

    gridbag.setConstraints (option_button_panel, c);
    getContentPane ().add (option_button_panel);


    final JButton goto_button = new JButton ("Goto");

    goto_button.addActionListener (new ActionListener () {
      public void actionPerformed (ActionEvent e) {
        doGoto ();
      }
    });


    final JButton clear_button = new JButton ("Clear");

    clear_button.addActionListener (new ActionListener () {
      public void actionPerformed (ActionEvent e) {
        clear ();
      }
    });


    final JButton close_button = new JButton ("Close");

    close_button.addActionListener (new ActionListener () {
      public void actionPerformed (ActionEvent e) {
        Navigator.this.dispose ();
      }
    });


    final FlowLayout flow_layout =
      new FlowLayout (FlowLayout.CENTER, 15, 5);

    final JPanel close_and_goto_panel = new JPanel (flow_layout);

    close_and_goto_panel.add (goto_button);
    close_and_goto_panel.add (clear_button);
    close_and_goto_panel.add (close_button);

    gridbag.setConstraints (close_and_goto_panel, c);
    getContentPane ().add (close_and_goto_panel);


    addWindowListener (new WindowAdapter () {
      public void windowClosing (WindowEvent event) {
        getEntryGroup ().removeEntryGroupChangeListener (Navigator.this);
        Navigator.this.dispose ();
      }
    });

    getEntryGroup ().addEntryGroupChangeListener (this);

    pack ();

    final Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
    setLocation (new Point ((screen.width - getSize ().width) / 2,
                            (screen.height - getSize ().height) / 2));

    setVisible (true);
  }

  /**
   *  Implementation of the EntryGroupChangeListener interface.  We listen to
   *  EntryGroupChange events so that we can get rid of the Navigator when the
   *  EntryGroup is no longer in use (for example when the EntryEdit is
   *  closed).
   **/
  public void entryGroupChanged (final EntryGroupChangeEvent event) {
    switch (event.getType ()) {
    case EntryGroupChangeEvent.DONE_GONE:
      getEntryGroup ().removeEntryGroupChangeListener (this);
      dispose ();
      break;
    }
  }

  /**
   *  This method finds the given pattern in the Bases of the given EntryGroup
   *  and returns a MarkerRange for it.
   *  @param pattern This is the pattern to search for.
   *  @param entry_group The EntryGroup to search.
   *  @param selection The current selection.
   *  @param start_at_end If true or if there is nothing in the Selection then
   *    the search will start at the first or last base (depending on value of
   *    the next parameter), otherwise the search will start at the Selection.
   *  @param search_backwards If true the search will move from last base to
   *    first base, otherwise first to last.
   *  @return The range that matches the pattern or null if there is no match.
   **/
  public static MarkerRange findBasePattern (final BasePattern pattern,
                                             final EntryGroup entry_group,
                                             final Selection selection,
                                             final boolean start_at_end,
                                             final boolean search_backwards) {
    // if start_at_end is false we want to start the search at the selection
    final Marker selection_base = selection.getLowestBaseOfSelection ();

    final Marker start_position;

    if (start_at_end || selection_base == null) {
      // null means start the search from the beginning
      start_position = null;
    } else {
      start_position = selection_base;
    }

    final MarkerRange match_range =
      pattern.findMatch (entry_group.getBases (),
                         start_position,
                         entry_group.getSequenceLength (),
                         search_backwards);

    if (match_range == null) {
      return null;
    } else {
      return match_range;
    }
  }

  /**
   *  This method finds the given amino acid seqeunce, sets the selection to
   *  the matching bases and then sends a GotoEvent to all the GotoEvent
   *  listeners that will make the first base of the match visible.
   *  @param sequence This is the pattern to search for.
   *  @param entry_group The EntryGroup to search.
   *  @param selection The current selection.
   *  @param start_at_end If true or if there is nothing in the Selection then
   *    the search will start at first or last base (depending on value of the
   *    next parameter), otherwise the search will start at the Selection.
   *  @param search_backwards If true the search will move from last base to
   *    first base, otherwise first to last.
   *  @return The range that matches the pattern or null if there is no match.
   **/
  public static MarkerRange findAminoAcidSequence (final AminoAcidSequence
                                                     sequence,
                                                   final EntryGroup
                                                     entry_group,
                                                   final Selection selection,
                                                   final boolean start_at_end,
                                                   final boolean
                                                     search_backwards) {
    // if start_at_end is false we want to start the search at the selection
    final Marker selection_base = selection.getLowestBaseOfSelection ();

    final Marker start_position;

    if (start_at_end || selection_base == null) {
      // null means start the search from the beginning
      start_position = null;
    } else {
      start_position = selection_base;
    }

    final MarkerRange match_range;

    if (search_backwards) {
      match_range = sequence.findMatch (entry_group.getBases (),
                                        start_position,
                                        true);
    } else {
      match_range = sequence.findMatch (entry_group.getBases (),
                                        start_position,
                                        false);
    }

    if (match_range == null) {
      return null;
    } else {
      return match_range;
    }
  }

  /**
   *  This method will perform the selected goto function.
   **/
  private void doGoto () {
    if (goto_base_button.isSelected ()) {
      doGotoBase ();
      return;
    }

    if (goto_base_pattern_button.isSelected ()) {
      doGotoBasePattern ();
      return;
    }

    if (goto_aa_pattern_button.isSelected ()) {
      doGotoAAPattern ();
      return;
    }

    if (goto_gene_name_button.isSelected ()) {
      final StringVector qualifiers_to_search = new StringVector ();
      qualifiers_to_search.add (Options.getOptions ().getAllGeneNames ());

      doGotoQualifierValue (qualifiers_to_search,
                            goto_gene_name_textfield.getText ().trim ());
      return;
    }

    if (goto_qualifier_button.isSelected ()) {
      doGotoQualifierValue (null, goto_qualifier_textfield.getText ().trim ());
      return;
    }

    if (goto_key_button.isSelected ()) {
      doGotoKey ();
      return;
    }
  }

  /**
   *  Clear all the JTextField components.
   **/
  private void clear () {
    goto_base_text.setText ("");
    goto_base_pattern_text.setText ("");
    goto_aa_pattern_text.setText ("");
    goto_qualifier_textfield.setText ("");
    goto_gene_name_textfield.setText ("");
    goto_feature_key_textfield.setText ("");
  }

  /**
   *  Show a message dialog saying that the search text field is empty.
   **/
  private void searchTextEmptyError () {
    new MessageDialog (this, "You have not entered a value to search for");
  }

  /**
   *  Go to the base that the user typed in to the goto_base_text TextArea.
   **/
  private void doGotoBase () {
    final String number_string = goto_base_text.getText ().trim ();

    if (number_string.length () == 0) {
      new MessageDialog (this, "you have not entered a number to go to");
      return;
    }

    try {
      final int destination_base =
        Integer.valueOf (number_string).intValue ();

      final MarkerRange destination_range =
        goto_event_source.gotoBase (destination_base);

      if (destination_range == null) {
        new MessageDialog (this,
                           "the base is out of range for this sequence");
      } else {
        // success select that base
        getSelection ().setMarkerRange (destination_range);
      }
    } catch (NumberFormatException e) {
      new MessageDialog (this, "Cannot understand this number: " +
                         goto_base_text.getText ());
    }
  }

  /**
   *  Go to the base pattern that the user typed in to the
   *  goto_base_pattern_text TextArea.
   **/
  private void doGotoBasePattern () {
    try {
      final String pattern_string =
        goto_base_pattern_text.getText ().trim ();

      if (pattern_string.length () == 0) {
        new MessageDialog (this, "you have not entered a pattern to go to");
        return;
      }

      final BasePattern pattern = new BasePattern (pattern_string);

      final boolean start_at_an_end = start_at_an_end_button.isSelected ();

      start_at_selection_button.setSelected (true);

      final MarkerRange match_range =
        findBasePattern (pattern,
                         getEntryGroup (),
                         getSelection (),
                         start_at_an_end,
                         search_backward_button.isSelected ());

      if (match_range == null) {
        new MessageDialog (this, "reached the end of sequence");
      } else {
        getSelection ().setMarkerRange (match_range);

        final Marker first_selected_base =
          getSelection ().getLowestBaseOfSelection ();

        goto_event_source.gotoBase (first_selected_base);
      }
    } catch (BasePatternFormatException e) {
      new MessageDialog (this,
                         "Illegal base pattern: " +
                         goto_base_pattern_text.getText ());
    }
  }

  /**
   *  Find the amino acid pattern that the user typed in to the
   *  goto_aa_pattern_text TextArea.
   **/
  private void doGotoAAPattern () {
    final String pattern_string =
      goto_aa_pattern_text.getText ().trim ();

    if (pattern_string.length () == 0) {
      new MessageDialog (this, "you have not entered a pattern to go to");
      return;
    }

    final AminoAcidSequence pattern = new AminoAcidSequence (pattern_string);

    final boolean start_at_an_end = start_at_an_end_button.isSelected ();

    start_at_selection_button.setSelected (true);

    final boolean search_backwards = search_backward_button.isSelected ();

    final MarkerRange match_range =
      findAminoAcidSequence (pattern,
                             getEntryGroup (),
                             getSelection (),
                             start_at_an_end,
                             search_backwards);

    if (match_range == null) {
      new MessageDialog (this, "reached the end of sequence");
    } else {
      getSelection ().setMarkerRange (match_range);

      goto_event_source.gotoBase (getSelection ().getLowestBaseOfSelection ());
    }
  }

  /**
   *  Select the next feature that contains the text given by the user in the
   *  goto_qualifier_textfield TextArea.
   **/
  private void doGotoQualifierValue (final StringVector qualifiers_to_search,
                                     final String search_text) {
    if (search_text.equals ("")) {
      searchTextEmptyError ();
      return;
    }

    final FeatureVector selected_features =
      getSelection ().getAllFeatures ();

    final int index;

    if (selected_features.size () == 0 ||
        start_at_an_end_button.isSelected ()) {
      index = -1;
    } else {
      index = getEntryGroup ().indexOf (selected_features.elementAt (0));
    }

    final int first_search_feature_index;

    Feature found_feature = null;

    if (search_backward_button.isSelected ()) {
      if (index == -1) {
        // nothing was selected so start the search at the first feature
        first_search_feature_index =
          getEntryGroup ().getAllFeaturesCount () - 1;
      } else {
        first_search_feature_index = index - 1;
      }

      for (int i = first_search_feature_index ; i >= 0 ; --i) {
        final Feature this_feature = getEntryGroup ().featureAt (i);

        if (this_feature.containsText (search_text,
                                       ignore_case_button.isSelected (),
                                       partial_match_button.isSelected (),
                                       qualifiers_to_search)) {
          found_feature = this_feature;
          break;
        }
      }
    } else {
      if (index == -1) {
        // nothing was selected so start the search at the first feature
        first_search_feature_index = 0;
      } else {
        first_search_feature_index = index + 1;
      }

      for (int i = first_search_feature_index ;
           i < getEntryGroup ().getAllFeaturesCount () ;
           ++i) {
        final Feature this_feature = getEntryGroup ().featureAt (i);

        if (this_feature.containsText (search_text,
                                       ignore_case_button.isSelected (),
                                       partial_match_button.isSelected (),
                                       qualifiers_to_search)) {

          found_feature = this_feature;
          break;
        }
      }
    }

    if (found_feature == null) {
      getSelection ().clear ();
      start_at_an_end_button.setSelected (true);

      new MessageDialog (this, "text not found");
    } else {
      getSelection ().set (found_feature);
      goto_event_source.gotoBase (getSelection ().getLowestBaseOfSelection ());
      start_at_selection_button.setSelected (true);
    }
  }

  /**
   *  Select the next feature that has the key given by the user in the
   *  goto_feature_key_textfield TextArea.
   **/
  private void doGotoKey () {
    final FeatureVector selected_features =
      getSelection ().getAllFeatures ();

    final int index;

    if (selected_features.size () == 0 ||
        start_at_an_end_button.isSelected ()) {
      index = -1;
    } else {
      index = getEntryGroup ().indexOf (selected_features.elementAt (0));
    }

    final int first_search_feature_index;

    final String search_key_string =
      goto_feature_key_textfield.getText ().trim ();

    if (search_key_string.equals ("")) {
      searchTextEmptyError ();
      return;
    }

    Feature found_feature = null;

    if (search_backward_button.isSelected ()) {
      if (index == -1) {
        // nothing was selected so start the search at the first feature
        first_search_feature_index =
          getEntryGroup ().getAllFeaturesCount () - 1;
      } else {
        first_search_feature_index = index - 1;
      }

      for (int i = first_search_feature_index ; i >= 0 ; --i) {
        final Feature this_feature = getEntryGroup ().featureAt (i);

        if (keyMatches (this_feature, search_key_string)) {
          found_feature = this_feature;
          break;
        }
      }
    } else {
      if (index == -1) {
        // nothing was selected so start the search at the first feature
        first_search_feature_index = 0;
      } else {
        first_search_feature_index = index + 1;
      }

      for (int i = first_search_feature_index ;
           i < getEntryGroup ().getAllFeaturesCount () ;
           ++i) {
        final Feature this_feature = getEntryGroup ().featureAt (i);

        if (keyMatches (this_feature, search_key_string)) {
          found_feature = this_feature;
          break;
        }
      }
    }

    if (found_feature == null) {
      getSelection ().clear ();
      start_at_an_end_button.setSelected (true);

      new MessageDialog (this, "key not found");
    } else {
      getSelection ().set (found_feature);
      goto_event_source.gotoBase (getSelection ().getLowestBaseOfSelection ());
      start_at_selection_button.setSelected (true);
    }
  }

  /**
   *  Returns true if and only if the given feature has search_key_string as
   *  it's Key.
   **/
  public boolean keyMatches (final Feature test_feature,
                             final String search_key_string) {
    final String feature_key_string;

    if (ignore_case_button.isSelected ()) {
      feature_key_string = test_feature.getKey ().toString ().toLowerCase ();
    } else {
      feature_key_string = test_feature.getKey ().toString ();
    }

    if (feature_key_string.equals (search_key_string.toLowerCase ())) {
      return true;
    } else {
      return false;
    }
  }

  /**
   *  Return the Selection object that was passed to the constructor.
   **/
  private Selection getSelection () {
    return selection;
  }

  /**
   *  Return the EntryGroup object that was passed to the constructor.
   **/
  private EntryGroup getEntryGroup () {
    return entry_group;
  }

  /**
   *  The JRadioButton that selects the goto base function.
   **/
  final JRadioButton goto_base_button;

  /**
   *  The JRadioButton that selects the goto base pattern function.
   **/
  final JRadioButton goto_base_pattern_button;

  /**
   *  The JRadioButton that selects the find amino acid sequence function.
   **/
  final JRadioButton goto_aa_pattern_button;

  /**
   *  The JRadioButton that selects the goto feature qualifier value function.
   **/
  final JRadioButton goto_qualifier_button;

  /**
   *  The JRadioButton that selects the goto gene name function.
   **/
  final JRadioButton goto_gene_name_button;

  /**
   *  The JRadioButton that selects the goto feature key function.
   **/
  final JRadioButton goto_key_button;

  /**
   *  This contains the pattern to search for if the user has selected the
   *  goto base function.
   **/
  final JTextField goto_base_text;

  /**
   *  This contains the pattern to search for if the user has selected the
   *  goto base pattern function.
   **/
  final JTextField goto_base_pattern_text;

  /**
   *  This contains the pattern to search for if the user has selected the
   *  goto amino acid function.
   **/
  final JTextField goto_aa_pattern_text;

  /**
   *  This contains the pattern to search for if the user has selected the
   *  goto qualifier value function.
   **/
  final JTextField goto_qualifier_textfield;

  /**
   *  This contains the pattern to search for if the user has selected the
   *  goto gene name function.
   **/
  final JTextField goto_gene_name_textfield;

  /**
   *  This contains the key to search for if the user has selected the
   *  goto key function.
   **/
  final JTextField goto_feature_key_textfield;

  /**
   *  The user selects this JRadioButton if the search should start at first/last
   *  base or first/last feature (depending on the search type).
   **/
  JRadioButton start_at_an_end_button;

  /**
   *  The user selects this JRadioButton if the search should start at the
   *  position of the current selection.
   **/
  final JRadioButton start_at_selection_button;

  /**
   *  If checked the search will go backwards.
   **/
  final JRadioButton search_backward_button;

  /**
   *  If checked the search will ignore the case of the query and subject.
   **/
  final JRadioButton ignore_case_button;

  /**
   *  If checked the search text is allowed to match a substring of a
   *  qualifier value.
   **/
  final JRadioButton partial_match_button;

  /**
   *  The GotoEventSource object that was passed to the constructor.
   **/
  final GotoEventSource goto_event_source;

  /**
   *  The EntryGroup object that was passed to the constructor.
   **/
  final EntryGroup entry_group;

  /**
   *  This is the Selection that was passed to the constructor.
   **/
  final private Selection selection;
}
