/* Splash.java
 *
 * created: Wed May 10 2000
 *
 * This file is part of Artemis
 *
 * Copyright (C) 2000,2002  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/pathsoft/repository/powmap/diana/components/Splash.java,v 1.30 2003/02/21 13:51:24 kmr Exp $
 */

package diana.components;

import AppGlobal;

import diana.*;

import uk.ac.sanger.pathogens.*;

import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;

/**
 *  Base class that creates a generic "Splash Screen"
 *
 *  @author Kim Rutherford <kmr@sanger.ac.uk>
 *  @version $Id: Splash.java,v 1.30 2003/02/21 13:51:24 kmr Exp $
 **/

abstract public class Splash extends Frame {
  /**
   *  Create a new Frame for a Splash screen.
   *  @param program_name The full name of the program.
   *  @param program_title The name to use in the title.
   *  @param program_version The version string.
   **/
  public Splash (final String program_name,
                 final String program_title,
                 final String program_version) {
    super (program_title + " " + program_version);

    this.program_name    = program_name;
    this.program_version = program_version;

    addWindowListener (new WindowAdapter () {
      public void windowClosing (WindowEvent event) {
        exit ();
      }
    });

    setLayout(new BorderLayout());

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

    setFont (font);

    setMenuBar (menu_bar);

    menu_bar.setFont (font);

    makeAllMenus ();

    helix_canvas = makeHelixCanvas ();

    add (helix_canvas, "Center");

    add (status_line, "South");

    helix_canvas.setFont (font);

    Toolkit toolkit = Toolkit.getDefaultToolkit ();

    final URL icon_url = Splash.class.getResource ("/icon.gif");

    if (icon_url != null) {
      final Image icon_image = toolkit.getImage (icon_url);

      MediaTracker tracker = new MediaTracker (this);

      tracker.addImage (icon_image, 0);

      try {
        tracker.waitForAll ();
        setIconImage (icon_image);
      } catch (InterruptedException e) {
        // ignore and continue
      }
    }

    pack ();

    final int x = 460;
    final int y = 250;

    setSize (x, y);

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

  /**
   *  This method will fill the background with white.
   **/
  public void paint (final Graphics g) {
    g.setColor (Color.white);
    g.fillRect (0, 0, getSize ().width, getSize ().height);
  }

  /**
   *  Return a Canvas object that will display a helix and a short copyright
   *  notice.
   **/
  private Canvas makeHelixCanvas () {
    return new Canvas () {
      public void update(Graphics g) {
        paint(g);
      }

      // return the program name and the program mode in one String
      private String getNameString () {
        if (Options.getOptions ().isEukaryoticMode ()) {
          return program_name + "  [Eukaryotic mode]";
        } else {
          return program_name + "  [Prokaryotic mode]";
        }
      }

      /**
       *  Draws the splash screen text.
       **/
      public int textPaint (final Graphics g) {
        final Font font = Options.getOptions ().getFont ();

        g.setFont (font);

        FontMetrics fm = this.getFontMetrics (font);

        final int font_height = fm.getHeight () + 3;

        g.setColor (Color.black);

        final int left_margin = 5;

        g.drawString (program_name,
                      helix_width + left_margin, font_height);
        g.drawString (program_version,
                      helix_width + left_margin, font_height * 2);
        if (Options.getOptions ().isEukaryoticMode ()) {
          g.drawString ("[Eukaryotic mode]",
                        helix_width + left_margin, font_height * 3);
        } else {
          g.drawString ("[Prokaryotic mode]",
                        helix_width + left_margin, font_height * 3);
        }
        g.drawString ("Copyright 1998 - 2003",
                      helix_width + left_margin, font_height * 9 / 2);
        g.drawString ("Genome Research Limited",
                      helix_width + left_margin, font_height * 11 / 2);

        return font_height;
      }

      public void paint (final Graphics g) {
        final boolean simple_splash_screen =
          Options.getOptions ().getPropertyTruthValue ("simple_splash_screen");

        g.setColor (Color.white);

        g.fillRect (0, 0, this.getSize ().width, this.getSize ().height);

        if (simple_splash_screen) {
          // java SIGILL bug work-around
          textPaint (g);
          return;
        }

        if (helix == null) {
          Toolkit toolkit = Toolkit.getDefaultToolkit ();

          final URL helix_url = Splash.class.getResource ("/diana/helix.gif");

          helix = toolkit.getImage (helix_url);

          final URL sanger_url =
            Splash.class.getResource ("/diana/sanger-centre.gif");
          sanger = toolkit.getImage (sanger_url);

          tracker = new MediaTracker (this);

          tracker.addImage (helix, 0);
          tracker.addImage (sanger, 1);

          try {
            tracker.waitForAll ();
            helix_height = helix.getHeight (this);
            helix_width = helix.getWidth (this);
            sanger_height = sanger.getHeight (this);
          } catch (InterruptedException e) {
            return;
          }
        }

        for (int i = 0 ; i * helix_height <= this.getSize ().height; ++i) {
          g.drawImage (helix,
                       0,
                       i * helix_height, this);
        }

        final int font_height = textPaint (g);

        int sanger_position = this.getSize ().height - sanger_height;

        if (sanger_position > font_height * 5.5) {
          g.drawImage (sanger,
                       helix_width + 5,
                       sanger_position, this);
        }
      }

      MediaTracker tracker = null;

      /**
       *  The image of the Sanger DNA logo.  This is set in paint().
       **/
      private Image helix = null;

      /**
       *  The image of the Sanger logo.  This is set in paint().
       **/
      private Image sanger = null;

      /**
       *  The height of the Sanger logo.  This is set in paint().
       **/
      private int sanger_height;

      /**
       *  The height of the Sanger DNA logo.  This is set in paint().
       **/
      private int helix_height;

      /**
       *  The width of the Sanger DNA logo.  This is set in paint().
       **/
      private int helix_width;
    };
  }

  /**
   *  Return the reference of the Label used as a status line.
   **/
  public Label getStatusLabel () {
    return status_line;
  }

  /**
   *  Return the reference of the MenuBar of this component.
   **/
  public MenuBar getMenuBar () {
    return menu_bar;
  }

  /**
   *  The possible sources for reading Entry objects.
   **/
  public EntrySourceVector getEntrySources (final Frame frame) {
    return AppGlobal.getEntrySources (frame, stream_progress_listener);
  }

  /**
   *  Return an InputStreamProgressListener which updates the error label with
   *  the current number of chars read while reading
   **/
  public InputStreamProgressListener getInputStreamProgressListener () {
    return stream_progress_listener;
  }

  /**
   *  Force the options files to be re-read and the EntryEdit components to be
   *  redisplayed.
   **/
  private void resetOptions () {
    Options.getOptions ().reset ();
  }

  /**
   *  Make all the menus and menu items for the main window.  Also sets up
   *  suitable ActionListener objects for each item.
   */
  private void makeAllMenus () {
    getMenuBar ().add (file_menu);
    getMenuBar ().add (options_menu);

    ActionListener menu_listener = null;

    menu_listener = new ActionListener () {
      public void actionPerformed (ActionEvent event) {
        resetOptions ();
      }
    };
    makeMenuItem (options_menu, "Re-read Options", menu_listener);

    final CheckboxMenuItem enable_direct_edit_item =
      new CheckboxMenuItem ("Enable Direct Editing");
    enable_direct_edit_item.setState (Options.getOptions ().canDirectEdit ());
    enable_direct_edit_item.addItemListener (new ItemListener () {
      public void itemStateChanged(ItemEvent event) {
        final boolean item_state = enable_direct_edit_item.getState ();
        Options.getOptions ().setDirectEdit (item_state);
      }
    });
    options_menu.add (enable_direct_edit_item);

    final CheckboxMenuItem enable_euk_mode_item =
      new CheckboxMenuItem ("Eukaryotic Mode");
    enable_euk_mode_item.setState (Options.getOptions ().isEukaryoticMode ());
    enable_euk_mode_item.addItemListener (new ItemListener () {
      public void itemStateChanged(ItemEvent event) {
        final boolean item_state = enable_euk_mode_item.getState ();
        Options.getOptions ().setEukaryoticMode (item_state);

        helix_canvas.repaint ();
      }
    });
    options_menu.add (enable_euk_mode_item);

    final CheckboxMenuItem highlight_active_entry_item =
      new CheckboxMenuItem ("Highlight Active Entry");
    final boolean highlight_active_entry_state =
      Options.getOptions ().highlightActiveEntryFlag ();
    highlight_active_entry_item.setState (highlight_active_entry_state);
    highlight_active_entry_item.addItemListener (new ItemListener () {
      public void itemStateChanged(ItemEvent event) {
        final boolean item_state = highlight_active_entry_item.getState ();
        Options.getOptions ().setHighlightActiveEntryFlag (item_state);
      }
    });
    options_menu.add (highlight_active_entry_item);

    if (Options.getOptions ().getPropertyTruthValue ("sanger_options") &&
        Options.getOptions ().getProperty ("black_belt_mode") != null) {
      final CheckboxMenuItem black_belt_mode_item =
        new CheckboxMenuItem ("Black Belt Mode");
      final boolean state =
        Options.getOptions ().isBlackBeltMode ();
      black_belt_mode_item.setState (state);
      black_belt_mode_item.addItemListener (new ItemListener () {
        public void itemStateChanged(ItemEvent event) {
          final boolean item_state = black_belt_mode_item.getState ();
          if (item_state) {
            Options.getOptions ().put ("black_belt_mode", "true");
          } else {
            Options.getOptions ().put ("black_belt_mode", "false");
          }
        }
      });
      options_menu.add (black_belt_mode_item);
    }

    if (Options.isUnixHost ()) {
      options_menu.addSeparator ();

      menu_listener = new ActionListener () {
        public void actionPerformed (ActionEvent event) {
          logger.setVisible (true);
        }
      };
      makeMenuItem (options_menu, "Show Log Window", menu_listener);

      menu_listener = new ActionListener () {
        public void actionPerformed (ActionEvent event) {
          logger.setVisible (false);
        }
      };
      makeMenuItem (options_menu, "Hide Log Window", menu_listener);
    }
  }

  /**
   *  Make a new menu item in the given menu, with its label given the
   *  String and add the given ActionListener to it.
   */
  protected static void makeMenuItem (Menu menu, String name,
                                    ActionListener listener) {
    MenuItem new_item = new MenuItem (name);
    menu.add (new_item);
    new_item.addActionListener (listener);
  }

  /**
   *  Return a Logger for warnings/errors/messages.
   **/
  public static Logger getLogger () {
    return logger;
  }

  /**
   *  Return the Canvas that the Splash screen is drawing on.
   **/
  public Canvas getCanvas () {
    return helix_canvas;
  }

  /**
   *  Do any necessary cleanup then exit.
   **/
  abstract protected void exit ();

  /**
   *  A label for status and error messages.
   **/
  final private Label status_line = new Label ("");

  /**
   *  The program name that was passed to the constructor.
   **/
  private String program_name;

  /**
   *  The program version that was passed to the constructor.
   **/
  private String program_version;

  /**
   *  The Canvas to draw the main splash screen into
   **/
  private Canvas helix_canvas;

  /**
   *  Menu bar for the main window.
   **/
  final private MenuBar menu_bar = new MenuBar ();

  final Menu file_menu = new Menu ("File");

  final Menu options_menu = new Menu ("Options");

  /**
   *  The Logger that is returned by getLogger().
   **/
  private final static LogViewer logger = new LogViewer ();

  /**
   *  An InputStreamProgressListener used to update the error label with the
   *  current number of chars read.
   **/
  private final InputStreamProgressListener stream_progress_listener =
    new InputStreamProgressListener () {
      public void progressMade (final InputStreamProgressEvent event) {
        final int char_count = event.getCharCount ();
        if (char_count == -1) {
          getStatusLabel ().setText ("");
        } else {
          getStatusLabel ().setText ("chars read so far: " + char_count);
        }
      }
    };
}
