/*
 * Copyright 2010-2015 Institut Pasteur.
 * 
 * This file is part of Icy.
 * 
 * Icy 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 3 of the License, or
 * (at your option) any later version.
 * 
 * Icy 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 Icy. If not, see <http://www.gnu.org/licenses/>.
 */
package icy.gui.menu;

import icy.action.FileActions;
import icy.action.GeneralActions;
import icy.action.PreferencesActions;
import icy.file.FileUtil;
import icy.file.Importer;
import icy.file.Loader;
import icy.gui.component.button.IcyCommandButton;
import icy.gui.component.menu.IcyRibbonApplicationMenuEntryPrimary;
import icy.gui.component.menu.IcyRibbonApplicationMenuEntrySecondary;
import icy.gui.plugin.PluginCommandButton;
import icy.gui.util.ComponentUtil;
import icy.main.Icy;
import icy.plugin.PluginDescriptor;
import icy.plugin.PluginLauncher;
import icy.plugin.PluginLoader;
import icy.plugin.PluginLoader.PluginLoaderEvent;
import icy.plugin.PluginLoader.PluginLoaderListener;
import icy.preferences.GeneralPreferences;
import icy.preferences.IcyPreferences;
import icy.resource.ResourceUtil;
import icy.resource.icon.IcyIcon;
import icy.sequence.Sequence;
import icy.sequence.SequenceImporter;
import icy.system.IcyExceptionHandler;
import icy.system.thread.ThreadUtil;
import icy.type.collection.CollectionUtil;
import icy.type.collection.list.RecentFileList;
import icy.util.StringUtil;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.List;

import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingConstants;

import org.pushingpixels.flamingo.api.common.AbstractCommandButton;
import org.pushingpixels.flamingo.api.common.CommandButtonDisplayState;
import org.pushingpixels.flamingo.api.common.JCommandButton;
import org.pushingpixels.flamingo.api.common.JCommandButton.CommandButtonKind;
import org.pushingpixels.flamingo.api.common.JCommandButtonPanel;
import org.pushingpixels.flamingo.api.common.JCommandButtonPanel.LayoutKind;
import org.pushingpixels.flamingo.api.common.RichTooltip;
import org.pushingpixels.flamingo.api.ribbon.RibbonApplicationMenu;
import org.pushingpixels.flamingo.api.ribbon.RibbonApplicationMenuEntryPrimary;
import org.pushingpixels.flamingo.api.ribbon.RibbonApplicationMenuEntrySecondary;

/**
 * @author Stephane
 */
public class ApplicationMenu extends RibbonApplicationMenu implements PluginLoaderListener
{
     static final int RECENTFILE_MAXLEN = 100;

    /**
     * Secondary panel management for "Open Recent File"
     */
    private class OpenRecentFileRollOverCallBack implements RibbonApplicationMenuEntryPrimary.PrimaryRolloverCallback
    {
        public OpenRecentFileRollOverCallBack()
        {
            super();
        }

        @Override
        public void menuEntryActivated(JPanel targetPanel)
        {
            ComponentUtil.setPreferredWidth(targetPanel, 480);

            final JCommandButtonPanel recentFilesPanel = new JCommandButtonPanel(CommandButtonDisplayState.MEDIUM);

            // set to 1 column maximum
            recentFilesPanel.setMaxButtonColumns(1);
            recentFilesPanel.setLayoutKind(LayoutKind.ROW_FILL);

            // recent files group
            recentFilesPanel.addButtonGroup("Recent Files");

            // remove obsolete entries
            recentFileList.clean();

            final int nbRecentFile = recentFileList.getSize();
            final IcyIcon icon = new IcyIcon("document");

            for (int i = 0; i < nbRecentFile; i++)
            {
                final String entry = recentFileList.getEntryAsName(i, RECENTFILE_MAXLEN, true);

                if (!StringUtil.isEmpty(entry))
                {
                    final JCommandButton button = new JCommandButton(entry, icon);

                    button.setHorizontalAlignment(SwingConstants.LEFT);

                    final String[] paths = recentFileList.getEntry(i);
                    // final File[] files = recentFileList.getEntryAsFiles(i);

                    final RichTooltip toolTip;
                    final int numFile = paths.length;

                    if (numFile == 1)
                        toolTip = new RichTooltip("Single file sequence", FileUtil.getFileName(paths[0]));
                    else
                        toolTip = new RichTooltip("Multiple files sequence", FileUtil.getFileName(paths[0]));

                    for (int j = 1; j < Math.min(10, numFile); j++)
                        toolTip.addDescriptionSection(FileUtil.getFileName(paths[j]));
                    if (numFile > 10)
                    {
                        toolTip.addDescriptionSection("...");
                        toolTip.addDescriptionSection(FileUtil.getFileName(paths[numFile - 1]));
                    }

                    button.setActionRichTooltip(toolTip);

                    button.addActionListener(new ActionListener()
                    {
                        @Override
                        public void actionPerformed(ActionEvent ae)
                        {
                            Loader.load(CollectionUtil.asList(paths), false, true, true);
                        }
                    });

                    // add button to history panel
                    recentFilesPanel.addButtonToLastGroup(button);
                }
            }

            // action group
            recentFilesPanel.addButtonGroup("Action");

            final IcyCommandButton clearButton = new IcyCommandButton(FileActions.clearRecentFilesAction);
            recentFilesPanel.addButtonToLastGroup(clearButton);

            targetPanel.removeAll();
            targetPanel.setLayout(new BorderLayout());
            targetPanel.add(new JScrollPane(recentFilesPanel), BorderLayout.CENTER);
            targetPanel.validate();
        }
    }

    /**
     * Secondary panel management for "Import"
     * Display all other importers (anything which is not "openable" from File)
     */
    private class ImportResourceRollOverCallBack implements RibbonApplicationMenuEntryPrimary.PrimaryRolloverCallback
    {
        public ImportResourceRollOverCallBack()
        {
            super();
        }

        @Override
        public void menuEntryActivated(JPanel targetPanel)
        {
            ComponentUtil.setPreferredWidth(targetPanel, 480);

            final JCommandButtonPanel importPanel = new JCommandButtonPanel(CommandButtonDisplayState.MEDIUM);

            // set to 1 column maximum
            importPanel.setMaxButtonColumns(1);
            importPanel.setLayoutKind(LayoutKind.ROW_FILL);

            // add Sequence importers
            final List<PluginDescriptor> sequenceImporterPlugins = PluginLoader.getPlugins(SequenceImporter.class);
            if (!sequenceImporterPlugins.isEmpty())
            {
                importPanel.addButtonGroup("Sequence importer");
                for (PluginDescriptor plugin : sequenceImporterPlugins)
                {
                    final AbstractCommandButton button = PluginCommandButton.createButton(plugin, false, false, false);

                    button.setHorizontalAlignment(SwingConstants.LEFT);
                    button.addActionListener(new ActionListener()
                    {
                        @Override
                        public void actionPerformed(ActionEvent event)
                        {
                            final AbstractCommandButton button = (AbstractCommandButton) event.getSource();
                            final PluginDescriptor pluginDescriptor = PluginLoader.getPlugin(button.getName());

                            if (pluginDescriptor != null)
                            {
                                try
                                {
                                    // we really need to start the plugin here in case it uses EzPlug for instance
                                    final SequenceImporter importer = (SequenceImporter) PluginLauncher
                                            .startSafe(pluginDescriptor);

                                    // asynchronous loading
                                    ThreadUtil.bgRun(new Runnable()
                                    {
                                        @Override
                                        public void run()
                                        {

                                            try
                                            {
                                                // plugin correctly started ? --> do load operation
                                                final Sequence result = importer.load();
                                                
                                                // display result sequence
                                                if (result != null)
                                                    Icy.getMainInterface().addSequence(result);
                                            }
                                            catch (Exception exc)
                                            {
                                                IcyExceptionHandler.handleException(exc, false);
                                            }
                                        }
                                    });
                                }
                                catch (Exception exc)
                                {
                                    IcyExceptionHandler.handleException(exc, false);
                                }
                            }
                        }
                    });

                    importPanel.addButtonToLastGroup(button);
                }
            }

            // add Sequence importers
            final List<PluginDescriptor> importerPlugins = PluginLoader.getPlugins(Importer.class);
            if (!importerPlugins.isEmpty())
            {
                importPanel.addButtonGroup("General importer");

                for (PluginDescriptor plugin : importerPlugins)
                {
                    final AbstractCommandButton button = PluginCommandButton.createButton(plugin, false, false, false);

                    button.setHorizontalAlignment(SwingConstants.LEFT);
                    button.addActionListener(new ActionListener()
                    {
                        @Override
                        public void actionPerformed(ActionEvent event)
                        {
                            final AbstractCommandButton button = (AbstractCommandButton) event.getSource();
                            final PluginDescriptor pluginDescriptor = PluginLoader.getPlugin(button.getName());

                            if (pluginDescriptor != null)
                            {
                                try
                                {
                                    // we really need to start the plugin here in case it uses EzPlug for instance
                                    final Importer importer = (Importer) PluginLauncher.startSafe(pluginDescriptor);

                                    // asynchronous loading
                                    ThreadUtil.bgRun(new Runnable()
                                    {
                                        @Override
                                        public void run()
                                        {

                                            try
                                            {
                                                // plugin correctly started ? --> do load operation
                                                importer.load();
                                            }
                                            catch (Exception exc)
                                            {
                                                IcyExceptionHandler.handleException(exc, false);
                                            }
                                        }
                                    });
                                }
                                catch (Exception exc)
                                {
                                    IcyExceptionHandler.handleException(exc, false);
                                }
                            }
                        }
                    });

                    importPanel.addButtonToLastGroup(button);
                }
            }

            targetPanel.removeAll();
            targetPanel.setLayout(new BorderLayout());
            targetPanel.add(new JScrollPane(importPanel), BorderLayout.CENTER);
            targetPanel.validate();
        }
    }

    /**
     * Default roll callback
     */
    private class EmptyRollOverCallBack implements RibbonApplicationMenuEntryPrimary.PrimaryRolloverCallback
    {
        public EmptyRollOverCallBack()
        {
            super();
        }

        @Override
        public void menuEntryActivated(JPanel targetPanel)
        {
            ComponentUtil.setPreferredWidth(targetPanel, 480);

            // ribbon need at least one component in targetPanel
            targetPanel.removeAll();
            targetPanel.add(new JPanel());
            targetPanel.validate();
        }
    }

    final RecentFileList recentFileList;

    private final RibbonApplicationMenuEntryPrimary amepCreate;
    private final RibbonApplicationMenuEntrySecondary amesCreateGraySequence;
    private final RibbonApplicationMenuEntrySecondary amesCreateRGBSequence;
    private final RibbonApplicationMenuEntrySecondary amesCreateRGBASequence;
    private final RibbonApplicationMenuEntryPrimary amepOpen;
    private final RibbonApplicationMenuEntryPrimary amepImport;
    private final RibbonApplicationMenuEntryPrimary amepSaveDefault;
    private final RibbonApplicationMenuEntrySecondary amepSave;
    private final RibbonApplicationMenuEntrySecondary amepSaveAs;
    private final RibbonApplicationMenuEntrySecondary amepSaveMetaData;
    private final RibbonApplicationMenuEntryPrimary amepClose;
    private final RibbonApplicationMenuEntrySecondary amesCloseCurrent;
    private final RibbonApplicationMenuEntrySecondary amesCloseOthers;
    private final RibbonApplicationMenuEntrySecondary amesCloseAll;
    private final RibbonApplicationMenuEntryPrimary amepPreferences;
    private final RibbonApplicationMenuEntryPrimary amepExit;

    /**
     * 
     */
    public ApplicationMenu()
    {
        super();

        recentFileList = new RecentFileList(IcyPreferences.applicationRoot().node("loader"));

        // CREATE SEQUENCE
        amepCreate = new IcyRibbonApplicationMenuEntryPrimary(FileActions.newSequenceAction);

        amesCreateGraySequence = new IcyRibbonApplicationMenuEntrySecondary(FileActions.newGraySequenceAction);
        amesCreateRGBSequence = new IcyRibbonApplicationMenuEntrySecondary(FileActions.newRGBSequenceAction);
        amesCreateRGBASequence = new IcyRibbonApplicationMenuEntrySecondary(FileActions.newARGBSequenceAction);

        amepCreate.addSecondaryMenuGroup("New image", amesCreateGraySequence, amesCreateRGBSequence, amesCreateRGBASequence);

        // OPEN & IMPORT
        amepOpen = new IcyRibbonApplicationMenuEntryPrimary(FileActions.openSequenceAction);
        amepOpen.setRolloverCallback(new OpenRecentFileRollOverCallBack());

        amepImport = new IcyRibbonApplicationMenuEntryPrimary(new IcyIcon(ResourceUtil.ICON_DOC_IMPORT), "Import",
                null, CommandButtonKind.POPUP_ONLY);
        amepImport.setRolloverCallback(new ImportResourceRollOverCallBack());

        // SAVE & EXPORT
        amepSaveDefault = new IcyRibbonApplicationMenuEntryPrimary(FileActions.saveDefaultSequenceAction);

        amepSave = new IcyRibbonApplicationMenuEntrySecondary(FileActions.saveSequenceAction);
        amepSaveAs = new IcyRibbonApplicationMenuEntrySecondary(FileActions.saveAsSequenceAction);
        amepSaveMetaData = new IcyRibbonApplicationMenuEntrySecondary(FileActions.saveMetaDataAction);

        amepSaveDefault.addSecondaryMenuGroup("Save", amepSave, amepSaveAs, amepSaveMetaData);
        
        // final RibbonApplicationMenuEntryPrimary amepExport = new
        // RibbonApplicationMenuEntryPrimary(
        // new ICYResizableIcon.Icy("doc_export.png"), "Export", new ActionListener()
        // {
        // @Override
        // public void actionPerformed(ActionEvent e)
        // {
        // System.out.println("export action...");
        // }
        // }, CommandButtonKind.ACTION_ONLY);
        // amepExport.setRolloverCallback(new DefaultRollOverCallBack());

        // CLOSE
        amepClose = new IcyRibbonApplicationMenuEntryPrimary(FileActions.closeSequenceAction);

        amesCloseCurrent = new IcyRibbonApplicationMenuEntrySecondary(FileActions.closeCurrentSequenceAction);
        amesCloseOthers = new IcyRibbonApplicationMenuEntrySecondary(FileActions.closeOthersSequencesAction);
        amesCloseAll = new IcyRibbonApplicationMenuEntrySecondary(FileActions.closeAllSequencesAction);

        amepClose.addSecondaryMenuGroup("Close Sequence", amesCloseCurrent, amesCloseOthers, amesCloseAll);

        // PREFERENCES
        amepPreferences = new IcyRibbonApplicationMenuEntryPrimary(PreferencesActions.preferencesAction);

        // EXIT
        amepExit = new IcyRibbonApplicationMenuEntryPrimary(GeneralActions.exitApplicationAction);
        amepExit.setRolloverCallback(new EmptyRollOverCallBack());

        // build menu

        addMenuEntry(amepCreate);
        addMenuEntry(amepOpen);
        addMenuEntry(amepSaveDefault);

        addMenuSeparator();
        addMenuEntry(amepImport);
        // addMenuEntry(amepExport);

        addMenuSeparator();
        addMenuEntry(amepClose);

        addMenuSeparator();
        addMenuEntry(amepPreferences);

        addMenuSeparator();
        addMenuEntry(amepExit);

        setDefaultCallback(new OpenRecentFileRollOverCallBack());

        refreshState();

        PluginLoader.addListener(this);
    }

    private void refreshState()
    {
        final Sequence focusedSequence = Icy.getMainInterface().getActiveSequence();

        final boolean hasImporter = (!PluginLoader.getPlugins(SequenceImporter.class).isEmpty())
                || (!PluginLoader.getPlugins(Importer.class).isEmpty());

        amepImport.setEnabled(hasImporter);
        amepSaveDefault.setEnabled(focusedSequence != null);
        amepSave.setEnabled((focusedSequence != null) && !StringUtil.isEmpty(focusedSequence.getFilename()));
        amepSaveAs.setEnabled(focusedSequence != null);
        amepSaveMetaData.setEnabled((focusedSequence != null) && !StringUtil.isEmpty(focusedSequence.getFilename())
                && GeneralPreferences.getSequencePersistence());
        amepClose.setEnabled(Icy.getMainInterface().getSequences().size() > 0);
    }

    /**
     * @return the recentFileList
     */
    public RecentFileList getRecentFileList()
    {
        return recentFileList;
    }

    public void addRecentLoadedFile(List<File> files)
    {
        addRecentLoadedFile(files.toArray(new File[files.size()]));
    }

    public void addRecentLoadedFile(File[] files)
    {
        recentFileList.addEntry(files);
    }

    public void addRecentLoadedFile(File file)
    {
        addRecentLoadedFile(new File[] {file});
    }

    /**
     * Add a list of recently opened files (String format)
     */
    public void addRecentFile(List<String> paths)
    {
        addRecentFile(paths.toArray(new String[paths.size()]));
    }

    public void addRecentFile(String[] paths)
    {
        recentFileList.addEntry(paths);
    }

    public void addRecentFile(String path)
    {
        addRecentFile(new String[] {path});
    }

    public void onSequenceActivationChange()
    {
        refreshState();
    }

    @Override
    public void pluginLoaderChanged(PluginLoaderEvent e)
    {
        // amepImport.addSecondaryMenuGroup("Import a sequence", getImportEntries());
        refreshState();
    }
}