package be.iminds.ilabt.jfed.experimenter_gui.slice.scp;

import be.iminds.ilabt.jfed.experiment.Experiment;
import be.iminds.ilabt.jfed.experiment.SshConnectionPool;
import be.iminds.ilabt.jfed.experiment.SshConnectionPoolFactory;
import be.iminds.ilabt.jfed.rspec.model.controller.ExperimentCommand;
import be.iminds.ilabt.jfed.rspec.model.javafx_impl.FXRspecNode;
import javafx.application.Platform;
import javafx.beans.property.LongProperty;
import javafx.beans.property.SimpleLongProperty;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.common.StreamCopier;
import net.schmizz.sshj.xfer.TransferListener;
import net.schmizz.sshj.xfer.scp.SCPFileTransfer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

/**
 * User: twalcari
 * Date: 8/24/2016
 * Time: 16:47
 */
public class SCPDownloadTask extends SCPTask {
    private static final Logger LOG = LoggerFactory.getLogger(SCPDownloadTask.class);

    private final String remotePath;
    private final String localPath;
    private final LongProperty size = new SimpleLongProperty();


    private final SshConnectionPoolFactory sshConnectionPoolFactory;

    public SCPDownloadTask(Experiment experiment, FXRspecNode node, String remotePath, String localPath, SshConnectionPoolFactory sshConnectionPoolFactory) {
        super(experiment, node);
        this.sshConnectionPoolFactory = sshConnectionPoolFactory;
        this.localPath = localPath;
        this.remotePath = remotePath;

        updateTitle("Download '" + remotePath + "' to '" + localPath + "' on " + node.getClientId());
    }

    @Override
    public Boolean call() throws Exception {
        SshConnectionPool sshConnectionPool = sshConnectionPoolFactory.getSshConnectionPool(experiment);
        SSHClient ssh =
                sshConnectionPool.getConnection(node.getUniqueId(), ExperimentCommand.BlockingMode.WAIT_FOR_SINGLE);

        if (ssh != null) {
            SCPFileTransfer fileTransfer = ssh.newSCPFileTransfer();
            fileTransfer.setTransferListener(new TransferListener() {
                @Override
                public TransferListener directory(String name) {
                    updateMessage("Downloading directory '" + name + "'");
                    return this;
                }

                @Override
                public StreamCopier.Listener file(String name, long size) {
                    Platform.runLater(() -> SCPDownloadTask.this.size.set(SCPDownloadTask.this.size.get() + size));
                    updateMessage("Downloading '" + name + "' (" + size + " bytes)");
                    return transferred -> {
                        updateMessage(String.format("Transferred %d%% of " + name, ((transferred * 100) / size)));
                        updateProgress(transferred, size);
                    };
                }
            });

            try {
                fileTransfer.download(remotePath, localPath);


                return true;
            } catch (IOException ex) {
                updateMessage("Error while downloading: " + ex.getMessage());
                LOG.error("Error while downloading {}", remotePath, ex);
                throw ex;
            } finally {
                ssh.close();
            }

        } else {
            updateMessage("Could not establish a connection to " + node.getClientId());
            throw new RuntimeException("Could not establish a connection to " + node.getClientId());
        }
    }

    @Override
    public FXRspecNode getNode() {
        return node;
    }

    @Override
    public String getLocalPath() {
        return localPath;
    }

    @Override
    public String getRemotePath() {
        return remotePath;
    }

    @Override
    public LongProperty sizeProperty() {
        return size;
    }
}
