/*
 * @(#)FileTransfer.java
 *
 * Copyright (c) 1999-2007 JSCAPE LLC
 *
 * This software is the confidential and proprietary information of
 * JSCAPE. ("Confidential Information").  You shall not disclose such
 * Confidential Information and shall use it only in accordance with
 * the terms of the license agreement you entered into with JSCAPE.
 */
package com.jscape.filetransfer;

import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.Date;
import java.util.Enumeration;
import java.util.TimeZone;
import java.util.Vector;


/**
 * Abstract interface for performing file transfer operations using FTP, FTPS (FTP over SSL) and SFTP (FTP over SSH)
 * protocols.
 * <p/>
 * Example Usage:<P>
 * <pre>
 * FileTransfer ftp = new FtpFileTransfer(hostname,username,password);
 * ftp.connect();
 * System.out.println(ftp.getDirListingAsString());
 * ftp.disconnect();
 * </pre>
 */
public interface FileTransfer
        extends AutoCloseable {

    /**
     * Flag to indicate that automatic transfer mode detection is used.
     *
     * @see #getMode
     */
    int AUTO = 0;

    /**
     * Flag to indicate that ASCII transfer mode is used.
     *
     * @see #getMode
     */
    int ASCII = 1;

    /**
     * Flag to indicate that BINARY transfer mode is used.
     *
     * @see #getMode
     */
    int BINARY = 2;

    /**
     * Represents the current directory.
     * Value of "."
     */
    String CURRENT_DIRECTORY = ".";

    /**
     * Represents the parent directory of current directory.
     * Value of ".."
     */
    String PARENT_DIRECTORY = "..";

    /**
     * Sets the proxy type will be used for this connection.
     *
     * @param value The proxy type. Values allowed: HTTP, SOCKS5
     */
    FileTransfer setProxyType(String value);

    /**
     * Sets the proxy hostname and port for this connection.
     * To clear these settings invoke the #clearProxySettings method.
     *
     * @param host the hostname or ip address of the proxy server
     * @param port     the port of the proxy server to connect to
     *
     * @see #clearProxySettings
     */
    FileTransfer setProxyHost(String host, int port);

    /**
     * Sets the proxy authentication username and password to use with
     * proxy server.
     * To clear these settings invoke the #clearProxySettings method.
     *
     * @param username the proxy username
     * @param password the proxy password
     *
     * @see #clearProxySettings
     */
    FileTransfer setProxyAuthentication(String username, String password);

    /**
     * Clears proxy server values.
     */
    void clearProxySettings();

    /**
     * Gets hostname of server.
     *
     * @return hostname
     */
    String getHostname();

    /**
     * Sets hostname of server.
     *
     * @param value the hostname or IP address of server
     */
    FileTransfer setHostname(String value);

    /**
     * Gets server port.
     * Default value is 21.
     *
     * @return server port
     */
    int getPort();

    /**
     * Sets port of remote server.
     *
     * @param value the port
     */
    FileTransfer setPort(int value);

    /**
     * Gets the timeout for opening connection to server.
     *
     * @return timeout in milliseconds
     */
    long getTimeout();

    /**
     * Sets the timeout for opening connection to server.
     *
     * @param value the timeout in milliseconds
     */
    FileTransfer setTimeout(long value);

    /**
     * Gets username.
     *
     * @return username
     */
    String getUsername();

    /**
     * Sets username.
     *
     * @param value the username
     */
    FileTransfer setUsername(String value);

    /**
     * Gets password.
     *
     * @return the password
     */
    String getPassword();

    /**
     * Sets password.
     *
     * @param value the password
     */
    FileTransfer setPassword(String value);

    /**
     * Gets blocksize for use in transferring files.
     *
     * @return blocksize in bytes
     */
    int getBlockTransferSize();

    /**
     * Sets block size for use in transferring files.
     *
     * @param value the blocksize in bytes
     */
    FileTransfer setBlockTransferSize(int value);

    /**
     * Gets whether passive mode is used for FTP connections.
     *
     * @return <code>true</code> if passive mode is used, <code>false</code> otherwise
     */
    boolean getPassive();

    /**
     * Sets whether passive mode is used for FTP connections.
     *
     * @param value if true, the transfers will be passive.
     */
    FileTransfer setPassive(boolean value);

    /**
     * Gets data transfer mode for current session.
     * Default mode is FileTransfer.AUTO where 0 = AUTO, 1 = ASCII, 2 = BINARY
     *
     * @return the data transfer mode
     *
     * @see #AUTO
     * @see #BINARY
     * @see #ASCII
     */
    int getMode();

    /**
     * Sets data transfer mode to ASCII. You must be connected to the
     * server prior to invoking this method.
     *
     * @throws FileTransferException if an I/O or server error occurs.
     */
    FileTransfer setAscii();

    /**
     * Sets data transfer mode to automatically detect transfer mode.
     * Any files with a base Content-Type value of text will be transferred
     * using ASCII, all other files will be transfered using binary.
     * <p/>
     * Example: file.txt, Content-Type = text/plain, uploaded using ASCII
     * <br>
     * Example: image.jpg Content-Type = image/jpg, uploaded using binary
     *
     * @param value <code>true</code> to turn automatic detect on <code>false</code> to turn off
     *
     * @throws FileTransferException if an I/O or server error occurs.
     */
    FileTransfer setAuto(boolean value);

    /**
     * Sets data transfer mode to binary. You must be connected to the
     * server prior to invoking this method.
     *
     * @throws FileTransferException if an I/O or server error occurs.
     */
    FileTransfer setBinary();

    /**
     * Gets encoding set used when issuing commands and transferring files.
     *
     * @return Returns the encoding is being used
     */
    String getWireEncoding();

    /**
     * Sets encoding set used when issuing commands and transferring files.
     * The default encoding is UTF8
     *
     * @param value the character encoding to be used
     */
    FileTransfer setWireEncoding(String value);

    /**
     * Get preserve file upload timestamps.
     *
     * @param value
     */
    FileTransfer setPreserveFileUploadTimestamp(boolean value);

    /**
     * Set preserve file download timestamps.
     *
     * @param value
     */
    FileTransfer setPreserveFileDownloadTimestamp(boolean value);

    boolean isChecksumVerificationRequired();

    FileTransfer setChecksumVerificationRequired(boolean value);

    /**
     * Set the timezone, used for preserving timestamps.
     *
     * @param value
     */
    FileTransfer setTimeZone(TimeZone value);

    /**
     * Gets debugging state.
     *
     * @return <code>true</code> if debugging is on
     */
    boolean getDebug();

    /**
     * Sets debugging state.
     * All debug statements are reported to debug stream.
     * Default debug stream is <code>System.out</code>.
     *
     * @param debug <code>true</code> to turn debugging on
     *
     * @see #setDebugStream
     */
    FileTransfer setDebug(boolean debug);

    /**
     * Gets PrintStream used in reporting debug statements.
     * Default <code>PrintStream</code> is <code>System.out</code>.
     *
     * @return the <code>PrintStream</code> used in reporting debug statements
     *
     * @see java.io.PrintStream
     */
    PrintStream getDebugStream();

    /**
     * Sets <code>PrintStream</code> used in reporting debug statements.
     * Default debug stream is <code>System.out</code>.
     *
     * @param ps the <code>PrintStream</code> to send debug statements to
     *
     * @see java.io.PrintStream
     */
    FileTransfer setDebugStream(PrintStream ps);

    /**
     * Adds FileTransferListener.
     *
     * @param listener the listener to add
     *
     * @see FileTransferListener
     */
    void addFileTransferListener(FileTransferListener listener);

    /**
     * Removes specified FileTransferListener.
     *
     * @param listener the listener to remove
     *
     * @see FileTransferListener
     */
    void removeFileTransferListener(FileTransferListener listener);

    /**
     * Gets local directory to be used in session.
     * Downloads will be stored relative to local directory.
     * Uploads are performed relative to current local directory.
     *
     * @return the local directory
     */
    File getLocalDir();

    /**
     * Sets local directory to be used in session.
     * Downloads will be stored relative to local directory.
     * Uploads are performed relative to current local directory.
     *
     * @param value the local directory
     */
    FileTransfer setLocalDir(File value);

    /**
     * Gets local directory listing.
     *
     * @return an <code>java.util.Enumeration</code> of <code>File</code>
     */
    Enumeration getLocalDirListing();

    /**
     * Creates local directory.
     * Directory is relative to current local directory
     *
     * @param localDirectory name of directory
     *
     * @return the directory
     *
     * @see #getLocalDir
     */
    File makeLocalDir(String localDirectory)
            throws FileTransferException;

    /**
     * Gets underlying file transfer instance.
     *
     * @return an instance of <code>Ftp</code>, <code>Ftps</code> or <code>Sftp</code>
     *
     * @see com.jscape.inet.ftp.Ftp
     * @see com.jscape.inet.ftps.Ftps
     */
    Object getImplementation();

    /**
     * Returns a copy of current transfer instance with same listeners.
     *
     * @return a copy of current transfer instance
     */
    FileTransfer copy();

    /**
     * Connects to server and performs login.
     *
     * @throws FileTransferException if an I/O or server error occurs.
     * @see #setUsername
     * @see #setPassword
     */
    FileTransfer connect()
            throws FileTransferException;

    /**
     * Quits session and disconnects from server.
     *
     * @throws FileTransferException if an I/O or server error occurs.
     */
    void disconnect()
            throws FileTransferException;
    
    void close();

    /**
     * Checks if client is connected to server.
     *
     * @return <code>true</code> if connected <code>false</code> otherwise
     */
    boolean isConnected();

    /**
     * Gets current working directory of server.
     *
     * @return current directory
     *
     * @throws FileTransferException if an I/O or server error occurs.
     */
    String getDir()
            throws FileTransferException;

    /**
     * Sets current directory on server.
     *
     * @param remoteDirectory the remote directory
     *
     * @throws FileTransferException if an I/O or server error occurs.
     */
    FileTransfer setDir(String remoteDirectory)
            throws FileTransferException;

    /**
     * Sets current directory on server to parent directory.
     *
     * @throws FileTransferException if an I/O or server error occurs.
     */
    FileTransfer setDirUp()
            throws FileTransferException;

    /**
     * Gets file listing of files matching regular expression. For example the regular expression "<tt>.</tt><tt>*</tt><tt>\\.txt</tt>" may return all
     * files containing a .txt filename extension.
     *
     * @param regex the filename filter
     *
     * @return an <code>Enumeration</code> of <code>FileTransferRemoteFile</code> objects
     *
     * @throws FileTransferException if an I/O or server error occurs.
     * @see #getDirListingAsString(String)
     * @see #getNameListing
     */
    Enumeration<FileTransferRemoteFile> getDirListing(String regex)
            throws FileTransferException;

    /**
     * Gets directory listing from server.
     *
     * @return an <code>Enumeration</code> of <code>FileTransferRemoteFile</code> objects
     *
     * @throws FileTransferException if an I/O or server error occurs.
     * @see #getDirListingAsString(String)
     * @see #getNameListing
     */
    Enumeration<FileTransferRemoteFile> getDirListing()
            throws FileTransferException;

    /**
     * Gets file listing of files matching regular expression. For example the regular expression
     * "<tt>.</tt><tt>*</tt><tt>\\.txt</tt>" may return all files containing a .txt filename extension.
     *
     * @param regex a filename filter
     *
     * @return a directory listing
     *
     * @throws FileTransferException if an I/O or server error occurs.
     */
    String getDirListingAsString(String regex)
            throws FileTransferException;

    /**
     * Gets directory listing of files on server.
     *
     * @return a directory listing
     *
     * @throws FileTransferException if an I/O or server error occurs.
     */
    String getDirListingAsString()
            throws FileTransferException;

    /**
     * Gets directory listing of files on server matching regular expression.
     * For example "<tt>.</tt><tt>*</tt><tt>\\.txt</tt>" may return all files containing a .txt filename extension.
     *
     * @param regex the filename filter
     *
     * @return an <code>Enumeration</code> of <code>String</code> where each item represents a file
     *         or directory name
     *
     * @throws FileTransferException if an I/O or server related error occurs
     */
    Enumeration getNameListing(String regex)
            throws FileTransferException;

    /**
     * Gets directory listing of files on server.
     *
     * @return an <code>Enumeration</code> of <code>String</code> where each item represents a file
     *         or directory name
     *
     * @throws FileTransferException if an I/O or server related error occurs
     */
    Enumeration getNameListing()
            throws FileTransferException;

    /**
     * Get remote directory list.
     *
     * @param remoteDirectory
     *
     * @return
     *
     * @throws FileTransferException
     */
    Vector<FileTransferRemoteFile> getRemoteFileList(String remoteDirectory)
            throws FileTransferException;

    /**
     * Get recursive directory size.
     *
     * @param remoteDirectory
     *
     * @return
     *
     * @throws FileTransferException
     */
    long getRecursiveDirectorySize(String remoteDirectory)
            throws FileTransferException;

    /**
     * Get recursive directory file count.
     *
     * @param remoteDirectory
     *
     * @return
     *
     * @throws FileTransferException
     */
    int getRecursiveDirectoryFileCount(String remoteDirectory)
            throws FileTransferException;

    /**
     * Makes directory on server.
     *
     * @param remoteDirectory name of directory to make
     *
     * @throws FileTransferException if an I/O or server error occurs.
     */
    void makeDir(String remoteDirectory)
            throws FileTransferException;

    /**
     * Makes directory on server, creating subdirectories if necessary.
     *
     * @param remoteDirectory full path of directory to make
     *
     * @throws FileTransferException if an I/O or server error occurs
     */
    void makeDirRecursive(String remoteDirectory)
            throws FileTransferException;

    /**
     * Deletes directory from server.
     *
     * @param remoteDirectory the directory to remove
     *
     * @throws FileTransferException if an I/O or server error occurs.
     */
    void deleteDir(String remoteDirectory)
            throws FileTransferException;

    /**
     * Deletes directory from server.
     * If the directory cannot be deleted because it is not empty the <code>recursive</code>
     * parameter will be used to determine if files and subdirectories within
     * directory should be removed.
     *
     * @param remoteDirectory      the directory to remove
     * @param recursive <code>true</code> if it should delete files and subdirectories within directory
     *
     * @throws FileTransferException if an I/O or server error occurs.
     */
    void deleteDir(String remoteDirectory, boolean recursive)
            throws FileTransferException;

    /**
     * Checks if the specified path exists on the remote server.
     *
     * @param remotePath a path to verify
     *
     * @return <code>true</code> if path exists; <code>false</code> otherwise
     *
     * @throws FileTransferException if an error occurs
     */
    boolean exists(String remotePath)
            throws FileTransferException;

    boolean isDirectory(String remotePath)
            throws FileTransferException;

    /**
     * Gets filesize of remote file from server.
     * <p/>
     * When using the FTP/S protocols the SIZE command is used.  The SIZE command is
     * not part of RFC-959 so may not work on all FTP servers.
     *
     * @param remoteFile the remote file
     *
     * @return filesize in bytes
     *
     * @throws FileTransferException if an I/O or protocol error occurs.
     */
    long getFilesize(String remoteFile)
            throws FileTransferException;

    /**
     * Gets date/timestamp of remote file from server.
     * <p/>
     * When using the FTP/S protocols the MDTM command is used.  The MDTM command is
     * not part of RFC-959 so may not work on all FTP servers.
     *
     * @param remoteFile the remote file
     *
     * @return date the date/timestamp of remote file
     *
     * @throws FileTransferException if an I/O or server error occurs.
     */
    Date getFileTimestamp(String remoteFile)
            throws FileTransferException;

    /**
     * Sets date/timestamp of remote file from server
     * <p/>
     * When using the FTP/S protocols the MDTM command is used.  The MDTM command is
     * not part of RFC-959 so may not work on all FTP servers.
     *
     * @param remoteFile the remote file
     * @param timestamp  the new date/timestamp
     *
     * @throws FileTransferException if an I/O or server error occurs.
     */
    FileTransfer setFileTimestamp(String remoteFile, Date timestamp)
            throws FileTransferException;

    /**
     * Set file modifcation time.
     *
     * @param remoteFile       - the remote file.
     * @param modificationTime - the time.
     *
     * @throws FileTransferException
     */
    FileTransfer setFileModificationTime(String remoteFile, Date modificationTime)
            throws FileTransferException;

    /**
     * Checks a checksum equality of local and remote files.
     *
     * @param localFile  a local file
     * @param remoteFile a remote file
     *
     * @return <code>true</code> if checksums are equal; <code>false</code> otherwise
     *
     * @throws FileTransferException if an error occurs
     */
    boolean sameChecksum(File localFile, String remoteFile)
            throws FileTransferException;

    /**
     * Renames remote file on server.
     *
     * @param sourceRemoteFile name of file to rename
     * @param destinationRemoteFile    new name of file
     *
     * @throws FileTransferException if an I/O or server error occurs.
     */
    void renameFile(String sourceRemoteFile, String destinationRemoteFile)
            throws FileTransferException;

    /**
     * Deletes remote file from server.
     *
     * @param remoteFile name of file to delete
     *
     * @throws FileTransferException if an I/O or server error occurs.
     */
    void deleteFile(String remoteFile)
            throws FileTransferException;

    /**
     * Deletes multiple files in servers current directory matching regular expression.
     * For example, to delete all files ending with .txt extension you may use the regular expression "<tt>.</tt><tt>*</tt><tt>\\.txt</tt>".
     *
     * @param regex the regular expression filter to use
     *
     * @throws FileTransferException if an error occurs.
     */
    void mdelete(String regex)
            throws FileTransferException;

    /**
     * Downloads file from server and writes contents to provided <code>OutputStream</code>.
     * Closure of <code>OutputStream</code> is responsibility of programmer.
     *
     * @param out        the OutputStream to write download to
     * @param remoteFile remote filename
     *
     * @throws FileTransferException if an I/O or server error occurs.
     */
    void download(OutputStream out, String remoteFile)
            throws FileTransferException;

    /**
     * Downloads file from server.
     * Downloads are stored relative to current local directory.
     *
     * @param localFile  destination filename
     * @param remoteFile remote filename
     *
     * @return File the file downloaded
     *
     * @throws FileTransferException if an I/O or server error occurs.
     * @see #setLocalDir
     */
    File download(String localFile, String remoteFile)
            throws FileTransferException;

    /**
     * Downloads file from server.
     * Downloads are stored relative to current local directory.
     *
     * @param remoteFile the file to download
     *
     * @return File the file downloaded
     *
     * @throws FileTransferException if an I/O or server error occurs.
     * @see #setLocalDir
     */
    File download(String remoteFile)
            throws FileTransferException;

    void resumeDownload(OutputStream out, String remoteFile, long remoteFileOffset)
            throws FileTransferException;

    /**
     * Resumes download of file from server.
     *
     * @param localFile  local file name
     * @param remoteFile the file to download
     * @param remoteFileOffset     file offset in bytes
     *
     * @throws FileTransferException if an I/O or server error occurs.
     */
    void resumeDownload(String localFile, String remoteFile, long remoteFileOffset)
            throws FileTransferException;

    /**
     * Resumes download of file from server.
     *
     * @param remoteFile the file to download
     * @param remoteFileOffset     file offset in bytes
     *
     * @throws FileTransferException if an I/O or server error occurs.
     */
    void resumeDownload(String remoteFile, long remoteFileOffset)
            throws FileTransferException;

    /**
     * Downloads specified files in current working remote directory from server
     * to local directory. Do not use this method to download a directory,
     * see <code>downloadDir(String)</code> method.
     * <p/>
     * Downloads are stored relative to current local directory.
     *
     * @param remoteFiles filenames of files to download
     *
     * @throws FileTransferException if an I/O or server error occurs.
     * @see #setLocalDir
     * @see #downloadDir(String)
     */
    void mdownload(Enumeration remoteFiles)
            throws FileTransferException;

    /**
     * Downloads multiple files matching regular expression from server's current
     * directory. Downloads are stored relative to current local directory.
     * For example, to download all files ending with extension .txt use the filter "<tt>.</tt><tt>*</tt><tt>\\.txt</tt>".
     * <p/>
     * To download a directory use the <code>downloadDir</code> method.
     *
     * @param regex the regular expression to use
     *
     * @throws FileTransferException if an I/O or server error occurs.
     * @see #setLocalDir
     * @see #downloadDir
     */
    void mdownload(String regex)
            throws FileTransferException;

    /**
     * Downloads remote directory and contents.
     * Downloads are stored relative to current local directory.
     *
     * @param remoteDirectory       the directory to download
     * @param retryAttempts      retry limit if download fails
     * @param checksumVerificationRequired whether or not to perform checksum after download, only supported in FTP/S protocols and not by all FTP servers
     * @param threadCount     the thread count
     *
     * @throws FileTransferException if an I/O or protocol error occurs.
     */
    void downloadDir(String remoteDirectory, int retryAttempts, boolean checksumVerificationRequired, int threadCount)
            throws FileTransferException;

    /**
     * Downloads remote directory and contents.
     * Downloads are stored relative to current local directory.
     *
     * @param remoteDirectory       the directory to download
     * @param retryAttempts      retry limit if download fails
     * @param checksumVerificationRequired whether or not to perform checksum after download, only supported in FTP/S protocols and not by all FTP servers
     *
     * @throws FileTransferException if an I/O or protocol error occurs.
     */
    void downloadDir(String remoteDirectory, int retryAttempts, boolean checksumVerificationRequired)
            throws FileTransferException;

    /**
     * Downloads remote directory and contents recursively from server.
     * Downloads are stored relative to current local directory.
     *
     * @param remoteDirectory the directory to download
     *
     * @throws FileTransferException if an I/O or server error occurs.
     * @see #setLocalDir
     */
    void downloadDir(String remoteDirectory)
            throws FileTransferException;

    void upload(InputStream in, long length, String remoteFile, boolean shouldAppend)
            throws FileTransferException;

    /**
     * Uploads file to server where contents of file is not on disk but
     * in memory.
     *
     * @param data   the raw contents of the file to upload
     * @param remoteFile   the filename to store file as on server
     * @param shouldAppend <code>true</code> to append to remote file on FTP server, <code>false</code> otherwise
     *
     * @throws FileTransferException if an I/O or server related error occurs
     */
    void upload(byte[] data, String remoteFile, boolean shouldAppend)
            throws FileTransferException;

    /**
     * Uploads file to server where contents of file is not on disk but
     * in memory.
     *
     * @param data the raw contents of the file to upload
     * @param remoteFile the filename to store file as on FTP server
     *
     * @throws FileTransferException if an I/O or server related error occurs
     */
    void upload(byte[] data, String remoteFile)
            throws FileTransferException;

    /**
     * Uploads file to server.
     * If <code>file</code> is a directory then directory and entire contents are uploaded.
     *
     * @param localFile       the local file to upload
     * @param remoteFile the destination filename of upload
     * @param shouldAppend     <code>true</code> to append to remote file on server, <code>false</code> otherwise
     *
     * @throws FileTransferException if an I/O or server related error occurs
     */
    void upload(File localFile, String remoteFile, boolean shouldAppend)
            throws FileTransferException;

    /**
     * Uploads file to server.
     * If <code>file</code> is a directory then directory and entire contents are uploaded.
     *
     * @param localFile       the local file to upload
     * @param remoteFile the destination filename of upload
     *
     * @throws FileTransferException if an I/O or server related error occurs
     */
    void upload(File localFile, String remoteFile)
            throws FileTransferException;

    /**
     * Uploads file to server.
     * If <code>file</code> is a directory then directory and entire contents are uploaded.
     *
     * @param localFile   the local file to upload
     * @param shouldAppend <code>true</code> to append to remote file on server, <code>false</code> otherwise
     *
     * @throws FileTransferException if an I/O or server related error occurs
     */
    void upload(File localFile, boolean shouldAppend)
            throws FileTransferException;

    /**
     * Uploads file to server with the specified temporary extension.
     * After the file has been uploaded then the file is renamed to the original
     * filename.
     *
     * @param tempFileExtension the temporary extension to use when uploading the file
     * @param localFile      the file to be uploaded
     *
     * @throws FileTransferException if an I/O or protocol error occurs
     */
    void upload(String tempFileExtension, File localFile)
            throws FileTransferException;

    /**
     * Uploads file to server.
     * If <code>file</code> is a directory then directory and entire contents are uploaded.
     *
     * @param localFile the local file to upload
     *
     * @throws FileTransferException if an I/O or server related error occurs
     */
    void upload(File localFile)
            throws FileTransferException;

    /**
     * Uploads file to server.
     * Uploads are performed relative to current local directory.
     *
     * @param localFile       the local file to upload
     * @param remoteFile the destination of upload
     * @param shouldAppend     <code>true</code> to append to remote file on FTP server, <code>false</code> otherwise
     *
     * @throws FileTransferException if an I/O or server error occurs.
     * @see #setLocalDir
     */
    void upload(String localFile, String remoteFile, boolean shouldAppend)
            throws FileTransferException;

    /**
     * Uploads file to server.
     * Uploads are performed relative to current local directory.
     *
     * @param localFile       the local file to upload
     * @param remoteFile the destination of upload
     *
     * @throws FileTransferException if an I/O or server error occurs.
     * @see #setLocalDir
     */
    void upload(String localFile, String remoteFile)
            throws FileTransferException;

    /**
     * Uploads file to server.
     * Uploads are performed relative to current local directory.
     *
     * @param localFile   the local file to upload
     * @param shouldAppend <code>true</code> to append to remote file on server, <code>false</code> otherwise
     *
     * @throws FileTransferException if an I/O or server error occurs.
     * @see #setLocalDir
     */
    void upload(String localFile, boolean shouldAppend)
            throws FileTransferException;

    /**
     * Uploads file to server.
     * Uploads are performed relative to current local directory.
     *
     * @param localFile the local file to upload
     *
     * @throws FileTransferException if an I/O or server error occurs.
     * @see #setLocalDir
     */
    void upload(String localFile)
            throws FileTransferException;

    void resumeUpload(InputStream in, long length, String remoteFile, long remoteFileOffset)
            throws FileTransferException;

    /**
     * Resume upload of file to server.
     *
     * @param localFile
     * @param remoteFile
     * @param localFileOffset
     *
     * @throws FileTransferException
     */
    void resumeUpload(File localFile, String remoteFile, long localFileOffset)
            throws FileTransferException;

    /**
     * Resumes upload of file to server.
     *
     * @param localFile   the local file to upload
     * @param localFileOffset file offset in bytes
     *
     * @throws FileTransferException if an I/O or server error occurs.
     */
    void resumeUpload(File localFile, long localFileOffset)
            throws FileTransferException;

    /**
     * Resumes upload of file to server.
     *
     * @param localFile   the local file to upload
     * @param localFileOffset file offset in bytes
     *
     * @throws FileTransferException if an I/O or server error occurs.
     */
    void resumeUpload(String localFile, long localFileOffset)
            throws FileTransferException;

    /**
     * Uploads the file which is created in the current directory under a name unique to that directory.
     *
     * @param in       the <code>InputStream</code> to upload file from
     * @param remoteFilePrefix the filename to be used as seed value for determining unique filename
     *
     * @return the resulting unique filename on server
     *
     * @throws FileTransferException if an I/O or protocol error occurs.
     */
    String uploadUnique(InputStream in, String remoteFilePrefix)
            throws FileTransferException;

    /**
     * Uploads the file which is created in the current directory under a name unique to that directory.
     *
     * @param localFile the file to be uploaded
     *
     * @return the resulting unique filename on server
     *
     * @throws FileTransferException if an I/O or protocol error occurs.
     */
    String uploadUnique(File localFile)
            throws FileTransferException;

    /**
     * Uploads the file which is created in the current directory under a name unique to that directory.
     *
     * @param localFile the file to be uploaded relative to current local directory
     *
     * @return the resulting unique filename on server
     *
     * @throws FileTransferException if an I/O or protocol error occurs.
     * @see #setLocalDir(File)
     */
    String uploadUnique(String localFile)
            throws FileTransferException;

    /**
     * Uploads multiple files to server.
     * Uploads are performed relative to current local directory.
     *
     * @param localFiles filenames of files to upload
     *
     * @throws FileTransferException if an I/O or server error occurs.
     * @see #setLocalDir
     */
    void mupload(Enumeration localFiles)
            throws FileTransferException;

    /**
     * Uploads multiple files matching regular expression to server's current directory.
     * Uploads are performed relative to current local directory. For example, to upload
     * all files with extension .txt you may use the regular expression "<tt>.</tt><tt>*</tt><tt>\\.txt</tt>".
     *
     * @param regex the regular expression to use
     *
     * @throws FileTransferException if an I/O or server error occurs.
     * @see #setLocalDir
     */
    void mupload(String regex)
            throws FileTransferException;

    /**
     * Uploads local directory and contents.
     * Uploads are stored relative to current remote directory.
     *
     * @param localDirectory        the directory to upload
     * @param retryAttempts      retry number when an error occurs
     * @param checksumVerificationRequired whether or not to perform checksum verification
     * @param tempFileExtension       the temporary extension which will be used when uploading files or <code>null</code> to use current extension
     * @param threadCount
     *
     * @throws FileTransferException if an I/O or protocol related error occurs.
     */
    void uploadDir(File localDirectory, int retryAttempts, boolean checksumVerificationRequired, String tempFileExtension, int threadCount)
            throws FileTransferException;

    /**
     * Uploads local directory and contents.
     * Uploads are stored relative to current remote directory.
     *
     * @param localDirectory        the directory to upload
     * @param retryAttempts      retry number when an error occurs
     * @param checksumVerificationRequired whether or not to perform checksum verification
     * @param tempFileExtension       the temporary extension which will be used when uploading files or <code>null</code> to use current extension
     *
     * @throws FileTransferException if an I/O or protocol related error occurs.
     */
    void uploadDir(File localDirectory, int retryAttempts, boolean checksumVerificationRequired, String tempFileExtension)
            throws FileTransferException;

    /**
     * Uploads local directory and contents recursively to server.
     * Uploads are stored relative to current remote directory.
     * Files are uploaded with the extension specified in the argument extension but
     * when the upload has finished the remote file name is renamed to the original file name.
     *
     * @param localDirectory  the directory to upload
     * @param tempFileExtension The extension file name used to upload each file
     *
     * @throws FileTransferException if an I/O or protocol error occurs.
     */
    void uploadDir(File localDirectory, String tempFileExtension)
            throws FileTransferException;

    /**
     * Uploads local directory and contents recursively to server.
     * Uploads are stored relative to current remote directory.
     *
     * @param localDirectory the directory to upload
     *
     * @throws FileTransferException if an I/O or protocol error occurs.
     */
    void uploadDir(File localDirectory)
            throws FileTransferException;

    /**
     * Gets <code>InputStream</code> for remote file for reading.
     *
     * @param remoteFile the remote file to get <code>InputStream</code> for
     * @param remoteFileOffset        the byte offset, 0 to get full file
     *
     * @return an <code>InputStream</code>
     *
     * @throws FileTransferException if an I/O or protocol related error occurs
     */
    InputStream getInputStream(String remoteFile, long remoteFileOffset)
            throws FileTransferException;

    /**
     * Gets <code>OutputStream</code> for writing to remote file.
     *
     * @param remoteFile the remote filename
     * @param remoteFileOffset      the byte offset, 0 to write at beginning of file
     *
     * @return an <code>OutputStream</code>
     *
     * @throws FileTransferException if an I/O or protocol related error occurs
     */
    OutputStream getOutputStream(String remoteFile, long remoteFileOffset)
            throws FileTransferException;

    /**
     * Interrupts the current data transfer and sets interrupted flag to <code>true</code>.
     * After invoking this method you must reset the interrupted flag to <code>false</code>.
     * before transferring any files.
     *
     * @see #reset
     */
    void interrupt();

    /**
     * Checks if transfer process was interrupted.
     *
     * @return <code>true</code> if transfer process was interrupted.
     */
    boolean interrupted();

    /**
     * Resets the interrupted flag to <code>false</code>.
     * This method should be invoked if you have interrupted a transfer using the
     * <code>interrupt</code> method and wish to resume transfering files.
     *
     * @see #interrupt
     */
    void reset();

    /**
     * Abort all upload threads. Used by the implementing classes Sftp, Ftp, Ftps to abort all spawned threads.
     */
    void abortUploadThreads();

    /**
     * Abort upload thread.
     *
     * @param remoteFile
     */
    void abortUploadThread(String remoteFile);

    /**
     * Abort download thread.
     *
     * @param remoteFile
     */
    void abortDownloadThread(String remoteFile);

    /**
     * Abort all download threads. Used by the implementing classes Sftp, Ftp, Ftps to abort all spawned threads.
     */
    void abortDownloadThreads();

}
