package org.limewire.ui.swing.search;

import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;

import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;

import net.miginfocom.swing.MigLayout;

import org.jdesktop.application.Resource;
import org.limewire.core.api.library.RemoteLibraryManager;
import org.limewire.core.api.search.browse.BrowseSearch;
import org.limewire.core.api.search.browse.BrowseStatus.BrowseState;
import org.limewire.friend.api.Friend;
import org.limewire.friend.api.FriendConnectionEvent;
import org.limewire.friend.api.FriendConnectionEvent.Type;
import org.limewire.listener.EventBean;
import org.limewire.listener.EventListener;
import org.limewire.listener.ListenerSupport;
import org.limewire.listener.SwingEDTEvent;
import org.limewire.ui.swing.components.Disposable;
import org.limewire.ui.swing.components.HTMLLabel;
import org.limewire.ui.swing.components.HeaderBar;
import org.limewire.ui.swing.components.HyperlinkButton;
import org.limewire.ui.swing.components.MessageComponent;
import org.limewire.ui.swing.components.decorators.HeaderBarDecorator;
import org.limewire.ui.swing.components.decorators.MessageDecorator;
import org.limewire.ui.swing.friends.chat.ChatMediator;
import org.limewire.ui.swing.search.model.SearchResultsModel;
import org.limewire.ui.swing.util.GuiUtils;
import org.limewire.ui.swing.util.I18n;

import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.assistedinject.Assisted;

/**
 * Replaces the search results when a browse fails.  Must be disposed.
 */
public class BrowseFailedMessagePanel extends JPanel implements Disposable{

    @Resource private Font chatFont;
    @Resource private Color chatForeground;

    private final SearchResultsModel searchResultsModel;
    private final Provider<ChatMediator> chatMediator;
    private final EventBean<FriendConnectionEvent> connectionEventBean;
    private EventListener<FriendConnectionEvent> connectionListener;
    private ListenerSupport<FriendConnectionEvent> connectionSupport;
    private final RemoteLibraryManager remoteLibraryManager;
    private final Provider<MessageDecorator> messageDecoratorProvider;
    private final HeaderBarDecorator headerBarDecorator;
    
    private BrowseSearch browseSearch;
    
    private boolean isInitialized = false;

    private BrowseState state;

    private List<Friend> friends;

    @Inject
    public BrowseFailedMessagePanel(EventBean<FriendConnectionEvent> connectionEventBean, Provider<ChatMediator> chatMediator, RemoteLibraryManager remoteLibraryManager,
            Provider<MessageDecorator> messageDecoratorProvider, HeaderBarDecorator headerBarDecorator,
            @Assisted SearchResultsModel searchResultsModel) {
        GuiUtils.assignResources(this);
        this.connectionEventBean = connectionEventBean;
        this.chatMediator = chatMediator;
        this.searchResultsModel = searchResultsModel;
        this.remoteLibraryManager = remoteLibraryManager;
        this.messageDecoratorProvider = messageDecoratorProvider;
        this.headerBarDecorator = headerBarDecorator;
    }
    
    public void update(BrowseState state, BrowseSearch browseSearch, List<Friend> friends){
        this.state = state;
        this.browseSearch = browseSearch;
        this.friends = friends;
        if(!isInitialized){
            isInitialized = true;
            initialize();
        }
        updateLabel();
    }
    
    @Inject
    void registerListener(ListenerSupport<FriendConnectionEvent> connectionSupport) {
        
        this.connectionSupport = connectionSupport;
        //TODO: this should probably be handled in the BrowseSearch models eventually
        connectionListener = new EventListener<FriendConnectionEvent>() {
            @Override
            @SwingEDTEvent
            public void handleEvent(FriendConnectionEvent event) {
                if (isInitialized) {
                    updateLabel();
                    repaint();
                }
            }
        };
        
        connectionSupport.addListener(connectionListener);
    }
  
    private void initialize() {
        setLayout(new MigLayout("insets 0, gap 0, fill", "[]", "[][grow][grow]"));
    }
    
    private void updateLabel(){
        removeAll();
        add(createMessageComponent(getLabelText()), "pos 0.50al 0.4al");
        add(createBottomComponent(), "pos 1al 1al");
    }

    /**
     * Floating message in the FriendLibrary. This displays feedback to the user
     * as to what state their friend is in when no files are displayed.
     */
    private JComponent createMessageComponent(String text) {
        
        HeaderBar header = new HeaderBar(new JLabel(""));
        header.setLayout(new MigLayout("insets 0, gap 0!, novisualpadding, alignx 100%, aligny 100%"));
        header.setAlignmentX(Component.CENTER_ALIGNMENT);
        headerBarDecorator.decorateBasic(header);
        add(header, "growx, growy, wrap");       
        
        MessageComponent messageComponent = new MessageComponent();
        messageDecoratorProvider.get().decorateGrayMessage(messageComponent);

        JLabel message = new JLabel(text);
        messageComponent.decorateHeaderLabel(message);
        messageComponent.addComponent(message, hasRefresh() ? "" : "wrap");
       

        if (hasRefresh()) {
            HyperlinkButton refresh = new HyperlinkButton(I18n.tr("Retry"));
            refresh.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    BrowseFailedMessagePanel.this.setVisible(false);
                    new DefaultSearchRepeater(browseSearch, searchResultsModel).refresh();
                }
            });
            messageComponent.decorateHeaderLink(refresh);
            messageComponent.addComponent(refresh, "gapleft 5, wrap");
        }
        
        if(state == BrowseState.NO_FRIENDS_SHARING || state == BrowseState.OFFLINE){
            String subText = null;
            if (isUserOffline()) {
                if(state == BrowseState.NO_FRIENDS_SHARING){
                subText = I18n.tr("When you sign on to WireShare, your friends' files will appear here.");
                } else {//BrowseState.OFFLINE
                    subText = I18n.tr("When you sign on to WireShare, your friend's files will appear here.");
                }
            } else {
                subText = I18n.tr("When they sign on to WireShare and share with you, their files will appear here.");
            }
                
            JLabel subMessage = new JLabel(subText);
            messageComponent.decorateSubLabel(subMessage);            
            messageComponent.addComponent(subMessage, "");
        }
        
        return messageComponent;
    }
    
    private boolean hasRefresh(){
        return state != BrowseState.OFFLINE && state != BrowseState.NO_FRIENDS_SHARING;
    }
    
    private JComponent createBottomComponent(){
        if(state == BrowseState.NO_FRIENDS_SHARING && !isUserOffline()){  
            String text;
            if(areFriendsSignedOnToLimeWire()){
                text = I18n.tr("<HTML><A href=\"\">Chat</A> and tell them to share.</HTML>");
            } else {
                text = I18n.tr("<HTML><A href=\"\">Chat</A> and tell them to sign on.</HTML>");
            }
            
            HTMLLabel message = new HTMLLabel(text);           
            message.setHtmlFont(chatFont);
            message.setHtmlForeground(chatForeground);
            message.addHyperlinkListener(new HyperlinkListener(){
                @Override
                public void hyperlinkUpdate(HyperlinkEvent e) {
                    if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
                        chatMediator.get().setVisible(true);
                    }
                }
            });
            
            JPanel panel = new JPanel(new MigLayout("insets 0, gap 0, novisualpadding"));
            panel.add(message, "gapright 5");
            return panel;
        }
        return new JLabel();
    }


    private String getLabelText() {
        if (isUserOffline()
                && (state == BrowseState.NO_FRIENDS_SHARING || state == BrowseState.OFFLINE)) {
            return getUserOfflineText();
        }

        if (state == BrowseState.NO_FRIENDS_SHARING) {
            if (areFriendsSignedOnToLimeWire()){
                return I18n.tr("No friends are sharing with you");
            } 
            return I18n.tr("No friends are on WireShare");
        }
        
        if (state == BrowseState.OFFLINE) {
            if (isSingleBrowse()) {
                return I18n.tr("{0} is not signed on to WireShare.", getSingleFriendName());
            } else {
                return I18n.tr("These people are not signed on to WireShare.");
            }
        }

        if (isSingleBrowse()) {
            return I18n.tr("There was a problem browsing {0}.", getSingleFriendName());
        } else {
            return I18n.tr("There was a problem viewing these people.");
        }

    }

    private boolean isUserOffline(){
        return connectionEventBean.getLastEvent() == null || connectionEventBean.getLastEvent().getType() != Type.CONNECTED;
    }
    
    private boolean isSingleBrowse(){
        return friends.size() == 1;
    }   
    
    public boolean areFriendsSignedOnToLimeWire(){
        return remoteLibraryManager.getFriendLibraryList().size() != 0;
    }
    
    
    private String getSingleFriendName(){
        return friends.get(0).getRenderName();
    }
    
    private String getUserOfflineText(){
        return I18n.tr("You are offline.");
    }

    @Override
	public void dispose() {
        if (connectionSupport != null) {
            connectionSupport.removeListener(connectionListener);
        }
    }

}
