/* FeaturePopup.java
 *
 * created: Wed Oct 21 1998
 *
 * 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: /nfs/disk222/yeastpub/Repository/powmap/diana/components/FeaturePopup.java,v 1.60 2000/09/18 09:57:46 kmr Exp $
 */

package diana.components;

import diana.*;

import uk.ac.sanger.pathogens.StringVector;

import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;

/**
 *  FeaturePopup class
 *
 *  @author Kim Rutherford
 *  @version $Id: FeaturePopup.java,v 1.60 2000/09/18 09:57:46 kmr Exp $
 *
 **/

public class FeaturePopup extends PopupMenu {
  /**
   *  Create a new FeaturePopup object.
   *  @param owner The component where this popup was popped up from.
   *  @param selection The selection to use for this popup.
   **/
  public FeaturePopup (final DisplayComponent owner,
                       final EntryGroup entry_group,
                       final Selection selection,
                       final GotoEventSource goto_event_source) {
    super (getMenuName (owner));

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

    selection_features = selection.getSelectedFeatures ();
    selection_segments = selection.getSelectedSegments ();

    makeSubMenus ();

    addGenericItems ();

    if (owner instanceof FeatureDisplay) {
      feature_display = (FeatureDisplay) owner;
      addFeatureDisplayItems ();
    } else {
      // must be a FeatureList
      feature_list = (FeatureList) owner;
      addFeatureListItems ();
    }

    maybeAdd (raise_feature_item);
    maybeAdd (lower_feature_item);
    maybeAdd (smallest_to_front_item);
    maybeAdd (zoom_to_selection_item);
    maybeAdd (select_visible_range);
    maybeAdd (select_visible_features);
    maybeAdd (score_cutoffs_item);
    maybeAdd (save_feature_list_item);
    if (getItemCount () > 0) {
      addSeparator ();
    }
    maybeAdd (entry_group_menu_item);
    maybeAdd (select_menu_item);
    maybeAdd (goto_menu_item);
    maybeAdd (view_menu_item);
    maybeAdd (edit_menu_item);
    maybeAdd (add_menu_item);
    maybeAdd (write_menu_item);
    maybeAdd (run_menu_item);
    addSeparator ();
    maybeAdd (show_labels_item);
    maybeAdd (one_line_per_entry_item);
    maybeAdd (show_forward_frame_lines_item);
    maybeAdd (show_reverse_frame_lines_item);
    maybeAdd (show_start_codons_item);
    maybeAdd (show_stop_codons_item);
    maybeAdd (frame_features_item);
    maybeAdd (base_colours_item);
    maybeAdd (correlation_scores_item);
    maybeAdd (show_genes_item);
    maybeAdd (show_products_item);
    addSeparator ();
    maybeAdd (broadcast_item);
  }

  /**
   *  Rename the name String to use for this Menu.
   **/
  private static String getMenuName (final DisplayComponent owner) {
    if (owner instanceof FeatureDisplay) {
      return "Feature Viewer Menu";
    } else {
      return "Feature List Menu";
    }
  }

  /**
   *  Add an item only if it isn't null.
   **/
  private void maybeAdd (MenuItem item) {
    if (item != null) {
      add (item);
    }
  }

  /**
   *  Create those menu items that are relevant to all components.
   **/
  private void addGenericItems () {
    if (selection_features.size () > 0 || selection_segments.size () > 0) {

    }
  }

  /**
   *  Create the Edit, Add and View sub menus.
   **/
  public void makeSubMenus () {
    final Frame frame = owner.getParentFrame ();

    entry_group_menu_item = new EntryGroupMenu (frame, getEntryGroup ());

    select_menu_item = new SelectMenu (frame,
                                       selection,
                                       getGotoEventSource (),
                                       getEntryGroup ());

    view_menu_item = new ViewMenu (frame,
                                   selection,
                                   getGotoEventSource (),
                                   getEntryGroup ());

    goto_menu_item = new GotoMenu (frame,
                                   selection,
                                   getGotoEventSource (),
                                   getEntryGroup ());

    if (Options.isStandAlone ()) {
      edit_menu_item = new EditMenu (frame,
                                     selection,
                                     getGotoEventSource (),
                                     getEntryGroup ());
      if (entry_group instanceof SimpleEntryGroup) {
        add_menu_item = new AddMenu (frame,
                                     selection, getEntryGroup ());
      }

      write_menu_item = new WriteMenu (frame,
                                       selection,
                                       getEntryGroup ());
      if (Options.isUnixHost ()) {
        run_menu_item = new RunMenu (frame, selection);
      }
    }
  }

  /**
   *  Create those menu items that are relevant only to FeatureDisplay objects.
   **/
  private void addFeatureDisplayItems () {
    show_start_codons_item = new CheckboxMenuItem ("Start Codons");
    show_start_codons_item.setState (feature_display.getShowStartCodons ());
    show_start_codons_item.addItemListener (new ItemListener () {
      public void itemStateChanged (ItemEvent event) {
        feature_display.setShowStartCodons (show_start_codons_item.getState ());
      }
    });

    show_stop_codons_item = new CheckboxMenuItem ("Stop Codons");
    show_stop_codons_item.setState (feature_display.getShowStopCodons ());
    show_stop_codons_item.addItemListener (new ItemListener () {
      public void itemStateChanged (ItemEvent event) {
        feature_display.setShowStopCodons (show_stop_codons_item.getState ());
      }
    });

    show_labels_item = new CheckboxMenuItem ("Feature Labels");
    show_labels_item.setState (feature_display.getShowLabels ());
    show_labels_item.addItemListener (new ItemListener () {
      public void itemStateChanged (ItemEvent e) {
        feature_display.setShowLabels (show_labels_item.getState ());
      }
    });

    one_line_per_entry_item = new CheckboxMenuItem ("One Line Per Entry");
    one_line_per_entry_item.setState (feature_display.getOneLinePerEntryFlag ());
    one_line_per_entry_item.addItemListener (new ItemListener () {
      public void itemStateChanged (ItemEvent e) {
        final boolean new_state = one_line_per_entry_item.getState ();
        if (new_state && getEntryGroup ().size () > 8) {
          feature_display.setShowLabels (false);
        }
        feature_display.setOneLinePerEntry (new_state);
      }
    });

    show_forward_frame_lines_item =
      new CheckboxMenuItem ("Forward Frame Lines");
    show_forward_frame_lines_item.setState (feature_display.getShowForwardFrameLines ());
    show_forward_frame_lines_item.addItemListener (new ItemListener () {
      public void itemStateChanged (ItemEvent e) {
        feature_display.setShowForwardFrameLines (show_forward_frame_lines_item.getState ());
      }
    });

    show_reverse_frame_lines_item =
      new CheckboxMenuItem ("Reverse Frame Lines");
    show_reverse_frame_lines_item.setState (feature_display.getShowReverseFrameLines ());
    show_reverse_frame_lines_item.addItemListener (new ItemListener () {
      public void itemStateChanged (ItemEvent e) {
        feature_display.setShowReverseFrameLines (show_reverse_frame_lines_item.getState ());
      }
    });

    frame_features_item = new CheckboxMenuItem ("All Features On Frame Lines");
    frame_features_item.setState (feature_display.getFrameFeaturesFlag ());
    frame_features_item.addItemListener (new ItemListener () {
      public void itemStateChanged (ItemEvent e) {
        feature_display.setFrameFeaturesFlag (frame_features_item.getState ());
      }
    });

    base_colours_item = new CheckboxMenuItem ("Colourise Bases");
    base_colours_item.setState (feature_display.getShowBaseColours ());
    base_colours_item.addItemListener (new ItemListener () {
      public void itemStateChanged (ItemEvent e) {
        feature_display.setShowBaseColours (base_colours_item.getState ());
      }
    });

    smallest_to_front_item =
      new MenuItem ("Smallest Features In Front");
    smallest_to_front_item.addActionListener (new ActionListener () {
      public void actionPerformed (ActionEvent e) {
        // clear the selection because selected features will always be on
        // top - which is not usually what is wanted
        selection.clear ();
        feature_display.smallestToFront ();
      }
    });

    score_cutoffs_item =
      new MenuItem ("Set Score Cutoffs ...");
    score_cutoffs_item.addActionListener (new ActionListener () {
      public void actionPerformed (ActionEvent e) {
        final ScoreChangeListener minimum_listener =
          new ScoreChangeListener () {
            public void scoreChanged (final ScoreChangeEvent event) {
              feature_display.setMinimumScore (event.getValue ());
            }
          };

        final ScoreChangeListener maximum_listener =
          new ScoreChangeListener () {
            public void scoreChanged (final ScoreChangeEvent event) {
              feature_display.setMaximumScore (event.getValue ());
            }
          };

        final ScoreChanger score_changer =
          new ScoreChanger ("Score Cutoffs",
                            minimum_listener, maximum_listener);

        score_changer.setVisible (true);
      }
    });

    if (selection_features.size () > 0 || selection_segments.size () > 0) {
      raise_feature_item = new MenuItem ("Raise Selected Features");
      raise_feature_item.addActionListener (new ActionListener () {
        public void actionPerformed (ActionEvent event) {
          raiseSelection ();
        }
      });

      lower_feature_item = new MenuItem ("Lower Selected Features");
      lower_feature_item.addActionListener (new ActionListener () {
        public void actionPerformed (ActionEvent event) {
          lowerSelection ();
        }
      });
    }

    if (!selection.isEmpty ()) {
      zoom_to_selection_item = new MenuItem ("Zoom to Selection");
      zoom_to_selection_item.addActionListener (new ActionListener () {
        public void actionPerformed (ActionEvent event) {
          zoomToSelection ();
        }
      });
    }


    select_visible_range =
      new MenuItem ("Select Visible Range");
    select_visible_range.addActionListener (new ActionListener () {
      public void actionPerformed (ActionEvent e) {
        selection.setMarkerRange (feature_display.getVisibleMarkerRange ());
      }
    });

    select_visible_features =
      new MenuItem ("Select Visible Features");
    select_visible_features.addActionListener (new ActionListener () {
      public void actionPerformed (ActionEvent e) {
        selection.set (feature_display.getCurrentVisibleFeatures ());
      }
    });
  }

  /**
   *  Create those menu items that are relevant only to FeatureList objects.
   **/
  private void addFeatureListItems () {
    if (Options.getOptions ().isStandAlone ()) {
      save_feature_list_item = new MenuItem ("Save List To File ...");
      save_feature_list_item.addActionListener (new ActionListener () {
        public void actionPerformed (ActionEvent e) {
          saveFeatureList ();
        }
      });
    }

    correlation_scores_item = new CheckboxMenuItem ("Show Correlation Scores");
    correlation_scores_item.setState (feature_list.getCorrelationScores ());
    correlation_scores_item.addItemListener (new ItemListener () {
      public void itemStateChanged(ItemEvent e) {
        feature_list.setCorrelationScores (correlation_scores_item.getState ());
      }
    });

    show_genes_item = new CheckboxMenuItem ("Show Gene Names");
    show_genes_item.setState (feature_list.getShowGenes ());
    show_genes_item.addItemListener (new ItemListener () {
      public void itemStateChanged(ItemEvent e) {
        feature_list.setShowGenes (show_genes_item.getState ());
      }
    });

    show_products_item = new CheckboxMenuItem ("Show Products");
    show_products_item.setState (feature_list.getShowProducts ());
    show_products_item.addItemListener (new ItemListener () {
      public void itemStateChanged(ItemEvent e) {
        feature_list.setShowProducts (show_products_item.getState ());
      }
    });
  }

  /**
   *  Save the text of the feature list to a file.
   **/
  private void saveFeatureList () {
    final Frame frame = owner.getParentFrame ();

    final FileDialog file_dialog =
      new FileDialog (frame, "Choose save file ...", FileDialog.SAVE);

    file_dialog.setVisible (true);

    if (file_dialog.getFile () != null) {
      final String file_name = file_dialog.getDirectory () +
        java.io.File.separator + file_dialog.getFile ();

      final File write_file = new File (file_name);

      if (write_file.exists ()) {
        final YesNoDialog yes_no_dialog =
          new YesNoDialog (frame,
                           "this file exists: " + write_file +
                           " overwrite it?");
        if (yes_no_dialog.getResult ()) {
          // yes - continue
        } else {
          // no
          return;
        }
      }

      try {
        final PrintWriter writer =
          new PrintWriter (new FileWriter (write_file));

        final StringVector list_strings = feature_list.getListStrings ();

        for (int i = 0 ; i < list_strings.size () ; ++i) {
          writer.println (list_strings.elementAt (i));
        }

        writer.close ();
      } catch (IOException e) {
        new MessageDialog (frame, "error while writing: " + e.getMessage ());
      }
    }
  }

  /**
   *  Raise the selected features.  (FeatureDisplay only.)
   **/
  private void raiseSelection () {
    final FeatureVector features_to_raise = selection.getAllFeatures ();

    for (int i = 0 ; i < features_to_raise.size () ; ++i) {
      final Feature selection_feature = features_to_raise.elementAt (i);

      feature_display.raiseFeature (selection_feature);
    }
  }

  /**
   *  Lower the selected features.  (FeatureDisplay only.)
   **/
  private void lowerSelection () {
    final FeatureVector features_to_lower = selection.getAllFeatures ();

    for (int i = 0 ; i < features_to_lower.size () ; ++i) {
      final Feature selection_feature = features_to_lower.elementAt (i);

      feature_display.lowerFeature (selection_feature);
    }
  }

  /**
   *  Zoom the FeatureDisplay to the selection.  (FeatureDisplay only.)
   **/
  private void zoomToSelection () {
    if (getEntryGroup ().getSequenceLength () < 1000) {
      // why bother in this case?
      return;
    }

    int first_base;
    int last_base;

    final FeatureSegmentVector segments = selection.getSelectedSegments ();

    if (segments.size () == 1) {
      // special case - zoom to the feature instead
      first_base = segments.elementAt (0).getFeature ().getRawFirstBase ();
      last_base  = segments.elementAt (0).getFeature ().getRawLastBase ();
    } else {
      first_base = selection.getLowestBaseOfSelection ().getRawPosition ();
      last_base  = selection.getHighestBaseOfSelection ().getRawPosition ();
    }

    if (first_base < 250) {
      first_base = 250;
    } else {
      first_base -= 250;
    }

    last_base += 250;

    feature_display.setFirstAndLastBase (first_base, last_base);
  }

  /**
   *  Return the EntryGroup object that this FeatureDisplay is displaying.
   **/
  private EntryGroup getEntryGroup () {
    return entry_group;
  }

  /**
   *  Return an object that implements the GotoEventSource interface and is
   *  for the sequence that this DisplayComponent is displaying.
   **/
  public GotoEventSource getGotoEventSource () {
    return goto_event_source;
  }

  /**
   *  The reference of the EntryGroup object that was passed to the
   *  constructor.
   **/
  private EntryGroup entry_group;

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

  /**
   *  This is a reference to the GotoEventSource object that was passed to the
   *  constructor.
   **/
  private GotoEventSource goto_event_source;

  /**
   *  The reference of the object that created this popup.
   **/
  private DisplayComponent owner;

  /**
   *  If the parent component of this popup is a FeatureDisplay then this will
   *  contain it's reference.
   **/
  private FeatureDisplay feature_display = null;

  /**
   *  If the parent component of this popup is a FeatureList then this will
   *  contain it's reference.
   **/
  private FeatureList feature_list = null;

  /**
   *  Set by the constructor to be the (possibly) empty vector of selected
   *  features.
   **/
  private FeatureVector selection_features;

  /**
   *  Set by the constructor to be the (possibly) empty vector of selected
   *  features.
   **/
  private FeatureSegmentVector selection_segments;

  private CheckboxMenuItem show_labels_item = null;
  private CheckboxMenuItem one_line_per_entry_item = null;
  private CheckboxMenuItem show_forward_frame_lines_item = null;
  private CheckboxMenuItem show_reverse_frame_lines_item = null;
  private CheckboxMenuItem show_start_codons_item = null;
  private CheckboxMenuItem show_stop_codons_item = null;
  private CheckboxMenuItem frame_features_item = null;
  private CheckboxMenuItem base_colours_item = null;
  private CheckboxMenuItem correlation_scores_item = null;
  private CheckboxMenuItem show_genes_item = null;
  private CheckboxMenuItem show_products_item = null;
  private MenuItem entry_group_menu_item = null;
  private MenuItem select_menu_item = null;
  private MenuItem add_menu_item = null;
  private MenuItem view_menu_item = null;
  private MenuItem edit_menu_item = null;
  private MenuItem goto_menu_item = null;
  private MenuItem write_menu_item = null;
  private MenuItem run_menu_item = null;
  private MenuItem broadcast_item = null;
  private MenuItem raise_feature_item = null;
  private MenuItem lower_feature_item = null;
  private MenuItem smallest_to_front_item = null;
  private MenuItem zoom_to_selection_item = null;
  private MenuItem score_cutoffs_item = null;
  private MenuItem select_visible_range = null;
  private MenuItem save_feature_list_item = null;
  private MenuItem select_visible_features = null;
}
