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

import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

import org.jdesktop.application.Resource;
import org.limewire.core.api.library.SharedFileList;
import org.limewire.friend.api.FriendConnectionEvent;
import org.limewire.friend.api.FriendEvent;
import org.limewire.friend.api.FriendConnectionEvent.Type;
import org.limewire.inject.LazySingleton;
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.friends.login.AutoLoginService;
import org.limewire.ui.swing.settings.SwingUiSettings;
import org.limewire.ui.swing.util.GuiUtils;

import ca.odell.glazedlists.event.ListEvent;
import ca.odell.glazedlists.event.ListEventListener;

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

/**
 * The panel in all shared lists that contains either the login view, the list
 * of friends the list is shared with, or a way of editing the list of friends.
 */
@LazySingleton
public class LibrarySharingPanel {

    /**
     * Property string for whether the sharing panel is in edit
     * mode or not.
     */
    public static final String EDIT_MODE = "EDIT_MODE";
    
    @Resource private Color backgroundColor;
    @Resource private Color borderColor;
    
    private static final String LOGIN_VIEW = "LOGIN_VIEW";
    private static final String EDITABLE_VIEW = "EDITABLE_VIEW";
    private static final String FRIEND_LIST_VIEW = "FRIEND_LIST_VIEW";
    
    private final Provider<LibrarySharingLoginPanel> loginPanelProvider;
    private final Provider<LibrarySharingFriendListPanel> friendListPanelProvider;
    private final Provider<LibrarySharingEditablePanel> editablePanelProvider;
    private final Provider<AutoLoginService> autoLoginServiceProvider;
    
    // these are all lazily created.
    private LibrarySharingLoginPanel loginPanel;
    private LibrarySharingFriendListPanel friendListPanel;
    private LibrarySharingEditablePanel editablePanel;
    
    private final JPanel component;    
    private final CardLayout layout = new CardLayout();    
    private final Map<String, JComponent> layoutMap = new HashMap<String, JComponent>();
    
    private final EventBean<FriendConnectionEvent> connectionEvent;
    private final ListEventListener<String> friendsListener;
    
    private enum View { NONE, LOGIN, FRIEND_LIST, EDIT_LIST }
    private View currentView = View.NONE;
    
    private SharedFileList currentList;
    
    @Inject
    public LibrarySharingPanel(Provider<LibrarySharingLoginPanel> loginPanel,
            Provider<LibrarySharingFriendListPanel> nonEditablePanel,
            Provider<LibrarySharingEditablePanel> editablePanel,
            EventBean<FriendConnectionEvent> connectionEvent,
            Provider<AutoLoginService> autoLoginServiceProvider) {
        this.loginPanelProvider = loginPanel;
        this.friendListPanelProvider = nonEditablePanel;
        this.editablePanelProvider = editablePanel;
        this.connectionEvent = connectionEvent;
        this.friendsListener = new FriendsListener();
        this.autoLoginServiceProvider = autoLoginServiceProvider;
                
        GuiUtils.assignResources(this);
        
        component = new JPanel();
        component.setMaximumSize(new Dimension(134, Integer.MAX_VALUE));
        component.setBackground(backgroundColor);
        component.setVisible(false);        
        component.setBorder(BorderFactory.createMatteBorder(0,0,0,1, borderColor));               
        component.setLayout(layout);
    }
    
    @Inject void register(ListenerSupport<FriendConnectionEvent> connectionEvent,
                          @Named("known") ListenerSupport<FriendEvent> friendSupport) {
        connectionEvent.addListener(new EventListener<FriendConnectionEvent>() {
            @Override
            @SwingEDTEvent
            public void handleEvent(FriendConnectionEvent event) {
                if(component.isVisible()) {
                    if(!isLoggedIn()) {
                        showLoginView();
                    } else if(currentView == View.LOGIN) {
                        if(SwingUiSettings.SHOW_SHARING_OVERLAY_MESSAGE.getValue()) {
                            showEditableView();
                        } else {
                            showFriendListView();
                        }
                    }
                }
            }
        });
        
        friendSupport.addListener(new EventListener<FriendEvent>() {
            @Override
            @SwingEDTEvent
            public void handleEvent(FriendEvent event) {
                if(currentView == View.EDIT_LIST) {
                    editablePanel.refreshSelectedList();
                }
            }
        });
    }
    
    void showLoginView() {
        if(!layoutMap.containsKey(LOGIN_VIEW)) {
            loginPanel = loginPanelProvider.get();
            JComponent newComponent = loginPanel.getComponent();
            component.add(newComponent, LOGIN_VIEW);
            layoutMap.put(LOGIN_VIEW, newComponent);
        }         
        currentView = View.LOGIN;
        loginPanel.setLoggingIn(isLoggingIn());
        sharesChanged();
        getComponent().firePropertyChange(EDIT_MODE, true, false);
        layout.show(component, LOGIN_VIEW);
    }
    
    void showEditableView() {
        if(!layoutMap.containsKey(EDITABLE_VIEW)) {
            editablePanel = editablePanelProvider.get();
            JComponent newComponent = editablePanel.getComponent();
            component.add(newComponent, EDITABLE_VIEW);
            layoutMap.put(EDITABLE_VIEW, newComponent);
        }         
        currentView = View.EDIT_LIST;
        editablePanel.editWithSelectedIds(currentList.getFriendIds());
        getComponent().firePropertyChange(EDIT_MODE, false, true);
        layout.show(component, EDITABLE_VIEW);
    }
    
    void showFriendListView() {
        if(!layoutMap.containsKey(FRIEND_LIST_VIEW)) {
            friendListPanel = friendListPanelProvider.get();
            JComponent newComponent = friendListPanel.getComponent();
            component.add(newComponent, FRIEND_LIST_VIEW);
            layoutMap.put(FRIEND_LIST_VIEW, newComponent);
        }
        currentView = View.FRIEND_LIST;
        sharesChanged();
        getComponent().firePropertyChange(EDIT_MODE, true, false);
        layout.show(component, FRIEND_LIST_VIEW);
    }

    /** Stops sharing the current list with any friends. */
    void stopSharing() {
        currentList.setFriendList(Collections.<String>emptyList());
    }
    
    /** Sets the new list of IDs that should be shared. */
    void setFriendIdsForSharing(List<String> friendIds) {
        currentList.setFriendList(friendIds);
    }
    
    private void sharesChanged() {
        if(currentList != null) {
            switch(currentView) {
            case FRIEND_LIST:
                friendListPanel.setSharedFriendIds(currentList.getFriendIds());
                break;
            case LOGIN:
                loginPanel.setSharedFriendIds(currentList.getFriendIds());
                break;
            }
        }
    }
    
    /** Sets a new backing SharedFileList that this sharing panel will use. */
    public void setSharedFileList(SharedFileList newList) {
        if(currentList != newList) {
            if(currentList != null) {
                currentList.getFriendIds().removeListEventListener(friendsListener);
            }
            currentList = newList;
            currentList.getFriendIds().addListEventListener(friendsListener); 
        } 
		// view may have changed based on sign out/sign in event
        if(isLoggedIn()) {
            if(SwingUiSettings.SHOW_SHARING_OVERLAY_MESSAGE.getValue()) {
                showEditableView();
            } else {
                showFriendListView();
            }
        } else {
            showLoginView();
        }
    }
    
    /**
	 * Enable the edit view if possible.
	 */
    public void showEditMode() {
        if(isLoggedIn()) {
            showEditableView();
        }
    }
    
    public JComponent getComponent() {
        return component;
    }
    
    private boolean isLoggedIn() {
        if(connectionEvent.getLastEvent() == null) {
            return false;
        } else {
            return connectionEvent.getLastEvent().getType() == Type.CONNECTED;
        }
    }
    
    private boolean isLoggingIn() {
        if (autoLoginServiceProvider.get().isAttemptingLogin()) {
            return true;
        }
        
        if(connectionEvent.getLastEvent() == null) {
            return false;
        } else {
            return connectionEvent.getLastEvent().getType() == Type.CONNECTING;
        }
    }
    
    private class FriendsListener implements ListEventListener<String> {
        @Override
        public void listChanged(final ListEvent<String> listChanges) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
				public void run() {
                    sharesChanged();
                }
            });
        }
    }
}
