// $Id: PmiiMenu.java,v 1.19 2004/06/14 20:44:55 m31 Exp $
//
// This file is part of the program suite "Principia Mathematica II"
// which is a working prototype for the main project:
// "Hilbert II" - http://www.qedeq.org
//
// Copyright 2001-2004  Michael Meyling <mime@qedeq.org>.
//
// "Principia Mathematica II" 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.

package com.meyling.principia.gui;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Observable;
import java.util.Observer;

import javax.swing.AbstractAction;
import javax.swing.ButtonGroup;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

import com.meyling.principia.PmiiFacade;
import com.meyling.principia.gui.jtabbedpane.PmiiTabbedPaneView;
import com.meyling.principia.help.HtmlInfo;
import com.meyling.principia.help.ModuleDescription;
import com.meyling.principia.io.DataDictionary;
import com.meyling.principia.log.Trace;


/**
 * Pmii menu.
 *
 * @version $Revision: 1.19 $
 * @author  Michael Meyling
 */
public class PmiiMenu extends JMenuBar implements Observer {

    // Possible Look & Feels
    private final static String mac      =
            "com.sun.java.swing.plaf.mac.MacLookAndFeel";
    private final static String metal    =
            "javax.swing.plaf.metal.MetalLookAndFeel";
    private final static String motif    =
            "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
    private final static String windows  =
            "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
    private final static String gtk  =
            "com.sun.java.swing.plaf.gtk.GTKLookAndFeel";

    // The current Look & Feel
    private String currentLookAndFeel = metal;

    private ButtonGroup lookMenuGroup = new ButtonGroup();

    private final PmiiController ctrl;
    
    private final JFrame mainFrame;
    
    private final PmiiTabbedPaneView tabbed;
    

    public PmiiMenu(final PmiiController ctrl, final JFrame mainFrame, 
            final PmiiTabbedPaneView tabbed) {
        super();
        this.ctrl = ctrl;
        this.mainFrame = mainFrame;
        this.tabbed = tabbed;
        this.add(createFileMenu());
        this.add(createGenerateMenu());
        this.add(createViewMenu());
        this.add(createLafMenu());
        this.add(createSpecial());
        this.add(createSettingsMenu());
        this.add(createHelpMenu());
    }

    private JMenu createFileMenu() {
        final JMenu fileMenu = new JMenu(getString("FileMenu.Name"));
        fileMenu.setMnemonic(getMnemonic("FileMenu.MnemonicKey"));
        fileMenu.getAccessibleContext().setAccessibleDescription(
            getString("FileMenu.ShortDescription"));

        {
            final JMenuItem newModule = new JMenuItem(getString("CreateNewModule.Name"));
            newModule.setMnemonic(getMnemonic("CreateNewModule.MnemonicKey"));
            newModule.getAccessibleContext().setAccessibleDescription(
                getString("CreateNewModule.ShortDescription"));
            newModule.addActionListener(this.ctrl.getCreateNewModuleAction());
            fileMenu.add(newModule);
        }

        {
            final JMenuItem saveModule = new JMenuItem(getString("SaveModule.Name"));
            saveModule.setMnemonic(getMnemonic("SaveModule.MnemonicKey"));
            saveModule.getAccessibleContext().setAccessibleDescription(
                getString("SaveModule.ShortDescription"));
            saveModule.addActionListener(this.ctrl.getSaveModuleAction());
            fileMenu.add(saveModule);
        }

        fileMenu.addSeparator();

        {
            final JMenuItem addNode = new JMenuItem(getString("LoadModule.Name"));
            addNode.setMnemonic(getMnemonic("LoadModule.MnemonicKey"));
            addNode.getAccessibleContext().setAccessibleDescription(
                getString("LoadModule.ShortDescription"));
            addNode.addActionListener(this.ctrl.getAddAction());
            fileMenu.add(addNode);
        }

        {
            final JMenuItem addFileNode = new JMenuItem(getString("LoadFileModule.Name"));
            addFileNode.setMnemonic(getMnemonic("LoadFileModule.MnemonicKey"));
            addFileNode.getAccessibleContext().setAccessibleDescription(
                getString("LoadFileModule.ShortDescription"));
            addFileNode.addActionListener(this.ctrl.getAddFileAction());
            fileMenu.add(addFileNode);
        }

        {
            final JMenuItem addAllNodesFromQedeq
                = new JMenuItem(getString("LoadAllProjectModules.Name"));
            addAllNodesFromQedeq.setMnemonic(getMnemonic("LoadAllProjectModules.MnemonicKey"));
            addAllNodesFromQedeq.getAccessibleContext().setAccessibleDescription(
                getString("LoadAllProjectModules.ShortDescription"));
            addAllNodesFromQedeq.addActionListener(this.ctrl.getAddAllModulesFromQedeqAction());
            fileMenu.add(addAllNodesFromQedeq);
        }

        fileMenu.addSeparator();

        {
            final JMenuItem delete
                = new JMenuItem(getString("RemoveModule.Name"));
            delete.setMnemonic(getMnemonic("RemoveModule.MnemonicKey"));
            delete.getAccessibleContext().setAccessibleDescription(
                getString("RemoveModule.ShortDescription"));
            delete.addActionListener(this.ctrl.getDeleteAction());
            fileMenu.add(delete);
        }

        {
            final JMenuItem removeAllNodes
                = new JMenuItem(getString("RemoveAllModules.Name"));
            removeAllNodes.setMnemonic(getMnemonic("RemoveAllModules.MnemonicKey"));
            removeAllNodes.getAccessibleContext().setAccessibleDescription(
                getString("RemoveAllModules.ShortDescription"));
            removeAllNodes.addActionListener(this.ctrl.getRemoveAllAction());
            fileMenu.add(removeAllNodes);
        }

        fileMenu.addSeparator();
        
        {
            final JMenuItem exit
                = new JMenuItem(getString("Exit.Name"));
            exit.setMnemonic(getMnemonic("Exit.MnemonicKey"));
            exit.getAccessibleContext().setAccessibleDescription(
                getString("Exit.ShortDescription"));
            exit.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    PmiiFacade.shutdown();
                    System.exit(0);
                }
            });
            fileMenu.add(exit);
        }

        return fileMenu;
    }


    private JMenu createGenerateMenu() {
        final JMenu generateMenu = new JMenu(getString("GenerateMenu.generate.Name"));
        generateMenu.setMnemonic(getMnemonic("GenerateMenu.generate.MnemonicKey"));
        generateMenu.getAccessibleContext().setAccessibleDescription(
            getString("GenerateMenu.generate.ShortDescription"));
            
        {    
            final JMenuItem html
                = new JMenuItem(getString("GenerateHtmlModule.Name"));
            html.setMnemonic(getMnemonic("GenerateHtmlModule.MnemonicKey"));
            html.getAccessibleContext().setAccessibleDescription(
                getString("GenerateHtmlModule.ShortDescription"));
            html.addActionListener(ctrl.getHtmlAction());
            generateMenu.add(html);
        }

        {    
            final JMenuItem htmlAll
                = new JMenuItem(getString("GenerateAllHtmlModules.Name"));
            htmlAll.setMnemonic(getMnemonic("GenerateAllHtmlModules.MnemonicKey"));
            htmlAll.getAccessibleContext().setAccessibleDescription(
                getString("GenerateAllHtmlModules.ShortDescription"));
            htmlAll.addActionListener(ctrl.getHtmlAllAction());
            generateMenu.add(htmlAll);
        }

        {
            final JMenuItem latex
                = new JMenuItem(getString("GenerateLatexModule.Name"));
            latex.setMnemonic(getMnemonic("GenerateLatexModule.MnemonicKey"));
            latex.getAccessibleContext().setAccessibleDescription(
                getString("GenerateLatexModule.ShortDescription"));
            latex.addActionListener(ctrl.getLatexAction());
            generateMenu.add(latex);
        }

        {    
            final JMenuItem latexAll
                = new JMenuItem(getString("GenerateAllLatexModules.Name"));
            latexAll.setMnemonic(getMnemonic("GenerateAllLatexModules.MnemonicKey"));
            latexAll.getAccessibleContext().setAccessibleDescription(
                getString("GenerateAllLatexModules.ShortDescription"));
            latexAll.addActionListener(ctrl.getLatexAllAction());
            generateMenu.add(latexAll);
        }

        {
            final JMenuItem compress
                = new JMenuItem(getString("CompressModule.Name"));
            compress.setMnemonic(getMnemonic("CompressModule.MnemonicKey"));
            compress.getAccessibleContext().setAccessibleDescription(
                getString("CompressModule.ShortDescription"));
            compress.addActionListener(ctrl.getCompressAction());
            generateMenu.add(compress);
        }

        {
            final JMenuItem compressAll
                = new JMenuItem(getString("CompressAllModule.Name"));
            compressAll.setMnemonic(getMnemonic("CompressAllModule.MnemonicKey"));
            compressAll.getAccessibleContext().setAccessibleDescription(
                getString("CompressAllModule.ShortDescription"));
            compressAll.addActionListener(ctrl.getCompressAllAction());
            generateMenu.add(compressAll);
        }

        {
            final JMenuItem reduce
                = new JMenuItem(getString("ReduceModule.Name"));
            reduce.setMnemonic(getMnemonic("ReduceModule.MnemonicKey"));
            reduce.getAccessibleContext().setAccessibleDescription(
                getString("ReduceModule.ShortDescription"));
            reduce.addActionListener(ctrl.getReduceAction());
            generateMenu.add(reduce);
        }

        {
            final JMenuItem reduceAll
                = new JMenuItem(getString("ReduceAllModule.Name"));
            reduceAll.setMnemonic(getMnemonic("ReduceAllModule.MnemonicKey"));
            reduceAll.getAccessibleContext().setAccessibleDescription(
                getString("ReduceAllModule.ShortDescription"));
            reduceAll.addActionListener(ctrl.getReduceAllAction());
            generateMenu.add(reduceAll);
        }


        return generateMenu;
    }


    private JMenu createViewMenu() {
        final JMenu viewMenu = new JMenu(getString("ViewMenu.view.Name"));
        viewMenu.setMnemonic(getMnemonic("ViewMenu.view.MnemonicKey"));
        viewMenu.getAccessibleContext().setAccessibleDescription(
            getString("ViewMenu.view.ShortDescription"));
            
        {    
            final JCheckBoxMenuItem wrap
                = new JCheckBoxMenuItem(getString("LineWarpOption.Name"),
                tabbed.getLineWrap());
            wrap.setMnemonic(getMnemonic("LineWarpOption.MnemonicKey"));
            wrap.getAccessibleContext().setAccessibleDescription(
                getString("LineWarpOption.ShortDescription"));
            wrap.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent actionEvent) {
                    tabbed.setLineWrap(wrap.isSelected());
                }
            });
            viewMenu.add(wrap);
        }

        {
            final JCheckBoxMenuItem html
                = new JCheckBoxMenuItem(getString("ExperimentalHtmlViewOption.Name"),
                tabbed.getHtmlView());
            html.setMnemonic(getMnemonic("ExperimentalHtmlViewOption.MnemonicKey"));
            html.getAccessibleContext().setAccessibleDescription(
                getString("ExperimentalHtmlViewOption.ShortDescription"));
            html.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent actionEvent) {
                    tabbed.setHtmlView(html.isSelected());
                }
            });
            viewMenu.add(html);
        }

        return viewMenu;
    }


    private JMenu createSettingsMenu() {
        final JMenu editMenu = new JMenu(getString("EditMenu.edit.Name"));
        editMenu.setMnemonic(getMnemonic("EditMenu.edit.MnemonicKey"));
        editMenu.getAccessibleContext().setAccessibleDescription(
            getString("EditMenu.edit.ShortDescription"));
            
        {    
            final JMenuItem preferences
                = new JMenuItem(getString("EditMenu.preferences.Name"));
            preferences.setMnemonic(getMnemonic("EditMenu.preferences.MnemonicKey"));
            preferences.getAccessibleContext().setAccessibleDescription(
                getString("EditMenu.preferences.ShortDescription"));
            preferences.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent actionEvent) {
                    Trace.traceBegin(this, "actionPerformed");
                    final JFrame p = new Preferences( 
                        getString("EditMenu.preferences.Name"));
                    p.show();
                    Trace.traceEnd(this, "actionPerformed");
                }
            });
            editMenu.add(preferences);
        }
        return editMenu;
    }


    private JMenu createSpecial() {
        final JMenu specialMenu = new JMenu(getString("SpecialMenu.special.Name"));
        specialMenu.setMnemonic(getMnemonic("SpecialMenu.special.MnemonicKey"));
        specialMenu.getAccessibleContext().setAccessibleDescription(
            getString("SpecialMenu.special.ShortDescription"));
            
        {
            final JMenuItem removeLocalBuffer
                = new JMenuItem(getString("ClearLocalBuffer.Name"));
            removeLocalBuffer.setMnemonic(getMnemonic("ClearLocalBuffer.MnemonicKey"));
            removeLocalBuffer.getAccessibleContext().setAccessibleDescription(
                getString("ClearLocalBuffer.ShortDescription"));
            removeLocalBuffer.addActionListener(this.ctrl.getRemoveLocalBufferAction());
            specialMenu.add(removeLocalBuffer);
        }

        {
            final JMenuItem addPreviouslyCheckedNodes 
                = new JMenuItem(getString("LoadPreviouslyCheckedModules.Name"));
            addPreviouslyCheckedNodes.setMnemonic(getMnemonic("LoadPreviouslyCheckedModules.MnemonicKey"));
            addPreviouslyCheckedNodes.getAccessibleContext().setAccessibleDescription(
                getString("LoadPreviouslyCheckedModules.ShortDescription"));
            addPreviouslyCheckedNodes.addActionListener(this.ctrl.getAddPreviouslyCheckedAction());
            specialMenu.add(addPreviouslyCheckedNodes);
        }

        return specialMenu;
    }

    private JMenu createLafMenu() {
        final JMenu lookMenu = new JMenu(getString("LafMenu.laf.Name"));
        lookMenu.setMnemonic(getMnemonic("LafMenu.laf.MnemonicKey"));
        lookMenu.getAccessibleContext().setAccessibleDescription(
            getString("LafMenu.laf.ShortDescription"));

        // ***** create laf switcher menu 
        final JMenuItem mi = createlookMenuItem(lookMenu, "LafMenu.java.Name", 
                   "LafMenu.java.MnemonicKey",
                   "LafMenu.java.ShortDescription", metal);
        mi.setSelected(true); // this is the default l&f

        createlookMenuItem(lookMenu, "LafMenu.mac.Name", "LafMenu.mac.MnemonicKey",
                   "LafMenu.mac.ShortDescription", mac);

        createlookMenuItem(lookMenu, "LafMenu.motif.Name", "LafMenu.motif.MnemonicKey",
                   "LafMenu.motif.ShortDescription", motif);

        createlookMenuItem(lookMenu, "LafMenu.windows.Name", "LafMenu.windows.MnemonicKey",
                   "LafMenu.windows.ShortDescription", windows);

        createlookMenuItem(lookMenu, "LafMenu.gtk.Name", "LafMenu.gtk.MnemonicKey",
                   "LafMenu.gtk.ShortDescription", gtk);
        return lookMenu;
    }


    private JMenu createHelpMenu() {
        final JMenu helpMenu = new JMenu(getString("HelpMenu.help.Name"));
        helpMenu.setMnemonic(getMnemonic("HelpMenu.help.MnemonicKey"));
        helpMenu.getAccessibleContext().setAccessibleDescription(
            getString("HelpMenu.help.ShortDescription")); 
        {
            final JMenuItem about
                = new JMenuItem(getString("HelpMenu.about.Name"));
            about.setMnemonic(getMnemonic("HelpMenu.about.MnemonicKey"));
            about.getAccessibleContext().setAccessibleDescription(
                getString("HelpMenu.about.ShortDescription"));
            about.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent actionEvent) {
                    new AboutDialog(null).show();
                }
            });
            helpMenu.add(about);
        }
        {
            final JMenuItem feature
                = new JMenuItem(getString("ModuleDescription.Name"));
            feature.setMnemonic(getMnemonic("ModuleDescription.MnemonicKey"));
            feature.getAccessibleContext().setAccessibleDescription(
                getString("ModuleDescription.ShortDescription"));
            feature.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent actionEvent) {
                    new ModuleDescription(getString("ModuleDescription.ShortDescription")).show();
                }
            });
            helpMenu.add(feature);
        }
        {
            final JMenuItem feature
                = new JMenuItem(getString("FeatureList.Name"));
            feature.setMnemonic(getMnemonic("FeatureList.MnemonicKey"));
            feature.getAccessibleContext().setAccessibleDescription(
                getString("FeatureList.ShortDescription"));
            feature.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent actionEvent) {
                    new HtmlInfo(getString("FeatureList.ShortDescription")).show();
                }
            });
            helpMenu.add(feature);
        }

        return helpMenu;
    }
    

    /**
     * Creates a JRadioButtonMenuItem for the Look and Feel menu
     */
    private JMenuItem createlookMenuItem(JMenu menu, String label, String mnemonic,
                   String accessibleDescription, String laf) {
        JMenuItem mi = (JRadioButtonMenuItem) menu.add(new JRadioButtonMenuItem(
            getString(label)));
        lookMenuGroup.add(mi);
        mi.setMnemonic(getMnemonic(mnemonic));
        mi.getAccessibleContext().setAccessibleDescription(
            getString(accessibleDescription));
        mi.addActionListener(new ChangeLookAndFeelAction(laf));
    
        mi.setEnabled(isAvailableLookAndFeel(laf));

        return mi;
    }


    /**
     * This method returns a string from the resource bundle.
     */
    public String getString(String key) {
        return DataDictionary.getInstance().getString(key);
    }


    /**
     * Returns a mnemonic from the resource bundle. Typically used as
     * keyboard shortcuts in menu items.
     */
    public char getMnemonic(String key) {
        return DataDictionary.getInstance().getMnemonic(key);
    }


    /**
     * A utility function that layers on top of the LookAndFeel's
     * isSupportedLookAndFeel() method. Returns true if the LookAndFeel
     * is supported. Returns false if the LookAndFeel is not supported
     * and/or if there is any kind of error checking if the LookAndFeel
     * is supported.
     *
     * The L&F menu will use this method to detemine whether the various
     * L&F options should be active or inactive.
     *
     */
    private boolean isAvailableLookAndFeel(String laf) {
        try { 
            Class lnfClass = Class.forName(laf);
            LookAndFeel newLAF = (LookAndFeel)(lnfClass.newInstance());
            return newLAF.isSupportedLookAndFeel();
        } catch(Exception e) { // If ANYTHING weird happens, return false
            return false;
        }
    }


    /*
     * @see java.util.Observer#update(Observable, Object)
     */
    public void update(Observable observable, Object obj) {
    }



    /**
     * Listen for about events.
     */
    private class AboutListener implements ActionListener {

        /**
         * Start actions for about dialog.
         *
         * @param   actionEvent     user event
         */
        public void actionPerformed(ActionEvent actionEvent) {
            new AboutDialog(null).show();
        }

    }


    private class ChangeLookAndFeelAction extends AbstractAction {
        final String laf;
        protected ChangeLookAndFeelAction(String laf) {
            super("ChangeTheme");
            this.laf = laf;
        }

        public void actionPerformed(ActionEvent e) {
            try {
                UIManager.setLookAndFeel(laf);
                SwingUtilities.updateComponentTreeUI(mainFrame);
            } catch (Exception ex) {
                Trace.trace(this, "actionPerformed", ex); 
            }
        }
    }



}
