/* Selector.java
 *
 * created: Tue Apr 11 2000
 *
 * This file is part of Artemis
 *
 * Copyright (C) 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: /nfs/disk222/yeastpub/Repository/powmap/diana/components/Selector.java,v 1.6 2000/10/03 12:54:19 kmr Exp $
 */

package diana.components;

import diana.*;

import uk.ac.sanger.pathogens.embl.EntryInformation;

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

/**
 *  This component allows the user to set the selection by filtering the
 *  features in an EntryGroup on key and contents.
 *
 *  @author Kim Rutherford <kmr@sanger.ac.uk>
 *  @version $Id: Selector.java,v 1.6 2000/10/03 12:54:19 kmr Exp $
 **/

public class Selector extends Frame {
  /**
   *  Create a new Selector that van set the given Selection.
   *  @param selection The Selection that the commands in the menu will
   *    operate on.
   *  @param entry_group The component will choose features from this
   *    EntryGroup.
   *  @param goto_event_source The object the we will call gotoBase () on.
   **/
  public Selector (final Selection selection,
                   final GotoEventSource goto_event_source,
                   final EntryGroup entry_group) {
    super ("Artemis Feature Selector");

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

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

    setFont (default_font);

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

    GridBagConstraints c = new GridBagConstraints();

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

    final Label top_label = new Label ("Select by:");
    gridbag.setConstraints (top_label, c);
    add (top_label);


    by_key_button = new Checkbox ("Key: ", false);
    final Panel by_key_panel = new Panel ();
    by_key_panel.setLayout (new FlowLayout (FlowLayout.LEFT));
    by_key_panel.add (by_key_button);
    c.gridwidth = 2;
    gridbag.setConstraints (by_key_panel, c);
    add (by_key_panel);

    final EntryInformation default_entry_information =
      Options.getArtemisEntryInformation ();

    key_selector = new KeyChoice (default_entry_information);
    c.gridwidth = GridBagConstraints.REMAINDER;
    gridbag.setConstraints (key_selector, c);
    add (key_selector);

    key_selector.addItemListener (new ItemListener () {
      public void itemStateChanged (ItemEvent _) {
        by_key_button.setState (true);
      }
    });

    by_key_button.addItemListener (new ItemListener () {
      public void itemStateChanged (ItemEvent e) {
        if (!by_key_button.getState ()) {
          by_qualifier_button.setState (false);
        }
      }
    });


    by_qualifier_button = new Checkbox ("Qualifier: ", false);
    final Panel by_qualifier_panel = new Panel ();
    by_qualifier_panel.setLayout (new FlowLayout (FlowLayout.LEFT));
    by_qualifier_panel.add (by_qualifier_button);
    c.gridwidth = 2;
    gridbag.setConstraints (by_qualifier_panel, c);
    add (by_qualifier_panel);

    qualifier_selector = new QualifierChoice (default_entry_information,
                                              key_selector.getSelectedItem ());
    c.gridwidth = GridBagConstraints.REMAINDER;
    gridbag.setConstraints (qualifier_selector, c);
    add (qualifier_selector);

    qualifier_selector.addItemListener (new ItemListener () {
      public void itemStateChanged (ItemEvent _) {
        by_qualifier_button.setState (true);
      }
    });

    key_selector.addItemListener (new ItemListener () {
      public void itemStateChanged (ItemEvent _) {
        qualifier_selector.setKey (key_selector.getSelectedItem ());
      }
    });

    by_qualifier_button.addItemListener (new ItemListener () {
      public void itemStateChanged (ItemEvent e) {
        if (by_qualifier_button.getState ()) {
          if (!by_key_button.getState ()) {
            by_key_button.setState (true);
          }
        }
      }
    });


    final Label qualifier_text_label = new Label ("containing this text: ");
    c.gridwidth = 2;
    gridbag.setConstraints (qualifier_text_label, c);
    add (qualifier_text_label);

    qualifier_text = new TextField ("", 18);

    c.gridwidth = GridBagConstraints.REMAINDER;
    gridbag.setConstraints (qualifier_text, c);
    add (qualifier_text);


    ignore_case = new Checkbox ("ignore case", true);

    final Panel ignore_case_panel = new Panel ();

    ignore_case_panel.setLayout (new FlowLayout (FlowLayout.LEFT));
    ignore_case_panel.add (ignore_case);

    c.gridwidth = GridBagConstraints.REMAINDER;
    gridbag.setConstraints (ignore_case_panel, c);
    add (ignore_case_panel);

    
    final Panel strand_panel = new Panel ();

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

    forward_strand_checkbox = new Checkbox ("forward strand features", true);
    strand_panel.add (forward_strand_checkbox);
    forward_strand_checkbox.addItemListener (new ItemListener () {
      public void itemStateChanged (ItemEvent _) {
        if (!forward_strand_checkbox.getState () &&
            !reverse_strand_checkbox.getState ()) {
          // make sure one of the strand is always selected
          reverse_strand_checkbox.setState (true);
        }
      }
    });


    reverse_strand_checkbox = new Checkbox ("reverse strand features", true);
    strand_panel.add (reverse_strand_checkbox);
    reverse_strand_checkbox.addItemListener (new ItemListener () {
      public void itemStateChanged (ItemEvent _) {
        if (!reverse_strand_checkbox.getState () &&
            !forward_strand_checkbox.getState ()) {
          // make sure one of the strand is always selected
          forward_strand_checkbox.setState (true);
        }
      }
    });

    
    c.gridwidth = GridBagConstraints.REMAINDER;
    gridbag.setConstraints (strand_panel, c);
    add (strand_panel);



    

    final Button select_button = new Button ("Select");

    select_button.addActionListener (new ActionListener () {
      public void actionPerformed (ActionEvent e) {
        selection.set (getSelected ());
      }
    });

    final Button view_button = new Button ("View");

    view_button.addActionListener (new ActionListener () {
      public void actionPerformed (ActionEvent e) {
        final FeaturePredicate predicate =
          new FeatureFromVectorPredicate (getSelected ());

        final FilteredEntryGroup filtered_entry_group =
          new FilteredEntryGroup (entry_group, predicate);

        String title = "All features";

        if (by_key_button.getState ()) {
          title += " with key \"" + key_selector.getSelectedItem () + "\"";
        }
        
        if (by_qualifier_button.getState ()) {
          if (qualifier_text.getText ().trim ().length () > 0) {
            title +=
              " with qualifier \"" + qualifier_selector.getSelectedItem () +
              "\" containing text \"" + qualifier_text.getText () + "\"";
          } else {
            title +=
              " with qualifier \"" +
              qualifier_selector.getSelectedItem () + "\"";
          }
        }

        if (forward_strand_checkbox.getState () &&
            !reverse_strand_checkbox.getState ()) {
          title += " on the forward strand";
        }

        if (!forward_strand_checkbox.getState () &&
            reverse_strand_checkbox.getState ()) {
          title += " on the reverse strand";
        }

        final FeatureListFrame feature_list_frame =
          new FeatureListFrame (title,
                                getSelection (),
                                goto_event_source, filtered_entry_group);

        feature_list_frame.setVisible (true);
      }
    });


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

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

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

    final Panel bottom_button_panel = new Panel (flow_layout);

    bottom_button_panel.add (select_button);
    bottom_button_panel.add (view_button);
    bottom_button_panel.add (close_button);

    gridbag.setConstraints (bottom_button_panel, c);
    add (bottom_button_panel);

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

    pack ();

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

    setVisible (true);
  }


  /**
   *  Return those features that match the current setting of the Selector.
   **/
  private FeatureVector getSelected () {
    final FeatureVector return_features = new FeatureVector ();

    final FeaturePredicate predicate;

    if (by_key_button.getState ()) {
      if (by_qualifier_button.getState ()) {
        final String search_text = qualifier_text.getText ().trim ();
        final String qualifier_name = qualifier_selector.getSelectedItem ();

        if (search_text.length () == 0) {
          predicate =
            new FeatureKeyQualifierPredicate (key_selector.getSelectedItem (),
                                              qualifier_name,
                                              true);
        } else {
          predicate =
            new FeatureKeyQualifierPredicate (key_selector.getSelectedItem (),
                                              qualifier_name,
                                              search_text,
                                              true,
                                              ignore_case.getState ());
        }
      } else {
        predicate = new FeatureKeyPredicate (key_selector.getSelectedItem ());
      }
    } else {
      // default to selecting all features
      predicate = new FeaturePredicate () {
        public boolean testPredicate (final Feature feature) {
          return true;
        }
      };
    }

    final FeatureEnumeration test_enumerator = entry_group.features ();

    while (test_enumerator.hasMoreFeatures ()) {
      final Feature this_feature = test_enumerator.nextFeature ();

      if (predicate.testPredicate (this_feature)) {
        if (this_feature.isForwardFeature ()) {
          if (forward_strand_checkbox.getState ()) {
            return_features.add (this_feature);
          }
        } else {
          if (reverse_strand_checkbox.getState ()) {
            return_features.add (this_feature);
          }          
        }
      }
    }

    return return_features;
  }

  /**
   *  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;
  }

  private Checkbox by_key_button;
  private Checkbox by_qualifier_button;
  private Checkbox by_qualifier_text_button;
  private Checkbox ignore_case;
  private Checkbox forward_strand_checkbox;
  private Checkbox reverse_strand_checkbox;
  private Panel by_key_panel;
  private Panel by_qualifier_panel;
  private Panel by_qualifier_text_panel;
  private KeyChoice key_selector;
  private QualifierChoice qualifier_selector;
  private TextField qualifier_text;

  /**
   *  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;
}
