package org.limewire.ui.swing.advanced.connection;

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.BorderFactory;
import javax.swing.JPopupMenu;
import javax.swing.Timer;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;

/**
 * A manager for a popup window.  PopupManager is associated with a 
 * PopupProvider that supplies the content for the popup window. 
 */
public class PopupManager {
    private static final int POPUP_DURATION = 4000;
    
    private final PopupProvider popupProvider;
    private JPopupMenu popup;
    private Timer exitTimer;

    /**
     * Constructs a PopupManager with the specified popup content provider.
     */
    public PopupManager(PopupProvider popupProvider) {
        this.popupProvider = popupProvider;
    }

    /**
     * Displays a popup window over the specified owner component.  The 
     * specified location is relative to the component origin.  The popup is 
     * automatically dismissed after four seconds, or when the popup is
     * clicked. 
     */
    public void showTimedPopup(Component owner, int x, int y) {
        // Get popup content.
        Component content = popupProvider.getPopupContent();
        
        if ((popup == null) && (content != null)) {
            // Add listener to dismiss popup on mouse click.
            content.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    hidePopup();
                }
            });

            // Create popup and display.
            popup = createPopup(content);
            popup.show(owner, x, y);
            
            // Start timer to hide popup.
            startExitTimer();
        }
    }
    
    /**
     * Hides the popup window.
     */
    public void hidePopup() {
        // Hide existing popup and reset.
        if (popup != null) {
            popup.setVisible(false);
            popup = null;
        }
        
        // Stop exit timer.
        stopExitTimer();
    }
    
    /**
     * Creates a popup window containing the specified component.
     */
    private JPopupMenu createPopup(Component component) {
        // Create popup.  We only display the border for the popup component,
        // so we remove it from the popup container.
        JPopupMenu popupMenu = new JPopupMenu();
        popupMenu.setBorder(BorderFactory.createEmptyBorder());
        popupMenu.setFocusable(false);
        popupMenu.add(component);
        
        // Add listener to clear reference when popup is hidden.
        popupMenu.addPopupMenuListener(new PopupMenuListener() {
            @Override
            public void popupMenuCanceled(PopupMenuEvent e) {
            }
            @Override
            public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
                popup = null;
            }
            @Override
            public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
            }
        });
        
        return popupMenu;
    }
    
    /**
     * Starts the timer to hide the popup window.
     */
    private void startExitTimer() {
        // Stop existing timer.
        stopExitTimer();

        // Create new timer to hide popup.
        exitTimer = new Timer(POPUP_DURATION, new ActionListener() {
            @Override
			public void actionPerformed(ActionEvent e) {
                hidePopup();
            }
        });
        
        // Start timer.
        exitTimer.start();
    }
    
    /**
     * Stops the timer to hide the popup window.
     */
    private void stopExitTimer() {
        if (exitTimer != null) {
            exitTimer.stop();
            exitTimer = null;
        }
    }
    
    /**
     * Defines a component that provides content for a popup window. 
     */
    public static interface PopupProvider {
        /**
         * Returns the content for a popup window. 
         */
        public Component getPopupContent();
    }
}
