package org.limewire.ui.swing.search;

import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

import net.miginfocom.swing.MigLayout;

import org.jdesktop.application.Resource;
import org.jdesktop.swingx.JXPanel;
import org.jdesktop.swingx.painter.Painter;
import org.limewire.core.api.search.SearchDetails.SearchType;
import org.limewire.core.api.search.browse.BrowseStatus;
import org.limewire.core.api.search.browse.BrowseStatus.BrowseState;
import org.limewire.friend.api.Friend;
import org.limewire.ui.swing.action.AbstractAction;
import org.limewire.ui.swing.components.Disposable;
import org.limewire.ui.swing.components.HyperlinkButton;
import org.limewire.ui.swing.components.IconButton;
import org.limewire.ui.swing.components.LimePopupDialog;
import org.limewire.ui.swing.friends.refresh.AllFriendsRefreshManager;
import org.limewire.ui.swing.friends.refresh.BrowseRefreshStatus;
import org.limewire.ui.swing.friends.refresh.BrowseRefreshStatusListener;
import org.limewire.ui.swing.painter.ComponentBackgroundPainter;
import org.limewire.ui.swing.painter.BorderPainter.AccentType;
import org.limewire.ui.swing.search.model.SearchResultsModel;
import org.limewire.ui.swing.util.GuiUtils;
import org.limewire.ui.swing.util.I18n;
/**
 * Shows status updates for browses.  Must be disposed.
 */
public class BrowseStatusPanel extends JXPanel implements Disposable{

    private BrowseStatus status;

    private JButton warningButton;
    private JXPanel refreshPanel;
    private JButton refreshButton;
    private JLabel updatesLabel;
    
    @Resource private Icon warningIcon;    
    @Resource private int arcWidth;
    @Resource private int arcHeight;
    @Resource private Color innerBorder;
    @Resource private Color innerBackground;
    @Resource private Color bevelLeft;
    @Resource private Color bevelTop1;
    @Resource private Color bevelTop2;
    @Resource private Color bevelRight;
    @Resource private Color bevelBottom;
    @Resource private Font font;
    @Resource private Color foreground;    
    @Resource private Color headerForeground;
    @Resource private Font headerFont;


    private final SearchResultsModel searchResultsModel;

    private final AllFriendsRefreshManager allFriendsRefreshManager;
    
    
    private BrowseRefreshStatusListener browseRefreshStatusListener;
    
    public BrowseStatusPanel(SearchResultsModel searchResultsModel, AllFriendsRefreshManager allFriendsRefreshManager){
        GuiUtils.assignResources(this);
        this.searchResultsModel = searchResultsModel;
        this.allFriendsRefreshManager = allFriendsRefreshManager;
        
        setOpaque(false);        
        initializeComponents();      
        if(isAllFriendsBrowse()){
            initializeAllFriendsListener();
        }
        layoutComponents();
        update();
    }
    
    private void initializeAllFriendsListener(){
        browseRefreshStatusListener = new BrowseRefreshStatusListener(){
            @Override
            public void statusChanged(final BrowseRefreshStatus status) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
					public void run() {
                        refreshPanel.setVisible(status != BrowseRefreshStatus.REFRESHED);                              
                    }
                });
            }            
        };
        allFriendsRefreshManager.addBrowseRefreshStatusListener(browseRefreshStatusListener);        
    }

    private void initializeComponents() {        
        warningButton = new IconButton(warningIcon);
        warningButton.addActionListener(new WarningAction());
        warningButton.setVisible(false);
        
        refreshPanel = new JXPanel();
        refreshPanel.setOpaque(false);
        refreshPanel.setBackgroundPainter(createRefreshBackgroundPainter());
        refreshPanel.setVisible(false);
        
        updatesLabel = new JLabel(I18n.tr("Update Available"));
        updatesLabel.setFont(font);
        updatesLabel.setForeground(foreground);
        
        refreshButton = new HyperlinkButton(new RefreshAction());
        refreshButton.setFont(font);
    }

    private void layoutComponents() {    
        refreshPanel.setLayout(new MigLayout("insets 6 8 6 8, gap 0, novisualpadding, aligny 50%, fill"));        
        
        refreshPanel.add(updatesLabel);
        refreshPanel.add(refreshButton, "gapleft 3");
        
        setLayout(new MigLayout("insets 0, gap 0, novisualpadding, filly"));
        add(warningButton);
        add(refreshPanel);
    }

    public void setBrowseStatus(BrowseStatus status) {
        this.status = status;
        update();
    }

    private void update() {
        if (!isAllFriendsBrowse()) {
            warningButton.setVisible(status != null && status.getState() == BrowseState.PARTIAL_FAIL);
            refreshPanel.setVisible(status != null && status.getState() == BrowseState.UPDATED);
        }
    }
    
    private void showFailedBrowses(){
        //TODO: present this properly
        List<String> friends = new ArrayList<String>();
        List<String> p2pUsers = new ArrayList<String>();
        
        for(Friend person : status.getFailedFriends()){
            if(person.isAnonymous()){
                p2pUsers.add(person.getRenderName());
            } else {
                friends.add(person.getRenderName());
            }            
        }
        
        JXPanel centerPanel = new JXPanel(new MigLayout("insets 0 5 5 5, gap 0, novisualpadding, fill"));
        if(friends.size() > 0){
            centerPanel.add(createHeaderLabel(I18n.tr("Friends")), "gaptop 5, wrap");
        }
        for (String name : friends){
            centerPanel.add(createItemLabel(name), "wrap");
        }
        
        if(p2pUsers.size() > 0){
            centerPanel.add(createHeaderLabel(I18n.tr("Users")), "gaptop 5, wrap");
        }
        for (String name : p2pUsers){
            centerPanel.add(createItemLabel(name), "wrap");
        }
        
        LimePopupDialog popup = new LimePopupDialog(I18n.tr("Unable to Browse"), centerPanel);
        popup.showPopup(warningButton, 0, 0);
    }
    
    private JLabel createHeaderLabel(String text){
        JLabel header = new JLabel(text);
        header.setForeground(headerForeground);
        header.setFont(headerFont);
        return header;
    }
    
    private JLabel createItemLabel(String text){
        JLabel item = new JLabel(text);
        item.setForeground(foreground);
        item.setFont(font);
        return item;
    }
    
    private Painter<JXPanel> createRefreshBackgroundPainter() {
        return new ComponentBackgroundPainter<JXPanel>(innerBackground, innerBorder, bevelLeft, bevelTop1, 
                bevelTop2, bevelRight,bevelBottom, arcWidth, arcHeight,
                AccentType.NONE);
    }
    
    private boolean isAllFriendsBrowse(){
        return searchResultsModel.getSearchType() == SearchType.ALL_FRIENDS_BROWSE;
    }
        
    private class RefreshAction extends AbstractAction {
        public RefreshAction(){
            super(I18n.tr("Refresh"));
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if(isAllFriendsBrowse()){
                allFriendsRefreshManager.refresh();
            } else {            
                new DefaultSearchRepeater(status.getBrowseSearch(), searchResultsModel).refresh();
            }
        }        
    }
  
    
    private class WarningAction extends AbstractAction {

        @Override
        public void actionPerformed(ActionEvent e) {
            showFailedBrowses();
        }        
    }


    @Override
    public void dispose() {
        if(browseRefreshStatusListener != null){        
            allFriendsRefreshManager.removeBrowseRefreshStatusListener(browseRefreshStatusListener);  
            browseRefreshStatusListener = null;
        }
    }
}
