package org.limewire.ui.swing.downloads;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.table.TableCellEditor;

import org.jdesktop.application.Application;
import org.limewire.core.api.URN;
import org.limewire.core.api.download.DownloadItem;
import org.limewire.core.api.download.DownloadListManager;
import org.limewire.core.api.download.DownloadState;
import org.limewire.core.api.download.DownloadItem.DownloadItemType;
import org.limewire.inject.EagerSingleton;
import org.limewire.setting.evt.SettingEvent;
import org.limewire.setting.evt.SettingListener;
import org.limewire.ui.swing.downloads.table.DownloadTable;
import org.limewire.ui.swing.downloads.table.DownloadTableFactory;
import org.limewire.ui.swing.player.PlayerMediator;
import org.limewire.ui.swing.settings.SwingUiSettings;
import org.limewire.ui.swing.tray.Notification;
import org.limewire.ui.swing.tray.TrayNotifier;
import org.limewire.ui.swing.util.GuiUtils;
import org.limewire.ui.swing.util.I18n;
import org.limewire.ui.swing.util.SwingUtils;

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

/**
 * Container to display the Downloads table.
 * 
 * <p>Note: This is an EagerSingleton to ensure that register() is called and 
 * the listeners are in place at startup.</p>
 */
@EagerSingleton
public class MainDownloadPanel extends JPanel {  	
    
    public static final String NAME = "MainDownloadPanel";    
        
    private final DownloadMediator downloadMediator;
    private final Provider<DownloadTableFactory> downloadTableFactory;
    private final DownloadListManager downloadListManager;
    private final Provider<PlayerMediator> playerMediator;
    
    private TrayNotifier notifier;
    private boolean isInitialized = false;
    private DownloadTable table;
    
    
    /**
     * Create the panel.
     */
    @Inject
    public MainDownloadPanel(Provider<DownloadTableFactory> downloadTableFactory, 
            DownloadMediator downloadMediator,
            TrayNotifier notifier, 
            DownloadListManager downloadListManager,
            Provider<PlayerMediator> playerMediator) {
        this.downloadMediator = downloadMediator;
        this.downloadTableFactory = downloadTableFactory;
        this.downloadListManager = downloadListManager;
        this.playerMediator = playerMediator;
        this.notifier = notifier;

        GuiUtils.assignResources(this);
    }
    
    public void selectAndScrollTo(URN urn) {
        // its possible the table hasn't been initialized yet
        // after the first download starts
        if(table == null) {
            initialize();
        }
        table.selectAndScrollTo(urn);
    }

    
    @Inject
    public void register() {              
        // Add listener for "show downloads" setting.
        SwingUiSettings.SHOW_TRANSFERS_TRAY.addSettingListener(new SettingListener() {
            @Override
            public void settingChanged(SettingEvent evt) {
                SwingUtils.invokeNowOrLater(new Runnable() {
                    @Override
                    public void run() {
                        initialize();
                    }
                });
            } 
        });
        
        //we have to eagerly initialize the table when the SHOW_DOWNLOAD_TRAY setting
        //is set to true on startup, otherwise the table space will be empty and the lines will
        //be put in the first time a download comes in, which looks a little weird
        if (SwingUiSettings.SHOW_TRANSFERS_TRAY.getValue()) {
            initialize();
        }
        
        // Add listener for downloads added and completed.
        downloadListManager.addPropertyChangeListener(new DownloadPropertyListener());
    }
    
    //Lazily initialized - initialize() is called when the first downloadItem is added to the list.  
    private void initialize() {
        if(!isInitialized){
            isInitialized = true;
            setLayout(new BorderLayout());
    
            table = downloadTableFactory.get().create(downloadMediator.getDownloadList());
            table.setTableHeader(null);
            JScrollPane pane = new JScrollPane(table);
            pane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
            add(pane, BorderLayout.CENTER);
        }
    }
    
    public List<DownloadItem> getSelectedDownloadItems(){
        return table.getSelectedItems();
    }

    /**
     * Listener to handle download added/completed events from the download 
     * list manager.
     */
    private class DownloadPropertyListener implements PropertyChangeListener {
        @Override
		public void propertyChange(PropertyChangeEvent event) {
            if (event.getPropertyName().equals(DownloadListManager.DOWNLOAD_COMPLETED)) {
                final DownloadItem downloadItem = (DownloadItem) event.getNewValue();
                DownloadState state = downloadItem.getState();
                if(downloadItem.getDownloadItemType() == DownloadItemType.ANTIVIRUS) {
                    // Don't show a popup when an antivirus download completes
                } else {
                    notifier.showMessage(new Notification(I18n.tr("Download Complete"), downloadItem.getFileName(), 
                            new AbstractAction() {
                        @Override
                        public void actionPerformed(ActionEvent e) {
                            ActionMap map = Application.getInstance().getContext().getActionManager()
                            .getActionMap();
                            map.get("restoreView").actionPerformed(e);

                            if (downloadItem.isLaunchable()) {
                                DownloadItemUtils.launch(downloadItem, playerMediator);
                            }
                        }
                    }));
                }
                
                // For LWC-4733. It is possible with extremely small file
                // downloads that the download can complete before initialize()
                // is called. We are planning to refactor so that this won't
                // happen but this null check will prevent the NPE in the release.
                if(table == null) {
                    initialize();
                }

                // the user might be editing one of the cell's while the download completes,
                // i.e. the user might have the mouse hovering over the pause button. (Bug LWC-4317)
                // Let's manually cancel cell editing here after the download completes
                TableCellEditor editor = table.getCellEditor();
                if ( editor != null )
                {
                    editor.cancelCellEditing();
                }
            }
        }
    }
}
