/*
 * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.java.sip.communicator.impl.gui.main.chat.filetransfer;

import java.awt.event.*;
import java.io.*;
import java.util.*;

import javax.swing.*;

import net.java.sip.communicator.impl.gui.*;
import net.java.sip.communicator.impl.gui.main.chat.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.plugin.desktoputil.SwingWorker;
// Disambiguates SwingWorker on Java 6 in the presence of javax.swing.*

/**
 * The <tt>ReceiveFileConversationComponent</tt> is the component shown in the
 * conversation area of the chat window to display a incoming file transfer.
 *
 * @author Yana Stamcheva
 */
public class ReceiveFileConversationComponent
    extends FileTransferConversationComponent
    implements  ActionListener,
                FileTransferStatusListener,
                FileTransferListener
{
    private final Logger logger
        = Logger.getLogger(ReceiveFileConversationComponent.class);

    private final IncomingFileTransferRequest fileTransferRequest;

    private final OperationSetFileTransfer fileTransferOpSet;

    private final ChatPanel chatPanel;

    private final Date date;

    private final String dateString;

    private File downloadFile;

    /**
     * Creates a <tt>ReceiveFileConversationComponent</tt>.
     * @param chatPanel the chat panel
     * @param opSet the <tt>OperationSetFileTransfer</tt>
     * @param request the <tt>IncomingFileTransferRequest</tt>
     * associated with this component
     * @param date the date
     */
    public ReceiveFileConversationComponent(
        ChatPanel chatPanel,
        final OperationSetFileTransfer opSet,
        final IncomingFileTransferRequest request,
        final Date date)
    {
        this.chatPanel = chatPanel;
        this.fileTransferOpSet = opSet;
        this.fileTransferRequest = request;
        this.date = date;
        this.dateString = getDateString(date);

        fileTransferOpSet.addFileTransferListener(this);

        byte[] thumbnail = request.getThumbnail();

        if (thumbnail != null && thumbnail.length > 0)
        {
            ImageIcon thumbnailIcon = new ImageIcon(thumbnail);

            if (thumbnailIcon.getIconWidth() > IMAGE_WIDTH
                || thumbnailIcon.getIconHeight() > IMAGE_HEIGHT)
            {
                thumbnailIcon
                    = ImageUtils.getScaledRoundedIcon(
                        thumbnail, IMAGE_WIDTH, IMAGE_WIDTH);
            }

            imageLabel.setIcon(thumbnailIcon);
        }

        titleLabel.setText(
            dateString
            + resources.getI18NString(
            "service.gui.FILE_TRANSFER_REQUEST_RECIEVED",
            new String[]{fileTransferRequest.getSender().getDisplayName()}));

        String fileName
            = getFileLabel(request.getFileName(), request.getFileSize());
        fileLabel.setText(fileName);

        acceptButton.setVisible(true);
        acceptButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                titleLabel.setText(
                    dateString
                    + resources
                    .getI18NString("service.gui.FILE_TRANSFER_PREPARING",
                                    new String[]{fileTransferRequest.getSender()
                                                .getDisplayName()}));
                acceptButton.setVisible(false);
                rejectButton.setVisible(false);
                cancelButton.setVisible(true);
                progressBar.setVisible(true);

                downloadFile = createFile(fileTransferRequest);

                new AcceptFile(downloadFile).start();
            }
        });

        rejectButton.setVisible(true);
        rejectButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                try
                {
                    fileTransferRequest.rejectFile();
                    acceptButton.setVisible(false);
                    rejectButton.setVisible(false);
                    setWarningStyle(true);
                    fileLabel.setText("");
                    titleLabel.setText(
                        dateString
                        + resources.getI18NString(
                            "service.gui.FILE_TRANSFER_REFUSED"));
                    ReceiveFileConversationComponent.this.chatPanel
                        .removeActiveFileTransfer(fileTransferRequest.getID());
                }
                catch (OperationFailedException e1)
                {
                    logger.error("Failed to reject file", e1);
                }
            }
        });

        progressBar.setMaximum((int)fileTransferRequest.getFileSize());
    }

    /**
     * Creates the file to download.
     *
     * @return the file to download.
     */
    private File createFile(IncomingFileTransferRequest fileTransferRequest)
    {
        File downloadFile = null;
        File downloadDir = null;

        String incomingFileName = fileTransferRequest.getFileName();
        // strip characters that are invalid on Windows and maybe other
        // platforms too
        incomingFileName = incomingFileName
            .replaceAll("[\\\\/:*?\"<>|]", "_");
        try
        {
            downloadDir = GuiActivator.getFileAccessService()
                .getDefaultDownloadDirectory();

            if (!downloadDir.exists())
            {
                if (!downloadDir.mkdirs())
                {
                    logger.error("Could not create the download directory : "
                        + downloadDir.getAbsolutePath());
                }
                if (logger.isDebugEnabled())
                    logger.debug("Download directory created : "
                        + downloadDir.getAbsolutePath());
            }
        }
        catch (IOException e)
        {
            if (logger.isDebugEnabled())
                logger.debug("Unable to find download directory.", e);
        }

        downloadFile = new File(downloadDir, incomingFileName);

        // If a file with the given name already exists, add an index to the
        // file name.
        int index = 0;
        int filenameLenght = incomingFileName.lastIndexOf(".");
        if(filenameLenght == -1)
        {
            filenameLenght = incomingFileName.length();
        }
        while (downloadFile.exists())
        {
            String newFileName
             = incomingFileName.substring(0, filenameLenght)
                 + "-" + ++index
                 + incomingFileName.substring(filenameLenght);

            downloadFile = new File(downloadDir, newFileName);
        }

        // Change the file name to the name we would use on the local file
        // system.
        if (!downloadFile.getName().equals(fileTransferRequest.getFileName()))
        {
            String fileName
                = getFileLabel( downloadFile.getName(),
                                fileTransferRequest.getFileSize());

            fileLabel.setText(fileName);
        }

        return downloadFile;
    }

    /**
     * Handles status changes in file transfer.
     */
    public void statusChanged(FileTransferStatusChangeEvent event)
    {
        FileTransfer fileTransfer = event.getFileTransfer();
        int status = event.getNewStatus();

        String fromContactName
            = fileTransferRequest.getSender().getDisplayName();

        if (status == FileTransferStatusChangeEvent.COMPLETED
            || status == FileTransferStatusChangeEvent.CANCELED
            || status == FileTransferStatusChangeEvent.FAILED
            || status == FileTransferStatusChangeEvent.REFUSED)
        {
            fileTransfer.removeStatusListener(this);
        }

        if (status == FileTransferStatusChangeEvent.PREPARING)
        {
            hideProgressRelatedComponents();

            titleLabel.setText(
                dateString
                + resources.getI18NString(
                "service.gui.FILE_TRANSFER_PREPARING",
                new String[]{fromContactName}));
        }
        else if (status == FileTransferStatusChangeEvent.FAILED)
        {
            hideProgressRelatedComponents();
            cancelButton.setVisible(false);

            titleLabel.setText(
                dateString
                + resources.getI18NString(
                "service.gui.FILE_RECEIVE_FAILED",
                new String[]{fromContactName}));

            setWarningStyle(true);
        }
        else if (status == FileTransferStatusChangeEvent.IN_PROGRESS)
        {
            titleLabel.setText(
                dateString
                + resources.getI18NString(
                "service.gui.FILE_RECEIVING_FROM",
                new String[]{fromContactName}));
            setWarningStyle(false);

            if (!progressBar.isVisible())
            {
                progressBar.setVisible(true);
            }
        }
        else if (status == FileTransferStatusChangeEvent.COMPLETED)
        {
            this.setCompletedDownloadFile(downloadFile);

            hideProgressRelatedComponents();
            cancelButton.setVisible(false);

            openFileButton.setVisible(true);
            openFolderButton.setVisible(true);

            titleLabel.setText(
                dateString
                + resources.getI18NString(
                "service.gui.FILE_RECEIVE_COMPLETED",
                new String[]{fromContactName}));
        }
        else if (status == FileTransferStatusChangeEvent.CANCELED)
        {
            hideProgressRelatedComponents();

            cancelButton.setVisible(false);

            titleLabel.setText(
                dateString
                + resources.getI18NString(
                "service.gui.FILE_TRANSFER_CANCELED"));
            setWarningStyle(true);
        }
        else if (status == FileTransferStatusChangeEvent.REFUSED)
        {
            hideProgressRelatedComponents();

            titleLabel.setText(
                dateString
                + resources.getI18NString(
                "service.gui.FILE_TRANSFER_REFUSED",
                new String[]{fromContactName}));
            cancelButton.setVisible(false);
            openFileButton.setVisible(false);
            openFolderButton.setVisible(false);

            setWarningStyle(true);
        }
    }

    /**
     * Returns the date of the component event.
     *
     * @return the date of the component event
     */
    @Override
    public Date getDate()
    {
        return date;
    }

    /**
     * Accepts the file in a new thread.
     */
    private class AcceptFile extends SwingWorker
    {
        private FileTransfer fileTransfer;

        private final File downloadFile;

        public AcceptFile(File downloadFile)
        {
            this.downloadFile = downloadFile;
        }

        @Override
        public Object construct()
        {
            fileTransfer = fileTransferRequest.acceptFile(downloadFile);

            chatPanel.addActiveFileTransfer(fileTransfer.getID(), fileTransfer);

            // Remove previously added listener, that notified us for request
            // cancellations.
            fileTransferOpSet.removeFileTransferListener(
                ReceiveFileConversationComponent.this);

            // Add the status listener that would notify us when the file
            // transfer has been completed and should be removed from
            // active components.
            fileTransfer.addStatusListener(chatPanel);

            fileTransfer.addStatusListener(
                ReceiveFileConversationComponent.this);

            return "";
        }

        @Override
        public void finished()
        {
            if (fileTransfer != null)
            {
                setFileTransfer(fileTransfer, fileTransferRequest.getFileSize());
            }
        }
    }

    /**
     * Returns the label to show on the progress bar.
     *
     * @param bytesString the bytes that have been transfered
     * @return the label to show on the progress bar
     */
    @Override
    protected String getProgressLabel(String bytesString)
    {
        return resources.getI18NString("service.gui.RECEIVED",
            new String[]{bytesString});
    }

    public void fileTransferCreated(FileTransferCreatedEvent event)
    {}

    public void fileTransferRequestCanceled(FileTransferRequestEvent event)
    {
        IncomingFileTransferRequest request = event.getRequest();

        if (request.equals(fileTransferRequest))
        {
            acceptButton.setVisible(false);
            rejectButton.setVisible(false);

            titleLabel.setText(
                dateString
                + resources.getI18NString(
                "service.gui.FILE_TRANSFER_CANCELED"));

            setWarningStyle(true);
        }
    }

    public void fileTransferRequestReceived(FileTransferRequestEvent event)
    {}

    public void fileTransferRequestRejected(FileTransferRequestEvent event)
    {}
}
