package org.limewire.ui.swing.filter;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.ListCellRenderer;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.ScrollPaneConstants;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;

import org.jdesktop.swingx.JXList;
import org.jdesktop.swingx.decorator.ColorHighlighter;
import org.jdesktop.swingx.decorator.HighlightPredicate;
import org.limewire.ui.swing.components.RolloverCursorListener;
import org.limewire.ui.swing.filter.AbstractFilter.FilterResources;
import org.limewire.ui.swing.util.I18n;

/**
 * Display panel for filter popup window.  This is used by PropertyFilter to 
 * display the "more" popup, and SourceFilter to display the "friend" popup.
 */
class FilterPopupPanel extends JPanel {
    private static final int MAX_VISIBLE_ROWS = 18;
    
    private final JPanel titlePanel = new JPanel();
    private final JLabel titleLabel = new JLabel();
    private final JButton closeButton = new JButton();
    private final JXList list = new JXList();
    private final JScrollPane scrollPane = new JScrollPane();
    private final JPopupMenu popupMenu = new JPopupMenu();
    
    private boolean popupReady;
    private boolean popupTriggered;
    
    /**
     * Constructs a FilterPopupPanel with the specified resources and title
     * text.
     */
    public FilterPopupPanel(FilterResources resources, String titleText) {
        
        setBorder(BorderFactory.createLineBorder(resources.getPopupBorderColor(), 2));
        setLayout(new BorderLayout());
        
        titlePanel.setBackground(resources.getPopupHeaderBackground());
        titlePanel.setBorder(BorderFactory.createEmptyBorder(1, 3, 1, 1));
        titlePanel.setLayout(new BorderLayout());
        
        titleLabel.setForeground(resources.getPopupHeaderForeground());
        titleLabel.setFont(resources.getPopupHeaderFont());
        titleLabel.setText(I18n.tr("All {0}", titleText));
        
        closeButton.setBorder(BorderFactory.createEmptyBorder(0, 3, 3, 3));
        closeButton.setContentAreaFilled(false);
        closeButton.setForeground(resources.getPopupHeaderForeground());
        closeButton.setIcon(resources.getPopupCloseIcon());
        closeButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                hidePopup();
            }
        });
        
        // Add listener to show cursor on mouse over.
        new RolloverCursorListener().install(closeButton);
        
        list.setFont(resources.getRowFont());
        list.setForeground(resources.getRowColor());
        list.setOpaque(false);
        list.setRolloverEnabled(true);
        list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        
        // Add highlighter for rollover.
        list.setHighlighters(new ColorHighlighter(HighlightPredicate.ROLLOVER_ROW,
                resources.getHighlightBackground(), resources.getHighlightForeground()));
        
        // Add listener to show cursor on mouse over.
        new RolloverCursorListener().install(list);
        
        scrollPane.setBorder(BorderFactory.createEmptyBorder());
        scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        scrollPane.setViewportView(list);
        
        popupMenu.setBorder(BorderFactory.createEmptyBorder());
        popupMenu.setFocusable(false);
        popupMenu.addPopupMenuListener(new PopupMenuListener() {
            @Override
            public void popupMenuCanceled(PopupMenuEvent e) {
            }

            @Override
            public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
                if (popupTriggered) {
                    popupReady = false;
                } else {
                    popupReady = true;
                }
            }

            @Override
            public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
                popupTriggered = true;
            }
        });
        
        add(titlePanel, BorderLayout.NORTH);
        add(scrollPane, BorderLayout.CENTER);
        titlePanel.add(titleLabel, BorderLayout.CENTER);
        titlePanel.add(closeButton, BorderLayout.EAST);
        popupMenu.add(this);
    }
    
    /**
     * Sets the cell renderer on the list.
     */
    public void setListCellRenderer(ListCellRenderer renderer) {
        list.setCellRenderer(renderer);
    }
    
    /**
     * Sets the data model on the list.
     */
    public void setListModel(ListModel model) {
        list.setModel(model);
    }
    
    /**
     * Sets the selection model on the list.
     */
    public void setListSelectionModel(ListSelectionModel selectionModel) {
        list.setSelectionModel(selectionModel);
    }
    
    /**
     * Returns true if the popup is ready to be displayed.  The return 
     * value will be false if the popup is about to be hidden due to a 
     * triggering event.  
     */
    public boolean isPopupReady() {
        return popupReady;
    }
    
    /**
     * Sets an indicator that determines whether the popup is ready to be 
     * displayed.
     */
    public void setPopupReady(boolean popupReady) {
        this.popupReady = popupReady;
    }
    
    /**
     * Sets an indicator that determines whether a triggering event is
     * about to occur that affects popup visibility.
     */
    public void setPopupTriggered(boolean popupTriggered) {
        this.popupTriggered = popupTriggered;
    }
    
    /**
     * Displays this panel in a popup window at the x,y position relative to
     * the specified invoker.
     */
    public void showPopup(Component invoker, int x, int y) {
        // Adjust popup list height.
        list.setVisibleRowCount(Math.min(list.getModel().getSize(), MAX_VISIBLE_ROWS));
        
        // Limit popup width.
        if (popupMenu.getPreferredSize().width > 275) {
            popupMenu.setPreferredSize(new Dimension(275, popupMenu.getPreferredSize().height));
        }
        
        // Display popup next to property label.  Coordinates are relative
        // to the invoker, so we adjust the horizontal position to align
        // with the list, and the vertical position to align with the 
        // filter label.
        popupMenu.show(invoker, x, y);
    }
    
    /**
     * Hides the popup window.
     */
    public void hidePopup() {
        popupMenu.setVisible(false);
    }
}
