private void UploadSingleFile(ISftpFileUploader fileUploaderImplementation, string fileToUpload, string destinationPath, bool overWriteExistingFiles)
        {
            System.Diagnostics.Debug.WriteLine($"Will upload {fileToUpload}");

            // check if file can be read
            var fileAvailability = _fileAvailabilityChecker.CheckFileAvailability(fileToUpload);

            if (fileAvailability.FileAvailabilityResult != FileAvailabilityResult.IsReadable)
            {
                _logger.LogError($"File '{fileAvailability.FileName}' could not be read - {fileAvailability.Description}/{fileAvailability.FileAvailabilityResult}");
                return;
            }

            // Remove any trailing forward-slashes.
            if (destinationPath.EndsWith("/"))
            {
                destinationPath = destinationPath.Substring(0, destinationPath.Length - 1);
            }

            string sftpServerDestinationFilePath = destinationPath + @"/" + Path.GetFileName(fileToUpload);

            if (_sftpClient.Exists(sftpServerDestinationFilePath) && overWriteExistingFiles == false)
            {
                string fileNotUploadedMessage = ($"'{fileToUpload}' not uploaded - already exists in destination-dir '{destinationPath}'");
                _logger.LogInformation(fileNotUploadedMessage);
            }
            else if (_sftpClient.Exists(sftpServerDestinationFilePath) && overWriteExistingFiles == true)
            {
                // Exists, overwrite if size changed or newer.
                long existingFileSize = _sftpClient.GetAttributes(sftpServerDestinationFilePath).Size;
                long localFileSize    = new FileInfo(fileToUpload).Length;
                bool isDifferentSize  = existingFileSize != localFileSize;

                DateTime existingFileTimeStamp = _sftpClient.GetLastWriteTimeUtc(sftpServerDestinationFilePath);
                DateTime localFileTimeStamp    = File.GetLastWriteTimeUtc(fileToUpload);
                bool     localFileIsNewer      = localFileTimeStamp > existingFileTimeStamp;

                if (isDifferentSize || localFileIsNewer)
                {
                    fileUploaderImplementation.PerformFileUpload(fileToUpload, sftpServerDestinationFilePath, _sftpClient, _logger);
                    string fileUploadMessage = ($"Uploaded '{fileToUpload}' into destination-dir '{destinationPath}'");
                    _logger.LogInformation(fileUploadMessage);
                }
                else
                {
                    string fileNotUploadedMessage = ($"'{fileToUpload}' not uploaded - already exists in destination-dir '{destinationPath}'");
                    _logger.LogInformation(fileNotUploadedMessage);
                }
            }
            else
            {
                // All-new file, just upload it.
                fileUploaderImplementation.PerformFileUpload(fileToUpload, sftpServerDestinationFilePath, _sftpClient, _logger);
                string fileUploadMessage = ($"Uploaded '{fileToUpload}' into destination-dir '{destinationPath}'");
                _logger.LogInformation(fileUploadMessage);
            }
        }
        public void Upload(TransferSettings transferSettings)
        {
            #region guard clause

            if (String.IsNullOrWhiteSpace(transferSettings.DestinationPath))
            {
                if (string.IsNullOrWhiteSpace(_connectivitySettings.UserName))
                {
                    throw new NotImplementedException("Could not form a destination path based on the user's name - it is blank");
                }

                _logger.LogInformation($"Blank destination-path, will rename to user's home dir");
                transferSettings.DestinationPath = $@"/home/{_connectivitySettings.UserName}";
            }

            #endregion guard clause

            _logger.LogInformation($"Will upload into directory '{transferSettings.DestinationPath}'");
            CreateServerDirectoryIfItDoesntExist(transferSettings.DestinationPath);

            // Create uploader-implementation
            ISftpFileUploader fileUploaderImplementation = CreateSftpUploaderFromTransferSettings(transferSettings, _logger);

            //detect whether its a directory or file, and act accordingly
            FileAttributes fileSystemEntryAttributes = File.GetAttributes(transferSettings.SourcePath);
            if ((fileSystemEntryAttributes & FileAttributes.Directory) == FileAttributes.Directory)
            {
                bool shouldZipCompressDirectoryBeforeUpload = transferSettings.CompressDirectoryBeforeUpload;
                if (shouldZipCompressDirectoryBeforeUpload)
                {
                    string        tempPath = Path.GetTempPath();
                    DirectoryInfo dirInfo  = new DirectoryInfo(transferSettings.SourcePath);
                    string        compressedZipFileFullPath = tempPath + @"\" + dirInfo.Name + ".zip";
                    if (File.Exists(compressedZipFileFullPath))
                    {
                        File.Delete(compressedZipFileFullPath);
                    }

                    ZipFile.CreateFromDirectory(transferSettings.SourcePath, compressedZipFileFullPath);

                    UploadSingleFile(fileUploaderImplementation, compressedZipFileFullPath, transferSettings.DestinationPath, transferSettings.OverWriteExistingFiles);
                }
                else
                {
                    UploadDirectory(transferSettings, fileUploaderImplementation);
                }
            }
            else // is file
            {
                string pathOfFileToUpload = transferSettings.SourcePath;
                UploadSingleFile(fileUploaderImplementation, pathOfFileToUpload, transferSettings.DestinationPath, transferSettings.OverWriteExistingFiles);
            }
        }
        /// <summary>
        /// Will upload an entire directory of files and, recursively, directories within.
        /// </summary>
        public void UploadDirectory(TransferSettings transferSettings, ISftpFileUploader fileUploaderImplementation)
        {
            try
            {
                System.Diagnostics.Debug.WriteLine($"Uploading directory {transferSettings.SourcePath}");
                _logger.LogInformation($"Uploading directory {transferSettings.SourcePath}");

                // upload files within directory
                IEnumerable <string> filesToUpload = Directory.EnumerateFiles(transferSettings.SourcePath, "*.*").ToList();

                // upload all individual files into the server directory
                int uploadedFileCounter = 1;
                foreach (string fileToUpload in filesToUpload)
                {
                    UploadSingleFile(fileUploaderImplementation, fileToUpload, transferSettings.DestinationPath, transferSettings.OverWriteExistingFiles);
                    uploadedFileCounter++;
                }

                // Traverse any sub-directories
                DirectoryInfo   dirInfo        = new DirectoryInfo(transferSettings.SourcePath);
                DirectoryInfo[] subDirectories = dirInfo.GetDirectories();
                if (!subDirectories.Any())
                {
                    return;
                }

                foreach (DirectoryInfo subDir in subDirectories)
                {
                    // Shallow copy transfer-settings object ...
                    TransferSettings copiedTransferSettings = new TransferSettings
                    {
                        OverWriteExistingFiles = transferSettings.OverWriteExistingFiles,
                        SourcePath             = subDir.FullName,
                        DestinationPath        = transferSettings.DestinationPath + @"/" + subDir.Name
                    };
                    _logger.LogInformation($"Will upload into directory '{subDir.Name}'");

                    // ... then call UploadDirectory() recursively.
                    CreateServerDirectoryIfItDoesntExist(copiedTransferSettings.DestinationPath);
                    UploadDirectory(copiedTransferSettings, fileUploaderImplementation);
                }
            }
            catch (Exception e)
            {
                throw new DotNetSftpClientException(e.Message, e);
            }
        }