/*
 *  Copyright (C) 2010-2021 JPEXS
 * 
 *  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 3 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, see <http://www.gnu.org/licenses/>.
 */
package com.jpexs.decompiler.flash.gui;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.swing.ButtonGroup;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.KeyStroke;
import javax.swing.MenuElement;
import javax.swing.event.MenuEvent;
import javax.swing.event.MenuListener;

/**
 *
 * @author JPEXS
 */
public class MainFrameClassicMenu extends MainFrameMenu {

    private final MainFrameClassic mainFrame;

    private final Map<String, MenuElement> menuElements = new HashMap<>();

    private final Map<String, Set<String>> menuGroups = new HashMap<>();

    private final Map<String, ButtonGroup> menuButtonGroups = new HashMap<>();

    public MainFrameClassicMenu(MainFrameClassic mainFrame, boolean externalFlashPlayerUnavailable) {
        super(mainFrame, externalFlashPlayerUnavailable);
        this.mainFrame = mainFrame;

    }

    private void addMenu(String path, String title, String icon, final ActionListener subLoader) {
        path = mapping(path);
        final String fpath = path;
        if (path.equals("_") || path.startsWith("_/")) {
            return;
        }
        String parentPath = "";
        if (path.contains("/")) {
            parentPath = path.substring(0, path.lastIndexOf('/'));
        }
        MenuElement parentMenu = menuElements.get(parentPath);
        if (parentMenu == null) {
            throw new IllegalArgumentException("Parent menu " + path + " does not exist");
        }
        JMenu menu = new JMenu(title);
        if (icon != null) {
            menu.setIcon(View.getIcon(icon, 16));
        }
        if (parentMenu instanceof JMenuBar) {
            ((JMenuBar) parentMenu).add(menu);
        }
        if (parentMenu instanceof JMenu) {
            ((JMenu) parentMenu).add(menu);
            if (subLoader != null) {
                ((JMenu) parentMenu).addMenuListener(new MenuListener() {

                    @Override
                    public void menuSelected(MenuEvent e) {
                        subLoader.actionPerformed(new ActionEvent(menu, 0, "load:" + fpath));
                    }

                    @Override
                    public void menuDeselected(MenuEvent e) {
                    }

                    @Override
                    public void menuCanceled(MenuEvent e) {
                    }
                });
            };
        }
        menuElements.put(path, menu);
    }

    @Override
    public void addMenuItem(String path, String title, String icon, ActionListener action, int priority, final ActionListener subLoader, boolean isLeaf, HotKey key, boolean isOptional) {
        path = mapping(path);

        menuHotkeys.put(path, key);
        menuActions.put(path, action);

        if (!isLeaf) {
            //action is ignored
            addMenu(path, title, icon, subLoader);
            return;
        }
        if (path.startsWith("_/")) {
            return;
        }
        String parentPath = "";
        if (path.contains("/")) {
            parentPath = path.substring(0, path.lastIndexOf('/'));
        }
        MenuElement parentMenu = menuElements.get(parentPath);
        if (parentMenu == null) {
            throw new IllegalArgumentException("Parent menu " + path + " does not exist");
        }
        JMenuItem menuItem = new JMenuItem(title);
        if (icon != null) {
            menuItem.setIcon(View.getIcon(icon, 16));
        }
        if (action != null) {
            menuItem.addActionListener(action);
        }
        if (key != null) {
            menuItem.setAccelerator(KeyStroke.getKeyStroke(key.key, key.getModifier()));
        }
        if (parentMenu instanceof JMenu) {
            ((JMenu) parentMenu).add(menuItem);
        } else {
            throw new IllegalArgumentException("Parent path " + path + " is not a menu");
        }
        menuElements.put(path, menuItem);
    }

    @Override
    public void addToggleMenuItem(String path, String title, String group, String icon, ActionListener action, int priority, HotKey key) {
        path = mapping(path);
        menuHotkeys.put(path, key);

        String parentPath = "";
        if (path.contains("/")) {
            parentPath = path.substring(0, path.lastIndexOf('/'));
        }
        MenuElement parentMenu = menuElements.get(parentPath);
        if (parentMenu == null) {
            throw new IllegalArgumentException("Parent menu " + path + " does not exist");
        }
        JMenuItem menuItem;
        if (group == null) {
            menuItem = new JCheckBoxMenuItem(title);
        } else {
            menuItem = new JRadioButtonMenuItem(title);
            if (!menuGroups.containsKey(group)) {
                menuGroups.put(group, new HashSet<>());
            }
            if (!menuButtonGroups.containsKey(group)) {
                menuButtonGroups.put(group, new ButtonGroup());
            }
            menuGroups.get(group).add(path);
            menuButtonGroups.get(group).add(menuItem);
        }
        if (icon != null) {
            menuItem.setIcon(View.getIcon(icon, 16));
        }
        if (action != null) {
            menuItem.addActionListener(action);
        }
        if (parentMenu instanceof JMenu) {
            ((JMenu) parentMenu).add(menuItem);
        } else {
            throw new IllegalArgumentException("Parent path " + path + " is not a menu");
        }
        menuElements.put(path, menuItem);
    }

    @Override
    public String getGroupSelection(String group) {
        if (!menuGroups.containsKey(group)) {
            return null;
        }
        for (String path : menuGroups.get(group)) {
            if (isMenuChecked(path)) {
                return path;
            }
        }
        return null;
    }

    @Override
    public void clearMenu(String path) {
        path = mapping(path);
        if (path.equals("_") || path.startsWith("_/")) {
            return;
        }
        MenuElement menu = menuElements.get(path);
        if (menu == null) {
            throw new IllegalArgumentException("Menu " + path + " does not exist");
        }
        if (menu instanceof JMenuBar) {
            ((JMenuBar) menu).removeAll();
        } else if (menu instanceof JMenu) {
            ((JMenu) menu).removeAll();
        } else {
            throw new IllegalArgumentException(path + " is not a menu");
        }

    }

    @Override
    public void setMenuEnabled(String path, boolean enabled) {
        path = mapping(path);
        if (path.equals("_") || path.startsWith("_/")) {
            return;
        }
        MenuElement menu = menuElements.get(path);
        if (menu == null) {
            throw new IllegalArgumentException("Menu " + path + " does not exist");
        }
        if (menu instanceof JMenuBar) {
            ((JMenuBar) menu).setEnabled(enabled);
        } else if (menu instanceof JMenu) {
            ((JMenu) menu).setEnabled(enabled);
        } else if (menu instanceof JMenuItem) {
            ((JMenuItem) menu).setEnabled(enabled);
        } else {
            throw new IllegalArgumentException(path + " is not a menu");
        }
    }

    @Override
    public boolean isMenuChecked(String path) {
        path = mapping(path);
        MenuElement menu = menuElements.get(path);
        if (menu == null) {
            throw new IllegalArgumentException("Menu " + path + " does not exist");
        }
        if (menu instanceof JCheckBoxMenuItem) {
            return ((JCheckBoxMenuItem) menu).isSelected();
        } else if (menu instanceof JRadioButtonMenuItem) {
            return ((JRadioButtonMenuItem) menu).isSelected();
        } else {
            throw new IllegalArgumentException(path + " is not selectable menu item");
        }
    }

    @Override
    public void setMenuChecked(String path, boolean checked) {
        path = mapping(path);
        MenuElement menu = menuElements.get(path);
        if (menu == null) {
            throw new IllegalArgumentException("Menu " + path + " does not exist");
        }
        if (menu instanceof JCheckBoxMenuItem) {
            ((JCheckBoxMenuItem) menu).setSelected(checked);
        } else if (menu instanceof JRadioButtonMenuItem) {
            ((JRadioButtonMenuItem) menu).setSelected(checked);
        } else {
            throw new IllegalArgumentException(path + " is not selectable menu item");
        }
    }

    @Override
    public void setGroupSelection(String group, String selected) {
        if (selected != null) {
            selected = mapping(selected);
        }
        for (String path : menuGroups.get(group)) {
            setMenuChecked(path, selected == null ? false : path.equals(selected));
        }
    }

    @Override
    public void initMenu() {
        JMenuBar menuBar = new JMenuBar();
        menuElements.put("", menuBar);
        mainFrame.setJMenuBar(menuBar);
    }

    @Override
    public void finishMenu(String path) {
        path = mapping(path);
        if (path.equals("_") || path.startsWith("_/")) {
            return;
        }
        if (!menuElements.containsKey(path)) {
            throw new IllegalArgumentException("Invalid menu: " + path);
        }
        if (path.startsWith("/file/recent")) {
            return;
        }
        if (path.startsWith("/tools/recentsearch")) {
            return;
        }
        MenuElement me = menuElements.get(path);
        if (me instanceof JMenu) {
            JMenu jm = (JMenu) me;
            if (jm.getMenuComponentCount() == 1) {
                String parentPath = path.contains("/") ? path.substring(0, path.lastIndexOf('/')) : "";
                MenuElement parMe = menuElements.get(parentPath);
                JMenuItem mi = (JMenuItem) jm.getMenuComponent(0);
                jm.remove(mi);
                if (parMe instanceof JMenu) {
                    JMenu parMenu = (JMenu) parMe;
                    parMenu.remove(jm);
                    parMenu.add(mi);
                } else if (parMe instanceof JMenuBar) {
                    JMenuBar parMenuBar = (JMenuBar) parMe;
                    parMenuBar.remove(jm);
                    parMenuBar.add(mi);
                }
            }
        }
    }

    @Override
    public void addSeparator(String parentPath) {
        parentPath = mapping(parentPath);
        if (parentPath.equals("_") || parentPath.startsWith("_/")) {
            return;
        }
        if (!menuElements.containsKey(parentPath)) {
            throw new IllegalArgumentException("Menu does not exist: " + parentPath);
        }
        MenuElement parent = menuElements.get(parentPath);
        if (parent instanceof JMenu) {
            ((JMenu) parent).addSeparator();
        } else {
            throw new IllegalArgumentException("Not a menu: " + parentPath);
        }
    }

    @Override
    public boolean supportsMenuAction() {
        return false;
    }

    @Override
    public boolean supportsAppMenu() {
        return false;
    }

    /**
     * Maps some menus to other location
     *
     * @param s Source
     * @return To
     */
    private String mapping(String s) {
        Map<String, String> map = new HashMap<>();
        map.put("/file/view", "/view");

        for (String k : map.keySet()) {
            String v = map.get(k);
            if (s.startsWith(k)) {
                s = v + s.substring(k.length());
                return s;
            }
        }
        return s;
    }

    @Override
    public void hilightPath(String path) {
        //TODO
    }

    @Override
    public void setPathVisible(String path, boolean val) {
        MenuElement me = menuElements.get(path);
        if (me instanceof JComponent) {
            ((JComponent) me).setVisible(val);
        }
    }
}
