/*
 *This library is free software; you can redistribute it and/or
 *modify it under the terms of the GNU Lesser General Public
 *License as published by the Free Software Foundation; either
 *version 2.1 of the License, or (at your option) any later version.
 *
 *This library 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
 *Lesser General Public License for more details.
 *
 *You should have received a copy of the GNU Lesser General Public
 *License along with this library; if not, write to the Free Software
 *Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

package uk.ac.man.bioinf.gui.util;
import uk.ac.man.bioinf.util.*;
import javax.swing.*;
import java.util.*;
import java.io.IOException;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.Dimension;
import java.awt.BorderLayout;
import java.net.URL;
/**
 * Provides a JFrame with a menu, a tool bar, a mainwindow  and a status bar.
 * The class also provides access to resources.
 * @author C.Miller
 * @version 1.0
 */


public class ApplicationFrame extends JFrame {
   private PackageResourceAdapter ra;
   private String appName;
   private JMenuBar mb;
   private JToolBar tb;
   private JLabel  messages;
   private HashMap menuMapping;
   private HashMap menuItemLocation;
   private HashMap menuItemMapping;
   private HashMap buttonMapping;
   private JPanel  contentPane;
   private JComponent contents;
   public ApplicationFrame() {
      this(null);
   }

   /**
    * Create an Application frame with the resources specified.
    * <ul>
    * <li> will try to get a title for the frame from the property message.appName.title
    * <li> will try to get a URL to show in the initial content pane from helpURL.appName.initialSplash
    * <li> stops window closing with a dialog box - lables this using message.appName.quit and message.appName.quitTitle
    * </ul>
    * @param resourceName looks in the package resources.locale.<resourceName> for a properties file
    */
   public ApplicationFrame(String resourceName) {
      super();
      appName          = resourceName;
      menuMapping      = new HashMap();
      menuItemMapping  = new HashMap();
      menuItemLocation = new HashMap();
      buttonMapping    = new HashMap();
      try {
         ra = new PackageResourceAdapter(resourceName);
      }
      catch(IOException e) {
         throw new RuntimeException("Couldn't find resource file 'resources.locale.' + resourceName + '.properties.");
      }
      this.setTitle(ra.getMessageString(appName + ".title"));
      initGUI();
   }

   private void initGUI() {
      final JFrame f = this;
      // window closing
      addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
               int n = JOptionPane.showConfirmDialog(f,ra.getMessageString(appName + ".quit"),
                                                     ra.getMessageString(appName + ".quitTitle"),
                                                     JOptionPane.YES_NO_OPTION);
               if(n == JOptionPane.YES_OPTION) {
                  System.err.println("Bye.");
                  System.exit(0);
               }
            }
         });
    
      setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);


      // menu bar
      mb = new JMenuBar();
      mb.setPreferredSize(new Dimension(200, 20));
      this.setJMenuBar(mb);
      // tool bar
      tb = new JToolBar();
      tb.setBorder(BorderFactory.createRaisedBevelBorder());
      
      // main content pane
      contentPane = new JPanel();
      contentPane.setLayout(new BorderLayout());
      contentPane.add(tb, BorderLayout.NORTH);

      // initial splash
      showInitialSplash();
      // the messages window at the botton

      messages   = new JLabel(ra.getMessageString(appName + ".initMessage"));
      messages.setBorder(BorderFactory.createLoweredBevelBorder()); 

      JPanel statusBar  = new JPanel();
      statusBar.setBorder(BorderFactory.createRaisedBevelBorder()); 
      statusBar.setLayout(new BorderLayout());
      statusBar.add(messages, BorderLayout.CENTER);
      contentPane.add(statusBar, BorderLayout.SOUTH);
      setContentPane(contentPane);
      pack();
      setVisible(true);
   }

   /**
    * add a menu with the specified text label.
    * @param resourceName use the text specified in ApplicationFrame.Menu.<resource name>
    */
   public JMenu addMenu(String resourceName) {
      String text;
      text=ra.getMessageString(appName + ".Menu." + resourceName);
      JMenu m = new JMenu(text);
      menuMapping.put(resourceName,m);
      mb.add(m);
      return m;
   }


   /**
    * remove a menu with the specified text label.
    * @param resourceName use the text specified in ApplicationFrame.Menu.<resource name>
    */
   public JMenu removeMenu(String resourceName) {
      JMenu m = (JMenu) menuMapping.remove(resourceName);
      if(m != null) {
         mb.remove(m);
      }
      else throw  new IllegalArgumentException("Can't find menu with resourceName " + resourceName);
      return m;
   }

   /**
    * create a menu with the specified text label.
    * @param menuName add to the specified menu
    * @param menuItemName use the text specified in ApplicationFrame.MenuItem.<resource name>
    */
   public JMenuItem addMenuItem(String menuName, String menuItemName) throws IllegalArgumentException {
      String text;
      JMenuItem mi;
      text=ra.getMessageString(appName + ".MenuItem." + menuItemName);
      JMenu m = (JMenu) menuMapping.get(menuName);
      if(m != null) {
         mi = new JMenuItem(text);
         menuItemMapping.put(menuItemName,mi);
         m.add(mi);
         menuItemLocation.put(menuItemName,menuName);
      }
      else throw  new IllegalArgumentException("Can't find menu with resourceName " + menuName);
      return mi;
   }

   /**
    * remove a menu item with the specified text label.
    * @param menuName add to the specified menu
    * @param menuItemName use the text specified in ApplicationFrame.MenuItem.<resource name>
    */
   public JMenuItem removeMenuItem(String menuItemName) throws IllegalArgumentException {
      String text;
      JMenuItem mi = (JMenuItem) menuItemMapping.remove(menuItemName);
      if(mi != null) {
         String mname = (String) menuItemLocation.remove(menuItemName);
         JMenu m = (JMenu)  menuMapping.get(mname);
         m.remove(mi);
      }
      else throw  new IllegalArgumentException("Can't find menu with resourceName " + menuItemName);
      return mi;
   }

   /**
    * create a menu with the specified text label.
    * @param menuName add to the specified menu
    * @param menuName use the text specified in ApplicationFrame.Menu.<resource name>
    */
   public JMenu addSubMenu(String menuName, String menuItemName) throws IllegalArgumentException  {
      String text;
      JMenu mi;
      text=ra.getMessageString(appName + ".Menu." + menuItemName);
      JMenu m = (JMenu) menuMapping.get(menuName);
      if(m != null) {
         mi = new JMenu(text);
         menuMapping.put(menuItemName,mi);
         m.add(mi);
      }
      else throw new IllegalArgumentException("Can't find menu with resourceName " + menuName);
      return mi;
   }

   public void setMenuEnabled(String menuName, boolean enabled) throws IllegalArgumentException  {
      JMenu m = (JMenu) menuMapping.get(menuName);
      if(m != null) {
         m.setEnabled(enabled);
      }
      else throw new IllegalArgumentException("Can't find menu with resourceName " + menuName);
   }


   public void setMenuItemEnabled(String menuItemName, boolean enabled) throws IllegalArgumentException  {
      JMenuItem m = (JMenu) menuItemMapping.get(menuItemName);
      if(m != null) {
         m.setEnabled(enabled);
      }
      else throw new IllegalArgumentException("Can't find menuitem with resourceName " + menuItemName);
   }


   /**
    * add a button with the specified text label.
    * @param labelName use the text specified in ApplicationFrame.Button.label<resource name>
    */
   public JButton addButton(String labelName) throws IllegalArgumentException  {
      String text;
      text=ra.getMessageString(appName + ".Button." + labelName);
      JButton b = new JButton(text);
      buttonMapping.put(labelName,b);
      tb.add(b);
      tb.invalidate();
      return b;
   }

   /**
    * add a button with the specified text label. and icon
    * @param labelName use the text specified in message.<app_name>.Button.label<resource name>
    * @param iconName  use the image specified in image.<app_name>.Button.label<resource name>
    */
   public JButton addButton(String labelName, String iconName) throws IllegalArgumentException  {
      String text;
      ImageIcon ii;
      text=ra.getMessageString(appName + ".Button." + labelName);
      ii=new ImageIcon(ra.getImageURL(appName + ".Button." + iconName));
      JButton b = new JButton(text,ii);
      buttonMapping.put(labelName,b);
      tb.add(b);
      tb.invalidate();
      return b;
   }

   /**
    * add a button with the specified text label, icon and tooltip.
    * @param labelName use the text specified in message.<app_name>.Button.label<resource name>
    * @param iconName  use the image specified in image.<app_name>.Button.label<resource name>
    * @param tooltipName use the text specified in tooltip.<app_name>.Button.label<resource name>
    */
   public JButton addButton(String labelName, String iconName, String tooltipName) throws IllegalArgumentException  {
      String text;
      ImageIcon ii;
      text=ra.getMessageString(appName + ".Button." + labelName);
      ii=new ImageIcon(ra.getImageURL(appName + ".Button." + iconName));
      JButton b = new JButton(text,ii);
      b.setToolTipText(ra.getToolTip(appName + ".Button." + iconName));
      buttonMapping.put(labelName,b);
      tb.add(b);
      tb.invalidate();
      return b;
   }


   /**
    * add a button with the specified text label.
    * @param labelName use the text specified in ApplicationFrame.Button.label<resource name>
    */
   public JToggleButton addToggleButton(String labelName) throws IllegalArgumentException  {
      String text;
      text=ra.getMessageString(appName + ".Button." + labelName);
      JToggleButton b = new JToggleButton(text);
      buttonMapping.put(labelName,b);
      tb.add(b);
      tb.invalidate();
      return b;
   }

   /**
    * add a button with the specified text label. and icon
    * @param labelName use the text specified in message.<app_name>.Button.label<resource name>
    * @param iconName  use the image specified in image.<app_name>.Button.label<resource name>
    */
   public JToggleButton addToggleButton(String labelName, String iconName) throws IllegalArgumentException  {
      String text;
      ImageIcon ii;
      text=ra.getMessageString(appName + ".Button." + labelName);
      ii=new ImageIcon(ra.getImageURL(appName + ".Button." + iconName));
      JToggleButton b = new JToggleButton(text,ii);
      buttonMapping.put(labelName,b);
      tb.add(b);
      tb.invalidate();
      return b;
   }

   /**
    * add a button with the specified text label, icon and tooltip.
    * @param labelName use the text specified in message.<app_name>.Button.label<resource name>
    * @param iconName  use the image specified in image.<app_name>.Button.label<resource name>
    * @param tooltipName use the text specified in tooltip.<app_name>.Button.label<resource name>
    */
   public JToggleButton addToggleButton(String labelName, String iconName, String tooltipName) throws IllegalArgumentException  {
      String text;
      ImageIcon ii;
      text=ra.getMessageString(appName + ".Button." + labelName);
      ii=new ImageIcon(ra.getImageURL(appName + ".Button." + iconName));
      JToggleButton b = new JToggleButton(text,ii);
      b.setToolTipText(ra.getToolTip(appName + ".Button." + iconName));
      buttonMapping.put(labelName,b);
      tb.add(b);
      tb.invalidate();
      return b;
   }


   /**
    * remove a menu with the specified text label.
    * @param resourceName use the text specified in ApplicationFrame.Menu.<resource name>
    */
   public JButton removeButton(String labelName) throws IllegalArgumentException  {
      JButton b = (JButton) buttonMapping.remove(labelName);
      if(b != null) {
         tb.remove(b);
      }
      else throw new IllegalArgumentException("Can't find menu with resourceName " + labelName);
      return b;
   }

   public void showInitialSplash() {
      
      // set up the initial splash to show in the main window
      URL page = ra.getHelpURL(appName + ".initialSplash");
      JEditorPane initialSplash = new JEditorPane();
      initialSplash.setEditable(false);
      try {
         initialSplash.setPage(page);
         initialSplash.setPreferredSize(new Dimension(200,100));
      } catch (IOException e) {
         System.err.println("Couldn't find initial splash page.\n" + e.getMessage());
      }
      setContents(initialSplash);
   }

   public PackageResourceAdapter getResourceAdapter() {
      return ra;
   }

   public void setContents(JComponent c) {
     if(contents != null) {
         contentPane.remove(contents);
      }
      contentPane.add(c, BorderLayout.CENTER);
      contents = c;
      contentPane.revalidate();
      contentPane.repaint();
   }

   public JComponent getContents() {
      return contents;
   }

   public void showMessage(String message) {
      messages.setText(message);
   }
}
