package de.renew.navigator;

import javax.swing.JMenuItem;
import javax.swing.JTree;

import CH.ifa.draw.DrawPlugin;
import CH.ifa.draw.IOHelper;
import CH.ifa.draw.io.ImportHolder;
import CH.ifa.draw.util.CommandMenuItem;
import de.renew.draw.ui.api.MenuApi;
import de.renew.draw.ui.ontology.MenuSectionPosition;
import de.renew.ioontology.FileFilterBuilder;
import de.renew.navigator.gui.NavigatorGuiProxy;
import de.renew.navigator.io.internal.FileFilterHandler;
import de.renew.navigator.models.NavigatorFileTree;
import de.renew.plugin.PluginManager;
import de.renew.plugin.PluginProperties;
import de.renew.plugin.annotations.Inject;
import de.renew.plugin.annotations.Provides;
import de.renew.plugin.di.DIPlugin;
import de.renew.windowmanagement.Workbench;


/**
 * This is the main class of the Navigator plug-in.
 * It is initializing and registering two CommandMenuItems to the Renew-GUI.
 * The initialization of the NavigatorGUI will be done when one of these commands gets executed.
 *
 * @author Konstantin Moellers (1kmoelle), Hannes Ahrens (4ahrens)
 * @version September 2015
 */
public final class NavigatorPlugin extends DIPlugin implements NavigatorExtender {
    private static final String OPEN_NAVIGATOR_COMMAND_MENU_ID = "de.renew.navigator.show";
    /**
     * property name in plugin.cfg of the open hotkey
     */
    public static final String OPEN_NAVIGATOR_HOTKEY_PROP_NAME =
        "de.renew.hotkeymap.navigator.open";

    private final NavigatorFileTree _model;
    private final AutosaveController _autoSave;
    private final FilesystemController _fileSystem;
    private final NavigatorGui _gui;
    private JMenuItem _openNavigatorItem;

    /**
     * Constructor for the NavigatorPlugin.
     *
     * @param importHolder the holder containing imported data.
     * @param ioHelper a helper for input/output operations.
     * @param workbench the main workbench interface of the application.
     */
    @Inject
    public NavigatorPlugin(ImportHolder importHolder, IOHelper ioHelper, Workbench workbench) {
        // Create the navigator model.
        _model = new NavigatorFileTree();

        // Create a FileFilterBuilder for filesystem ops.
        FileFilterBuilder builder = FileFilterHandler.createFileFilterBuilder();

        // Create controllers.
        _autoSave = new AutosaveController(this);
        _fileSystem = new FilesystemController(this, builder);

        // Initialize the GUI proxy.
        _gui = new NavigatorGuiProxy(_fileSystem, workbench, this);
    }

    @Override
    @Provides
    public NavigatorFileTree getModel() {
        return _model;
    }

    /**
     * This is a getter that gets the navigator gui.
     *
     * @return _gui The NavigatorGui.
     */
    @Provides
    public NavigatorGui getGui() {
        return _gui;
    }

    /**
     * This method overwrites the virtual PluginAdapter.initGui() method.
     * Two new commands get initialized and registered to the Renew-GUI:
     * - OpenNavigatorCommand: opening the Navigator
     * - OpenInNavigatorCommand: opening the Navigator and a JFileChooser to open files
     * The OpenNavigatorCommand gets registered to the plug-in menu, similar to the MulanViewer with
     * the shortcut ctrl+shift+n.
     * The OpenInNavigatorCommand gets registered to the file menu, with the shortcut ctrl+shift+o
     * to open files.
     */
    @Override
    public void init() {
        PluginManager pluginManager = PluginManager.getInstance();
        if (pluginManager != null) {
            pluginManager.addCLCommand(OpenNavigatorCommand.CMD, new OpenNavigatorCommand(this));
        }
        // Init Menu.
        initMenu();
        // Create controllers
        initControllers();
    }

    private void initMenu() {
        _openNavigatorItem = new CommandMenuItem(
            new OpenNavigatorCommand(this),
            PluginProperties.getUserProperties().getHotkeyProperty(
                OPEN_NAVIGATOR_HOTKEY_PROP_NAME,
                getProperties().getHotkeyProperty(OPEN_NAVIGATOR_HOTKEY_PROP_NAME)));
        _openNavigatorItem.putClientProperty(MenuApi.ID_PROPERTY, OPEN_NAVIGATOR_COMMAND_MENU_ID);
        MenuApi.registerMenu(
            DrawPlugin.FILE_MENU, _openNavigatorItem, 2, MenuSectionPosition.BEGINNING);
    }

    /**
     * Clean up method to deregister the navigator plugin.
     *
     * {@link de.renew.plugin.IPlugin#cleanup}
     **/
    @Override
    public boolean cleanup() {
        //gui.closeWindow();

        if (_openNavigatorItem != null) {
            MenuApi.unregisterMenu(_openNavigatorItem);
            _openNavigatorItem = null;
        }
        PluginManager pluginManager = PluginManager.getInstance();
        if (pluginManager != null) {
            pluginManager.removeCLCommand(OpenNavigatorCommand.CMD);
        }

        return true;
    }

    @Override
    public void registerExtension(NavigatorExtension extension) {
        _gui.addExtension(extension);
    }

    @Override
    public boolean deregisterExtension(NavigatorExtension extension) {
        return _gui.removeExtension(extension);
    }

    @Override
    public JTree getTree() {
        return _gui.getTree();
    }

    /**
     * The openNavigator() method assures the NavigatorGUI is created, initialized, visible and in
     * the front.
     */
    public void openNavigator() {
        // Load model from autosave.
        if (_autoSave.isAutosaveFileExisting()) {
            _autoSave.loadModel();
        }

        // Open the GUI window.
        _gui.openWindow();
    }

    /**
     * Initializes controllers and let them observe the model.
     */
    private void initControllers() {
        _model.addObserver(_autoSave);
        _model.addObserver(_fileSystem);
    }

    /**
     * This method first calls openNavigator() to assure the navigator is open and initialized.
     * Afterward it calls the navigator-GUI to open a JFileChooser for adding files and folders.
     *
     * @deprecated Use {@link #openNavigator} directly
     */
    @Deprecated
    public void openInNavigator() {
        openNavigator();
    }

    /**
     * @return the current plugin instance
     * @deprecated Please let the Plugin be injected.
     */
    @Deprecated
    public static NavigatorPlugin getCurrent() {
        return (NavigatorPlugin) PluginManager.getInstance().getPluginByName("Navigator");
    }
}