package org.limewire.ui.swing.library.sharing;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;

import net.miginfocom.swing.MigLayout;

import org.jdesktop.application.Resource;
import org.jdesktop.swingx.JXTable;
import org.limewire.collection.glazedlists.GlazedListsFactory;
import org.limewire.friend.api.Friend;
import org.limewire.friend.api.FriendEvent;
import org.limewire.inject.LazySingleton;
import org.limewire.listener.EventListener;
import org.limewire.listener.ListenerSupport;
import org.limewire.listener.SwingEDTEvent;
import org.limewire.ui.swing.components.HyperlinkButton;
import org.limewire.ui.swing.table.GlazedJXTable;
import org.limewire.ui.swing.util.GuiUtils;
import org.limewire.ui.swing.util.I18n;

import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.SortedList;
import ca.odell.glazedlists.gui.TableFormat;
import ca.odell.glazedlists.impl.swing.SwingThreadProxyEventList;
import ca.odell.glazedlists.swing.DefaultEventTableModel;

import com.google.inject.Inject;
import com.google.inject.name.Named;

@LazySingleton
class LibrarySharingFriendListPanel {

    @Resource private Font labelFont;
    @Resource private Color labelColor;
    @Resource private Font linkFont;
    @Resource private Color backgroundColor;
    
    private final JPanel component;
    private final JLabel headerLabel;
    private final HyperlinkButton editButton;
    private final Map<String, Friend> knownFriends;
    private final List<String> sharedIds;
    
    private final LibrarySharingFriendListRenderer renderer;
    private final EventList<String> eventList;
    private final JXTable friendList;
    private final JScrollPane scrollPane;

    @Inject
    public LibrarySharingFriendListPanel(EditSharingAction sharingAction, @Named("known") Map<String, Friend> knownFriends) {
        GuiUtils.assignResources(this);
        this.knownFriends = knownFriends;        
        this.friendList = new GlazedJXTable();
        this.sharedIds = new ArrayList<String>();
        
        eventList = new BasicEventList<String>();
        SortedList<String> sortedList = GlazedListsFactory.sortedList(eventList, new FriendComparator());
        SwingThreadProxyEventList<String> stpl = GlazedListsFactory.swingThreadProxyEventList(sortedList);
        friendList.setModel(new DefaultEventTableModel<String>(stpl, new FriendTableFormat()));
        
        component = new JPanel(new MigLayout("insets 0, gap 0, fillx", "134!", ""));        
        component.setOpaque(false);
        
        headerLabel = new JLabel();
        headerLabel.setFont(labelFont);
        headerLabel.setForeground(labelColor);
        component.add(headerLabel, "aligny top, gaptop 8, gapleft 6, gapbottom 6, wrap");

        friendList.setTableHeader(null);
        friendList.setShowGrid(false, false);
        friendList.setFocusable(false);
        friendList.setBackground(backgroundColor);
        friendList.setRowHeight(36);
        
        scrollPane = new JScrollPane(friendList, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        scrollPane.setMinimumSize(new Dimension(0,0));
        scrollPane.setBorder(BorderFactory.createEmptyBorder(1,0,1,0));
        scrollPane.setBackground(backgroundColor);
        
        renderer = new LibrarySharingFriendListRenderer(scrollPane);
        friendList.getColumnExt(0).setCellRenderer(renderer);
       
        component.add(scrollPane, "grow, wrap");
        
        editButton = new HyperlinkButton(I18n.tr("Edit Sharing"), sharingAction);
        editButton.setFont(linkFont);
        component.add(editButton, "aligny top, gaptop 5, gapleft 6, gapbottom 5, wrap");
        
        scrollPane.getVerticalScrollBar().addComponentListener(new ComponentListener(){
            @Override
            public void componentHidden(ComponentEvent e) {
                scrollPane.setBorder(BorderFactory.createEmptyBorder(1,0,1,0));
            }

            @Override
            public void componentShown(ComponentEvent e) {
                scrollPane.setBorder(BorderFactory.createMatteBorder(1,0,1,0, Color.BLACK));
            }
            
            @Override
            public void componentMoved(ComponentEvent e) {}
            @Override
            public void componentResized(ComponentEvent e) {}
        });
    }
    
    @Inject void register(@Named("known") ListenerSupport<FriendEvent> friendSupport) {
        friendSupport.addListener(new EventListener<FriendEvent>() {
            @Override
            @SwingEDTEvent
            public void handleEvent(FriendEvent event) {
                switch(event.getType()) {
                case ADDED:
                    setSharedFriendIds(sharedIds);
                    break;
                }
            }
        });
    }
    
    void clear() {
        eventList.clear();
    }
    
    /** Sets the list of IDs this is shared with. */
    void setSharedFriendIds(List<String> newFriendIds) {
        if(!newFriendIds.isEmpty()) {
            headerLabel.setText(I18n.tr("Sharing list with..."));
        } else {
            headerLabel.setText(I18n.tr("Not Shared"));
        }
        
        // Only set if we're not refreshing..
        if(newFriendIds != sharedIds) {
            sharedIds.clear();
            sharedIds.addAll(new ArrayList<String>(newFriendIds));
        }
        
        List<String> newModel = new ArrayList<String>();
        int unknown = 0;
        for(String id : sharedIds) {
            Friend friend = knownFriends.get(id);
            if(friend != null) {
                newModel.add(friend.getRenderName());
            } else {
                unknown++;
            }
        }
        if(unknown > 0) {
            newModel.add(I18n.tr("{0} friends from other accounts", unknown));
            // TODO: Do something about row sizes.
            friendList.setRowHeightEnabled(true);            
        } else {
            friendList.setRowHeightEnabled(false);
        }
        eventList.clear();
        eventList.addAll(newModel);
        friendList.setVisibleRowCount(newModel.size());
        component.revalidate();
    }
    
    JComponent getComponent() {
        return component;
    }
    
    private static class FriendComparator implements Comparator<String> {
        @Override
        public int compare(String name1, String name2) {
            return name1.compareToIgnoreCase(name2);
        }
    }
    
    private static class FriendTableFormat implements TableFormat<String> {
        @Override
        public int getColumnCount() {
            return 1;
        }

        @Override
        public String getColumnName(int column) {
            return "";
        }

        @Override
        public Object getColumnValue(String baseObject, int column) {
            return baseObject;
        }       
    }
}
