/*****************************************************************
 *   Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you under the Apache License, Version 2.0 (the
 *  "License"); you may not use this file except in compliance
 *  with the License.  You may obtain a copy of the License at
 *
 *    https://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations
 *  under the License.
 ****************************************************************/
package org.apache.cayenne.modeler.osx;

import java.awt.Color;
import java.awt.Component;
import java.awt.Desktop;
import java.awt.Graphics;
import java.util.HashSet;
import java.util.Set;

import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.UIManager;
import javax.swing.border.AbstractBorder;
import javax.swing.border.Border;

import org.apache.cayenne.di.Inject;
import org.apache.cayenne.modeler.action.AboutAction;
import org.apache.cayenne.modeler.action.ActionManager;
import org.apache.cayenne.modeler.action.ConfigurePreferencesAction;
import org.apache.cayenne.modeler.action.ExitAction;
import org.apache.cayenne.modeler.init.platform.PlatformInitializer;

public class OSXPlatformInitializer implements PlatformInitializer {

    @Inject
    protected ActionManager actionManager;

    public void initLookAndFeel() {

        // override some default styles and colors, assuming that Aqua theme will be used
        overrideUIDefaults();

        Desktop desktop = Desktop.getDesktop();

        desktop.setAboutHandler(e -> actionManager.getAction(AboutAction.class).showAboutDialog());
        desktop.setPreferencesHandler(e -> actionManager.getAction(ConfigurePreferencesAction.class).showPreferencesDialog());
        desktop.setQuitHandler((e, r) -> {
            if(!actionManager.getAction(ExitAction.class).exit()) {
                r.cancelQuit();
            } else {
                r.performQuit();
            }
        });
    }

    private void overrideUIDefaults() {
        Color lightGrey = new Color(0xEEEEEE);
        Color darkGrey  = new Color(225, 225, 225);
        Border darkBorder = BorderFactory.createLineBorder(darkGrey);

        UIManager.put("ToolBarSeparatorUI",           OSXToolBarSeparatorUI.class.getName());
        UIManager.put("PanelUI",                      OSXPanelUI.class.getName());
        // next two is custom-made for Cayenne's MainToolBar
        UIManager.put("ToolBar.background",           lightGrey);
        UIManager.put("MainToolBar.background",       lightGrey);
        UIManager.put("MainToolBar.border",           BorderFactory.createEmptyBorder(0, 7, 0, 7));
        UIManager.put("ToolBar.border",               darkBorder);
        UIManager.put("ScrollPane.border",            darkBorder);
        UIManager.put("Table.scrollPaneBorder",       darkBorder);
        UIManager.put("SplitPane.border",             BorderFactory.createEmptyBorder());
        UIManager.put("SplitPane.background",         darkGrey);
        UIManager.put("Tree.rendererFillBackground",  Boolean.TRUE);
        UIManager.put("ComboBox.background",          Color.WHITE);
        UIManager.put("ComboBox.selectionBackground", darkGrey);
        UIManager.put("ComboBox.selectionForeground", Color.BLACK);
        UIManager.put("Tree.selectionForeground",     Color.BLACK);
        UIManager.put("Tree.selectionBackground",     lightGrey);
        UIManager.put("Tree.selectionBorderColor",    lightGrey);
        UIManager.put("Table.selectionForeground",    Color.BLACK);
        UIManager.put("Table.selectionBackground",    lightGrey);
        UIManager.put("Table.focusCellHighlightBorder", BorderFactory.createEmptyBorder());
        UIManager.put("CheckBoxHeader.border",          BorderFactory.createEmptyBorder(0, 9, 0, 0));

        // MacOS BigSur needs additional style tweaking for the tabs active state
        OSXVersion version = OSXVersion.fromSystemProperties();
        if(version.gt(OSXVersion.CATALINA)) {
            UIManager.put("TabbedPane.selectedTabTitlePressedColor", Color.BLACK);
            UIManager.put("TabbedPane.selectedTabTitleNormalColor", Color.BLACK);
            UIManager.put("TabbedPane.selectedTabTitleShadowDisabledColor", new Color(0, 0, 0, 0));
            UIManager.put("TabbedPane.selectedTabTitleShadowNormalColor", new Color(0, 0, 0, 0));
        }

        Border backgroundPainter = new AbstractBorder() {
            @Override
            public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
                g.setColor(lightGrey);
                g.fillRect(0, 0, width - 1, height - 1);
            }
        };
        UIManager.put("MenuItem.selectedBackgroundPainter", backgroundPainter);
        UIManager.put("MenuItem.selectionForeground",       Color.BLACK);
    }

    public void setupMenus(JFrame frame) {
        // set additional look and feel for the window
        frame.getRootPane().putClientProperty("apple.awt.brushMetalLook", Boolean.TRUE);

        Set<Action> removeActions = new HashSet<>();
        removeActions.add(actionManager.getAction(ExitAction.class));
        removeActions.add(actionManager.getAction(AboutAction.class));
        removeActions.add(actionManager.getAction(ConfigurePreferencesAction.class));

        JMenuBar menuBar = frame.getJMenuBar();
        for (Component menu : menuBar.getComponents()) {
            if (menu instanceof JMenu) {
                JMenu jMenu = (JMenu) menu;

                Component[] menuItems = jMenu.getPopupMenu().getComponents();
                for (int i = 0; i < menuItems.length; i++) {

                    if (menuItems[i] instanceof JMenuItem) {
                        JMenuItem jMenuItem = (JMenuItem) menuItems[i];

                        if (removeActions.contains(jMenuItem.getAction())) {
                            jMenu.remove(jMenuItem);

                            // this algorithm is pretty lame, but it works for
                            // the current (as of 08.2010) menu layout
                            if (i > 0
                                    && i == menuItems.length - 1
                                    && menuItems[i - 1] instanceof JPopupMenu.Separator) {
                                jMenu.remove(i - 1);
                            }
                        }
                    }
                }
            }
        }
    }
}
