/*
 * jNPad v0.3 - jNPad's an Simple Text Editor written in Java
 *
 * Copyright (C) 2014-2017  rgs
 *
 * Require JDK 1.6 (or later)
 *
 * 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 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.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 *
 *
 * Info, Questions, Suggestions & Bugs Report to rgsevero@gmail.com
 */

package jnpad.ui.plaf;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;

import javax.swing.ButtonModel;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.UIManager;
import javax.swing.event.MouseInputListener;
import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicGraphicsUtils;
import javax.swing.plaf.basic.BasicMenuUI;

import jnpad.GUIUtilities;

/**
 * The Class JNPadMenuUI.
 *
 * @version 0.3
 * @since   jNPad v0.1
 */
public final class JNPadMenuUI extends BasicMenuUI {
  private static Color miBg;
  private static Color miFg;
  private static Color borderColor;
  private static Color topLevelMenuBg;

  /**
   * 
   * @param x JComponent
   * @return ComponentUI
   */
  public static ComponentUI createUI(JComponent x) {
    return new JNPadMenuUI();
  }

  /**
   * 
   * @param c JComponent
   * @return MouseInputListener 
   * @see javax.swing.plaf.basic.BasicMenuUI#createMouseInputListener(javax.swing.JComponent)
   */
  @Override
  protected MouseInputListener createMouseInputListener(JComponent c) {
    return new UMouseInputHandler();
  }

  /**
   * 
   * @param g Graphics
   * @param menuItem JMenuItem
   * @param bgColor Color
   * @see javax.swing.plaf.basic.BasicMenuItemUI#paintBackground(java.awt.Graphics, javax.swing.JMenuItem, java.awt.Color)
   */
  @Override
  protected void paintBackground(Graphics g, JMenuItem menuItem, Color bgColor) {
    ButtonModel model = menuItem.getModel();
    Color oldColor = g.getColor();
    int menuWidth = menuItem.getWidth();
    int menuHeight = menuItem.getHeight();

    if (((menuItem instanceof JMenu)) && (((JMenu) menuItem).isTopLevelMenu())) {
      paintTopLevelBackground(g, menuItem, bgColor);
      return;
    }

    if (menuItem.isOpaque()) {
      if (model.isArmed() || (menuItem instanceof JMenu && model.isSelected())) {
        g.setColor(bgColor);
        g.fillRect(0, 0, menuWidth, menuHeight);
      }
      else {
        g.setColor(miBg());
        g.fillRect(0, 0, menuWidth, menuHeight);
      }
      g.setColor(oldColor);
    }
    else if (model.isArmed() || (menuItem instanceof JMenu && model.isSelected())) {
      g.setColor(bgColor);
      g.fillRect(0, 0, menuWidth, menuHeight);
      g.setColor(oldColor);
    }
  }

  /**
   * 
   * @param g Graphics
   * @param menuItem JMenuItem
   * @param bgColor Color
   */
  protected void paintTopLevelBackground(Graphics g, JMenuItem menuItem, Color bgColor) {
    ButtonModel model = menuItem.getModel();
    Color oldColor = g.getColor();
    int menuWidth = menuItem.getWidth();
    int menuHeight = menuItem.getHeight();

    if (model.isRollover() && !model.isSelected()) {
      g.setColor(topLevelMenuBg());
      g.fillRect(0, 0, menuWidth, menuHeight);
      GUIUtilities.drawBorder(g, borderColor(), 0, 0, menuWidth, menuHeight);
      g.setColor(oldColor);
    }
    else if (model.isSelected()) {
      g.setColor(miBg());
      g.fillRect(0, 0, menuWidth, menuHeight);
      g.setColor(borderColor());
      paintTopLevelSelectedBox(g, menuItem);
      g.setColor(oldColor);
    }
    else {
      super.paintBackground(g, menuItem, bgColor);
    }
  }

  /**
   * 
   * @param g Graphics
   * @param menuItem JMenuItem
   */
  private void paintTopLevelSelectedBox(Graphics g, JMenuItem menuItem) {
    Point point = getPopupMenuOrigin();
    int menuWidth = menuItem.getWidth();
    int menuHeight = menuItem.getHeight();

    if (point.getY() >= 0) {
      g.drawLine(0, 0, menuWidth - 1, 0);
      g.drawLine(menuWidth - 1, 0, menuWidth - 1, menuHeight - 1);
      g.drawLine(0, 0, 0, menuWidth - 1);
    }
    else {
      g.drawLine(menuWidth - 1, 0, menuWidth - 1, menuHeight - 1);
      g.drawLine(0, 0, 0, menuWidth - 1);
      g.drawLine(menuWidth - 1, menuHeight - 1, 0, menuHeight - 1);
    }
  }

  /**
   * 
   * @return Point
   */
  protected Point getPopupMenuOrigin() {
    JMenu menu = (JMenu) menuItem;
    JPopupMenu popupMenu = menu.getPopupMenu();

    Dimension dim1 = menu.getSize();
    Dimension dim2 = popupMenu.getSize();
    if (dim2.width == 0)
      dim2 = popupMenu.getPreferredSize();

    Point point = menu.getLocationOnScreen();
    Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();

    int x, y;

    if (menu.getParent() instanceof JPopupMenu) {
      int mspox = UIManager.getInt("Menu.submenuPopupOffsetX"); //$NON-NLS-1$
      int mspoy = UIManager.getInt("Menu.submenuPopupOffsetY"); //$NON-NLS-1$
      x = dim1.width + mspox;
      if (point.x + x + dim2.width >= dim.width && dim.width - dim1.width < 2 * point.x)
        x = 0 - mspox - dim2.width;
      y = mspoy;
      if (point.y + y + dim2.height >= dim.height && dim.height - dim1.height < 2 * point.y)
        y = dim1.height - mspoy - dim2.height;
    }
    else {
      int mmpox = UIManager.getInt("Menu.menuPopupOffsetX"); //$NON-NLS-1$
      int mmpoy = UIManager.getInt("Menu.menuPopupOffsetY"); //$NON-NLS-1$
      x = mmpox;
      if (point.x + x + dim2.width >= dim.width && dim.width - dim1.width < 2 * point.x)
        x = dim1.width - mmpox - dim2.width;
      y = dim1.height + mmpoy;
      if (point.y + y + dim2.height >= dim.height && dim.height - dim1.height < 2 * point.y)
        y = 0 - mmpoy - dim2.height;
    }
    return new Point(x, y);
  }

  /**
   * 
   * @param g Graphics
   * @param menuItem JMenuItem
   * @param textRect Rectangle
   * @param text String
   * @see javax.swing.plaf.basic.BasicMenuItemUI#paintText(java.awt.Graphics, javax.swing.JMenuItem, java.awt.Rectangle, java.lang.String)
   */
  @Override
  protected void paintText(Graphics g, JMenuItem menuItem, Rectangle textRect, String text) {
    ButtonModel model = menuItem.getModel();
    FontMetrics fm = g.getFontMetrics();
    int mnemIndex = menuItem.getDisplayedMnemonicIndex();

    if (!model.isEnabled()) {
      // *** paint the text disabled
      if (UIManager.get("MenuItem.disabledForeground") instanceof Color) { //$NON-NLS-1$
        g.setColor(UIManager.getColor("MenuItem.disabledForeground")); //$NON-NLS-1$
        BasicGraphicsUtils.drawStringUnderlineCharAt(g, text, mnemIndex,
                                                     textRect.x,
                                                     textRect.y + fm.getAscent());
      }
      else {
        g.setColor(menuItem.getBackground().brighter());
        BasicGraphicsUtils.drawStringUnderlineCharAt(g, text, mnemIndex,
                                                     textRect.x,
                                                     textRect.y + fm.getAscent());
        g.setColor(menuItem.getBackground().darker());
        BasicGraphicsUtils.drawStringUnderlineCharAt(g, text, mnemIndex,
                                                     textRect.x - 1,
                                                     textRect.y + fm.getAscent() - 1);
      }
    }
    else {
      // *** paint the text normally
      if (model.isArmed() || (menuItem instanceof JMenu && model.isSelected())) {
        if (!((JMenu) menuItem).isTopLevelMenu()) {
          g.setColor(selectionForeground); // Uses protected field.
        }
        else {
          g.setColor(miFg()); // Uses protected field.
        }
      }
      BasicGraphicsUtils.drawStringUnderlineCharAt(g, text, mnemIndex,
                                                   textRect.x,
                                                   textRect.y + fm.getAscent());
    }
  }

  /**
   * Update.
   *
   * @param g Graphics
   * @param c JComponent
   * @see javax.swing.plaf.basic.BasicMenuItemUI#update(java.awt.Graphics, javax.swing.JComponent)
   */
  @Override
  public void update(Graphics g, JComponent c) {
    JMenu menu = (JMenu) c;
    if (menu.isTopLevelMenu()) {
      menu.setOpaque(false);
    }
    else {
      menuItem.setBorderPainted(false);
      menuItem.setOpaque(false);
    }
    super.update(g, c);
  }

  /**
   * Top level menu bg.
   *
   * @return the color
   */
  static Color topLevelMenuBg() {
    if (topLevelMenuBg == null) {
      Color color = UIManager.getColor("MenuItem.background"); //$NON-NLS-1$
      topLevelMenuBg = new ColorUIResource(Math.max(color.getRed() - 50, 0),
                                           Math.max(color.getGreen() - 50, 0),
                                           Math.max(color.getBlue() - 50, 0));
    }
    return topLevelMenuBg;
  }

  /**
   * bg.
   *
   * @return the color
   */
  private static Color miBg() {
    if (miBg == null)
      miBg = UIManager.getColor("MenuItem.background"); //$NON-NLS-1$
    return miBg;
  }

  /**
   * fg.
   *
   * @return the color
   */
  private static Color miFg() {
    if (miBg == null)
      miFg = UIManager.getColor("MenuItem.foreground"); //$NON-NLS-1$
    return miFg;
  }

  /**
   * Border color.
   *
   * @return the color
   */
  private static Color borderColor() {
    if (borderColor == null) {
      borderColor = LAFUtils.isDarkLAF() ? JNPadLightMetalTheme.GRAY : JNPadLightMetalTheme.DARK_GRAY;
    }
    return borderColor;
  }
  
  //////////////////////////////////////////////////////////////////////////////
  /**
   * The Class UMouseInputHandler.
   */
  protected class UMouseInputHandler extends BasicMenuUI.MouseInputHandler {
    /**
     * 
     * @param evt MouseEvent 
     * @see javax.swing.plaf.basic.BasicMenuUI.MouseInputHandler#mouseEntered(java.awt.event.MouseEvent)
     */
    @Override
    public void mouseEntered(MouseEvent evt) {
      super.mouseEntered(evt);
      JMenu menu = (JMenu) evt.getSource();
      if (menu.isTopLevelMenu() /* && menu.isRolloverEnabled() */) {
        menu.getModel().setRollover(true);
        menuItem.repaint();
      }
    }

    /**
     * 
     * @param evt MouseEvent 
     * @see javax.swing.plaf.basic.BasicMenuUI.MouseInputHandler#mouseExited(java.awt.event.MouseEvent)
     */
    @Override
    public void mouseExited(MouseEvent evt) {
      super.mouseExited(evt);
      JMenu menu = (JMenu) evt.getSource();
      if (menu.isTopLevelMenu() /* && menu.isRolloverEnabled() */) {
        menu.getModel().setRollover(false);
        menuItem.repaint();
      }
    }
  }
  //////////////////////////////////////////////////////////////////////////////

}
