/// <summary>
        /// Creates and initializes an instance of IOrchestratedJob of the specified type.
        /// </summary>
        /// <param name="jobDetails">
        /// Details describing the IOrchestratedJob type to create.
        /// </param>
        /// <param name="scheduler">
        /// The scheduler managing the job.
        /// </param>
        /// <param name="log">
        /// The object through which log entries can be made.
        /// </param>
        /// <returns>
        /// An instance of IOrchestratedJob of the specified type.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// * Parameter jobDetails cannot be null.
        /// -OR-
        /// * Parameter log cannot be null.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Parameter JobDetails does not specify a valid IOrchestratedJob type.
        /// </exception>
        public static IOrchestratedJob Create(ScheduledJobDetails jobDetails,
                                              IScheduler scheduler,
                                              CommerceLog log)
        {
            if (jobDetails == null)
            {
                throw new ArgumentNullException("jobDetails", "Parameter jobDetails cannot be null.");
            }

            if (log == null)
            {
                throw new ArgumentNullException("log", "Parameter log cannot be null.");
            }

            IOrchestratedJob result = null;

            if (jobDetails.Payload != null)
            {
                switch (jobDetails.JobType)
                {
                case ScheduledJobType.ApplyReferralReward:
                    result = new ApplyReferralRewardJob(log);
                    break;

                case ScheduledJobType.ApplyRedemptionReward:
                    result = new ApplyRedemptionRewardJob(log);
                    break;

                case ScheduledJobType.ClaimDiscountsForNewCard:
                    result = new ClaimDiscountsForNewCardJob(log);
                    break;

                case ScheduledJobType.ClaimDiscountForExistingCards:
                    result = new ClaimDiscountForExistingCardsJob(log);
                    break;

                case ScheduledJobType.AmexOfferRegistration:
                    result = new AmexOfferRegistrationJob(log);
                    break;

                default:
                    throw new ArgumentException("Parameter JobDetails does not specify a valid IOrchestratedJob type.",
                                                "jobDetails");
                }

                result.Initialize(jobDetails, scheduler);
            }
            else
            {
                log.Error("{0} orchestrated job contains no Payload.", null, jobDetails.JobType,
                          ResultCode.JobContainsNoPayload);
            }

            return(result);
        }
        /// <summary>
        /// Process MasterCard clearing file job execution.
        /// </summary>
        /// <param name="details">
        /// Details of the job to be executed.
        /// </param>
        /// <param name="log">
        /// Log within which to log status of job processing.
        /// </param>
        /// <returns>
        /// A task to execute the  job.
        /// </returns>
        /// <remarks>
        /// Once complete, this job will schedule a corresponding MasterCardProcessClearingJob.
        /// </remarks>
        public async Task Execute(ScheduledJobDetails details,
                                  CommerceLog log)
        {
            Log = log;
            Log.Verbose("Starting execution of job.\r\nDetails {0}", details);

            MasterCardClearingBlobClient blobClient = MasterCardBlobClientFactory.MasterCardClearingBlobClient(log);

            // Download files from MasterCard and upload them to the blob store.
            IFtpClient ftpClient = MasterCardFtpClientFactory.ClearingFtpClient(Log);

            string[] files = await ftpClient.DirectoryListAsync();

            if (files != null)
            {
                foreach (string fileName in files)
                {
                    using (MemoryStream memStream = new MemoryStream())
                    {
                        // Download the file from MasterCard.
                        await ftpClient.DownloadFileAsync(fileName, memStream).ConfigureAwait(false);

                        // Upload the file to the blob store.
                        memStream.Position = 0;
                        await blobClient.UploadAsync(memStream, fileName).ConfigureAwait(false);
                    }
                }
            }

            // Process all pending clearing files in the blob store.
            ICollection <string> fileNames = blobClient.RetrieveNamesOfPendingFiles();

            if (fileNames != null)
            {
                foreach (string fileName in fileNames)
                {
                    using (MemoryStream memoryStream = new MemoryStream())
                    {
                        // Download the file from the blob store.
                        try
                        {
                            memoryStream.Position = 0;
                            await blobClient.DownloadAsync(memoryStream, fileName).ConfigureAwait(false);
                        }
                        catch (Exception ex)
                        {
                            Log.Error("Unexpected Exception when downloading Clearing File from Blob store.", ex);
                            throw;
                        }

                        // Process the file.
                        try
                        {
                            memoryStream.Position = 0;
                            ISettlementFileProcessor clearingProcessor = MasterCardFileProcessorFactory.MasterCardClearingProcessor(memoryStream, fileName);
                            await clearingProcessor.Process().ConfigureAwait(false);
                        }
                        catch (Exception ex)
                        {
                            Log.Error("Unexpected Exception when processing Clearing File.", ex);
                            throw;
                        }
                    }

                    // Mark the file as having been processed.
                    await blobClient.MarkAsCompleteAsync(fileName).ConfigureAwait(false);
                }
            }

            Log.Verbose("Execution of job {0} complete ", details.JobId);
        }