/*
 * 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.toolbar;

import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.Serializable;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;
import javax.swing.event.MouseInputAdapter;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;

import jnpad.JNPadBundle;
import jnpad.ui.plaf.LAFUtils;
import jnpad.util.Utilities;

/**
 * The Class PopupToolBoxButton.
 *
 * @version 0.3
 * @since   jNPad v0.1
 */
public class PopupToolBoxButton extends ToolBarButton {
  private PopupToolBox           _popupToolBox;
  private Icon                   _standardIcon;
  private Icon                   _realIcon;
  private JButton                _button;
  private String                 _tooltip;
  private boolean                _showSplitter;
  private String                 _dropDownToolTip;
  private boolean                _popupMenuIsShowing;
  private boolean                _innerActionEnabled;
  private ActionListener         _actionListener;
  private Action                 _action;
  private PropertyChangeListener _actionPropertyChangeListener;

  /** Logger */
  private final static Logger    LOGGER           = Logger.getLogger(PopupToolBoxButton.class.getName());

  /** UID */
  private static final long      serialVersionUID = -577818802286323894L;
  
  /**
   * Instantiates a new popup tool box button.
   */
  public PopupToolBoxButton() {
    this(0, 1, true);
  }

  /**
   * Instantiates a new popup tool box button.
   *
   * @param rows int
   * @param cols int
   */
  public PopupToolBoxButton(int rows, int cols) {
    this(rows, cols, true);
  }

  /**
   * Instantiates a new popup tool box button.
   *
   * @param rows int
   * @param cols int
   * @param rollover boolean
   */
  public PopupToolBoxButton(int rows, int cols, boolean rollover) {
    _popupToolBox = new PopupToolBox(rows, cols, rollover);
    MouseHandler mouseHandler = new MouseHandler();
    addMouseMotionListener(mouseHandler);
    addMouseListener(mouseHandler);
    super.addActionListener(_actionListener = new ActionListenerImpl());
  }

  /**
   * Adds the action listener.
   *
   * @param l ActionListener
   * @see javax.swing.AbstractButton#addActionListener(java.awt.event.ActionListener)
   */
  @Override
  public void addActionListener(ActionListener l) {
    super.addActionListener(l);
    _innerActionEnabled = true;
  }

  /**
   * Adds the.
   *
   * @param button the button
   * @return the button
   */
  public JButton add(JButton button) {
    JButton toolbutton = (JButton) _popupToolBox.add(button);
    toolbutton.addActionListener(_actionListener);
    return toolbutton;
  }

  /**
   * Sets the default.
   *
   * @param button the new default
   */
  public void setDefault(JButton button) {
    _button  = button;

    // set tooltip
    _tooltip = _button.getToolTipText();
    if (Utilities.isEmptyString(_tooltip))
      _tooltip = _button.getText();
    setToolTipText(_tooltip);

    // set text
    String text = button.getText();
    if (text != null)
      setText(text);
    
    // set icon
    Icon icon = button.getIcon();
    if (icon != null)
      setIcon(button.getIcon());
    
    // set enabled
    setEnabled(button.isEnabled());
    
    // set margin
    setMargin(button.getMargin());

    // handle action
    if (_action != null && _actionPropertyChangeListener != null) {
      _action.removePropertyChangeListener(_actionPropertyChangeListener);
      _actionPropertyChangeListener = null;
    }
    _action = button.getAction();
    if (_action == null && button instanceof ToolBoxButton) {
      _action = ((ToolBoxButton) button)._action;
    }
    if (_action != null) {
      _action.addPropertyChangeListener(_actionPropertyChangeListener = new PropertyChangeListenerImpl());
    }
  }
  
  /**
   * Gets the default.
   *
   * @return the default
   */
  public JButton getDefault() {
    return _button;
  }

  /**
   * Sets the icon.
   *
   * @param icon Icon
   * @see javax.swing.AbstractButton#setIcon(javax.swing.Icon)
   */
  @Override
  public final void setIcon(Icon icon) {
    _realIcon = icon;
    if (icon != null && icon instanceof ImageIcon)
      super.setIcon(_standardIcon = new DropDownIcon( (ImageIcon) icon));
    else
      super.setIcon(icon);
  }

  /**
   * Paint.
   *
   * @param g Graphics
   * @see javax.swing.JComponent#paint(java.awt.Graphics)
   */
  @Override
  public void paint(Graphics g) {
    super.paint(g);
    try {
      if (_showSplitter) {
        boolean b = super.isEnabled();
        showSplitter(b ? LAFUtils.getControlDkShadow() : LAFUtils.getToolBarShadow(), g, getSplitterPosn(), 1, getHeight() - 4);
        showSplitter(b ? LAFUtils.getControlHighlight() : LAFUtils.getToolBarHighlight(), g, getSplitterPosn() + 1, 1, getHeight() - 4);
      }
    }
    catch (Exception ex) {
      LOGGER.log(Level.WARNING, ex.getMessage(), ex);
    }
  }

  /**
   * Gets the splitter posn.
   *
   * @return int
   */
  private int getSplitterPosn() {
    return getIconPosn() + _realIcon.getIconWidth() + 3;
  }

  /**
   * Gets the icon posn.
   *
   * @return int
   */
  private int getIconPosn() {
      return (getWidth() - _standardIcon.getIconWidth()) / 2;
  }

  /**
   * Sets the drop down tool tip.
   *
   * @param dropDownToolTip String
   */
  public void setDropDownToolTip(String dropDownToolTip) {
    _dropDownToolTip = dropDownToolTip;
  }

  /**
   * Show splitter.
   *
   * @param c Color
   * @param g Graphics
   * @param x int
   * @param y int
   * @param height int
   */
  private void showSplitter(Color c, Graphics g, int x, int y, int height) {
    g.setColor(c);
    g.drawLine(x, y, x, y + height);
  }

  /**
   * Show splitter.
   *
   * @param show boolean
   */
  private void showSplitter(boolean show) {
    if (show && !_showSplitter) {
      _showSplitter = true;
      repaint();
      String tooltip = null;
      Container parent = getParent();
      if (parent instanceof JComponent)
        tooltip = _dropDownToolTip;
      if (tooltip == null)
        tooltip = JNPadBundle.getString("PopupButton.select"); //$NON-NLS-1$
      setToolTipText(tooltip);
    }
    else if (!show && _showSplitter) {
      _showSplitter = false;
      repaint();
      setToolTipText(_tooltip);
    }
  }

  /**
   * Popup.
   */
  private void popup() {
    final JPopupMenu popupMenu = new JPopupMenu();

    PopupMenuListener pml = new PopupMenuListenerImpl();
    popupMenu.addPopupMenuListener(pml);

    final MouseAdapter m = (new MouseAdapter() {
      @Override
      public void mouseClicked(final MouseEvent e) {
        _popupMenuIsShowing = false;
        popupMenu.setVisible(false);
      }
    });
    
    _popupToolBox.setButtonMouseListener(m);
    _popupToolBox.rebuild();
    popupMenu.add(_popupToolBox);
    SwingUtilities.updateComponentTreeUI(popupMenu);
    popupMenu.show(this, 0, getHeight());

    _popupMenuIsShowing = true;
  }

  /**
   * Update ui.
   *
   * @see javax.swing.JButton#updateUI()
   */
  @Override
  public void updateUI() {
    super.updateUI();
    try {
      SwingUtilities.updateComponentTreeUI(_popupToolBox);
    }
    catch (Exception ex) {
      //ignored
    }
  }

  /**
   * Fire action performed.
   *
   * @param event ActionEvent
   * @see javax.swing.AbstractButton#fireActionPerformed(java.awt.event.ActionEvent)
   */
  @Override
  protected void fireActionPerformed(ActionEvent event) {
    if (_showSplitter) {
      if (!_popupMenuIsShowing)
        popup();
    }
    else {
      super.fireActionPerformed(event);
    }
  }

  //////////////////////////////////////////////////////////////////////////////
  /**
   * The Class PopupMenuListenerImpl.
   */
  private class PopupMenuListenerImpl implements PopupMenuListener {
    /**
     * Popup menu canceled.
     *
     * @param e the PopupMenuEvent
     * @see javax.swing.event.PopupMenuListener#popupMenuCanceled(javax.swing.event.PopupMenuEvent)
     */
    @Override
    public void popupMenuCanceled(PopupMenuEvent e) {
      _popupMenuIsShowing = false;
    }

    /**
     * Popup menu will become invisible.
     *
     * @param e the PopupMenuEvent
     * @see javax.swing.event.PopupMenuListener#popupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent)
     */
    @Override
    public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {/*empty*/}

    /**
     * Popup menu will become visible.
     *
     * @param e the PopupMenuEvent
     * @see javax.swing.event.PopupMenuListener#popupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent)
     */
    @Override
    public void popupMenuWillBecomeVisible(PopupMenuEvent e) {/*empty*/}
  }
  //////////////////////////////////////////////////////////////////////////////

  //////////////////////////////////////////////////////////////////////////////
  /**
   * The Class ActionListenerImpl.
   */
  private class ActionListenerImpl implements ActionListener, Serializable { // Serializable keep FindBugs happy 
    /** UID */
    private static final long serialVersionUID = -8814455331658962299L;

    /**
     * Action performed.
     *
     * @param e the ActionEvent
     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
     */
    @Override
    public void actionPerformed(ActionEvent e) {
      Object obj = e.getSource();
      if (!_innerActionEnabled) {
        if (obj == PopupToolBoxButton.this) {
          if (_button != null && _button != obj) {
            ActionListener[] listeners = _button.getActionListeners();
            for (ActionListener listener : listeners) {
              listener.actionPerformed(new ActionEvent(_button, 
                                                       e.getID(), 
                                                       e.getActionCommand(), 
                                                       e.getWhen(), 
                                                       e.getModifiers()));
            }
          }
        }
        else if (obj instanceof JButton) {
          setDefault( (JButton) obj);
        }
      }
    }
  }
  //////////////////////////////////////////////////////////////////////////////

  //////////////////////////////////////////////////////////////////////////////
  /**
   * The Class MouseHandler.
   */
  private class MouseHandler extends MouseInputAdapter {
    /**
     * Mouse moved.
     *
     * @param e MouseEvent
     * @see java.awt.event.MouseAdapter#mouseMoved(java.awt.event.MouseEvent)
     */
    @Override
    public void mouseMoved(final MouseEvent e) {
      if (_standardIcon != null)
        showSplitter(e.getX() >= getSplitterPosn());
    }

    /**
     * Mouse entered.
     *
     * @param e MouseEvent
     * @see java.awt.event.MouseAdapter#mouseEntered(java.awt.event.MouseEvent)
     */
    @Override
    public void mouseEntered(final MouseEvent e) {
      if (_standardIcon != null)
        showSplitter(e.getX() >= getSplitterPosn());
    }

    /**
     * Mouse exited.
     *
     * @param e MouseEvent
     * @see java.awt.event.MouseAdapter#mouseExited(java.awt.event.MouseEvent)
     */
    @Override
    public void mouseExited(final MouseEvent e) {
      if (_standardIcon != null)
        showSplitter(false);
    }
  }
  //////////////////////////////////////////////////////////////////////////////

  //////////////////////////////////////////////////////////////////////////////
  /**
   * The Class PropertyChangeListenerImpl.
   */
  private class PropertyChangeListenerImpl implements PropertyChangeListener, Serializable { // Serializable keep FindBugs happy 
    /** UID */
    private static final long serialVersionUID = -276468994510092616L;

    /**
     * Property change.
     *
     * @param e PropertyChangeEvent
     * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
     */
    @Override
    public void propertyChange(final PropertyChangeEvent e) {
      if ("enabled".equals(e.getPropertyName())) { //$NON-NLS-1$
        setEnabled(((Boolean) e.getNewValue()).booleanValue());
      }
    }
  }
  //////////////////////////////////////////////////////////////////////////////

}// fin de PopupToolBoxButton
