package org.limewire.ui.swing.downloads.table.renderer;

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Collection;

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

import net.miginfocom.swing.MigLayout;

import org.jdesktop.application.Resource;
import org.limewire.core.api.download.DownloadItem;
import org.limewire.core.api.download.DownloadPropertyKey;
import org.limewire.core.api.download.DownloadState;
import org.limewire.core.api.download.DownloadItem.DownloadItemType;
import org.limewire.core.api.download.DownloadItem.ErrorState;
import org.limewire.core.api.endpoint.RemoteHost;
import org.limewire.core.api.malware.AntivirusUpdateType;
import org.limewire.friend.api.Friend;
import org.limewire.ui.swing.components.IconButton;
import org.limewire.ui.swing.downloads.table.DownloadActionHandler;
import org.limewire.ui.swing.table.TableRendererEditor;
import org.limewire.ui.swing.transfer.TransferRendererResources;
import org.limewire.ui.swing.util.GuiUtils;
import org.limewire.ui.swing.util.I18n;
import org.limewire.util.CommonUtils;

import com.google.inject.Inject;

/**
 * Renderer/editor component for the download table to display message. 
 */
public class DownloadMessageRendererEditor extends TableRendererEditor {

    @Resource private Icon infoIcon;
    
    private final DownloadActionHandler actionHandler;
    private final TransferRendererResources resources;
    
    private JLabel messageLabel;
    private JButton infoButton;
    
    private DownloadItem downloadItem;
    
    /**
     * Constructs a DownloadMessageRendererEditor that uses the specified 
     * action handler.
     */
    @Inject
    public DownloadMessageRendererEditor(DownloadActionHandler actionHandler) {
        this.actionHandler = actionHandler;
        this.resources = new TransferRendererResources();
        
        GuiUtils.assignResources(this);
        
        setLayout(new MigLayout("insets 0, gap 0, aligny center, nogrid, novisualpadding"));
        
        messageLabel = new JLabel();
        
        infoButton = new IconButton(infoIcon);
        infoButton.setActionCommand(DownloadActionHandler.INFO_COMMAND);
        infoButton.setToolTipText(I18n.tr("Info"));
        infoButton.addActionListener(new ButtonListener());
        
        add(messageLabel, "");
        add(infoButton, "");
    }

    @Override
    protected Component doTableCellEditorComponent(JTable table, Object value, 
            boolean isSelected, int row, int column) {
        if (value instanceof DownloadItem) {
            // Save download item for use by button listener.
            downloadItem = (DownloadItem) value;
            update(downloadItem);
            return this;
        } else {
            return emptyPanel;
        }
    }

    @Override
    protected Component doTableCellRendererComponent(JTable table, Object value,
            boolean isSelected, boolean hasFocus, int row, int column) {
        if (value instanceof DownloadItem) {
            update((DownloadItem) value);
            return this;
        } else {
            return emptyPanel;
        }
    }

    /**
     * Updates the display components using the specified download item.
     */
    private void update(DownloadItem item) {
        DownloadState state = item.getState();
        
        resources.decorateComponent(messageLabel);
        messageLabel.setText(getPercentMessage(item) + getMessage(item));
        if (state == DownloadState.DANGEROUS ) {
            messageLabel.setForeground(resources.getDisabledForeground());
        }
        
        infoButton.setVisible(item.getDownloadItemType() == DownloadItemType.ANTIVIRUS ||
                item.getDownloadItemType() == DownloadItemType.BITTORRENT ||
                state == DownloadState.DANGEROUS);
    }
    
    /**
     * Returns the percent complete as a string.
     */
    private String getPercentMessage(DownloadItem item) {
        int percent = item.getPercentComplete();
        DownloadState state = item.getState();
        if (percent == 0 || state.isFinished() ||
                state == DownloadState.DOWNLOADING ||
                state == DownloadState.ERROR) {
            return "";
        }
        return percent + "% - ";    
    }
    
    /**
     * @return the message displayed after the percentage. Can be null for non-covered states.
     */
    private String getMessage(DownloadItem item) {
        switch (item.getState()) {
        case RESUMING:
            return I18n.tr("Resuming");
        case CANCELLED:
            return I18n.tr("Cancelled");
        case FINISHING:
            return I18n.tr("Finishing...");
        case DONE:
            return I18n.tr("Done");
        case CONNECTING:
            Collection<RemoteHost> hosts = item.getRemoteHosts();
            if(hosts.size() == 0){
                return I18n.tr("Connecting...");
            }
            //{0}: 1 person, 2 people, etc
            return I18n.tr("Connecting to {0}", getPeopleText(item));
        case DOWNLOADING:            
            // {0}: current size
            // {1}: total size
            // {2}: download speed
            // {3}: download source
            if(item.getDownloadSourceCount() == 0){
                return I18n.tr("{0} of {1} ({2})",
                        GuiUtils.formatUnitFromBytes(item.getCurrentSize()), 
                        GuiUtils.formatUnitFromBytes(item.getTotalSize()),
                        GuiUtils.formatKilobytesPerSec(item.getDownloadSpeed()));
            } else { 
                return I18n.tr("{0} of {1} ({2}) from {3}",
                    GuiUtils.formatUnitFromBytes(item.getCurrentSize()), 
                    GuiUtils.formatUnitFromBytes(item.getTotalSize()),
                    GuiUtils.formatKilobytesPerSec(item.getDownloadSpeed()), 
                    getPeopleText(item));
            }
        case TRYING_AGAIN:
            return getTryAgainMessage(item.getRemainingTimeInState());
        case STALLED:
        	 if(item.getDownloadItemType() == DownloadItemType.BITTORRENT) {
                return I18n.tr("Error downloading torrent");
             } else {
             	return I18n.tr("Stalled - {0} of {1}", 
                    GuiUtils.formatUnitFromBytes(item.getCurrentSize()),
                    GuiUtils.formatUnitFromBytes(item.getTotalSize()));
             }
        case ERROR:         
            if(item.getErrorState() == ErrorState.INVALID) {
                return I18n.tr(item.getErrorState().getMessage());
            } else {
                return I18n.tr("Unable to download: ") + I18n.tr(item.getErrorState().getMessage());
            }
        case PAUSED:
            // {0}: current size, {1} total size
            return I18n.tr("Paused - {0} of {1}", 
                    GuiUtils.formatUnitFromBytes(item.getCurrentSize()), GuiUtils.formatUnitFromBytes(item.getTotalSize()));
        case LOCAL_QUEUED:
            return getQueueTimeMessage(item.getRemainingTimeInState());
        case REMOTE_QUEUED:
            if(item.getRemoteQueuePosition() == -1 || item.getRemoteQueuePosition() == Integer.MAX_VALUE){
                return getQueueTimeMessage(item.getRemainingTimeInState());
            }
            return I18n.trn("Waiting - Next in line",
                    "Waiting - {0} in line",
                    item.getRemoteQueuePosition(), item.getRemoteQueuePosition());
        case DANGEROUS:
            return I18n.tr("File deleted - Dangerous file");
        default:
            return null;
        }
        
    }
    
    private String getTryAgainMessage(long tryingAgainTime) {
        if(tryingAgainTime == DownloadItem.UNKNOWN_TIME){
            return I18n.tr("Looking for file...");                
        } else {
            return I18n.tr("Looking for file ({0} left)", CommonUtils.seconds2time(tryingAgainTime));
        }
    }
    
    private String getPeopleText(DownloadItem item) {
        Collection<RemoteHost> hosts = item.getRemoteHosts();
        if (hosts.size() == 0) {
            //checking sources to support showing the number of bit torrent hosts.
            int downloadSourceCount = item.getDownloadSourceCount();
            if(downloadSourceCount < 1) {
                return I18n.tr("nobody");
            } else {
                return I18n.trn("{0} User", "{0} Users", downloadSourceCount);
            }
        } else if (hosts.size() == 1) {

            Friend friend = hosts.iterator().next().getFriendPresence().getFriend();
            if (friend.isAnonymous()) {
                return I18n.tr("1 User");
            } else {
                return friend.getRenderName();
            }

        } else {
            boolean hasP2P = false;
            boolean hasFriend = false;
            
            for (RemoteHost host : hosts) {                
                if (host.getFriendPresence().getFriend().isAnonymous()) {
                    hasP2P = true;
                } else {
                    hasFriend = true;
                }
                
                if (hasP2P && hasFriend) {
                    // We found both.  We're done.
                    break;
                }
            }
            if (hasP2P && hasFriend ) {
                return I18n.trn("{0} Person", "{0} People", hosts.size());
            } else if (hasP2P) {
                return I18n.trn("{0} User", "{0} Users", hosts.size());
            } else {
                //just friends
                return I18n.trn("{0} Friend", "{0} Friends", hosts.size());
            }
        }
    }
    
    private String getQueueTimeMessage(long queueTime){
        //if(queueTime == DownloadItem.UNKNOWN_TIME){
            return I18n.tr("Waiting...");                
        //} else {
        //    return I18n.tr("Waiting...", CommonUtils.seconds2time(queueTime));
        //}
    }

    /**
     * Action listener for editor buttons.
     */
    private class ButtonListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            // Reset cursor if source component is IconButton.  If the action
            // displays a modal dialog, then IconButton does not receive the
            // mouseExited event to reset the default cursor.
            if (e.getSource() instanceof IconButton) {
                ((IconButton) e.getSource()).resetDefaultCursor();
            }
            
            actionHandler.performAction(e.getActionCommand(), downloadItem);
            cancelCellEditing();
        }
    }
}
