Inheritance: IIngestManifestFile
        /// <summary>
        /// Creates the manifest asset file asynchronously.
        /// </summary>
        /// <param name="ingestManifestAsset">The parent manifest asset.</param>
        /// <param name="filePath">The file path.</param>
        /// <param name="token"><see cref="CancellationToken"/></param>
        /// <returns><see cref="Task"/>of type <see cref="IIngestManifestFile"/></returns>
        public Task <IIngestManifestFile> CreateAsync(IIngestManifestAsset ingestManifestAsset, string filePath, CancellationToken token)
        {
            if (ingestManifestAsset == null)
            {
                throw new ArgumentNullException("ingestManifestAsset");
            }

            if (string.IsNullOrWhiteSpace(filePath))
            {
                throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, StringTable.ErrorCreatingIngestManifestFileEmptyFilePath));
            }

            AssetCreationOptions options = ingestManifestAsset.Asset.Options;

            Task <IIngestManifestFile> rootTask = new Task <IIngestManifestFile>(() =>
            {
                token.ThrowIfCancellationRequested();

                IngestManifestAssetCollection.VerifyManifestAsset(ingestManifestAsset);
                if (!File.Exists(filePath))
                {
                    throw new FileNotFoundException(String.Format(CultureInfo.InvariantCulture, StringTable.BulkIngestProvidedFileDoesNotExist, filePath));
                }
                FileInfo info = new FileInfo(filePath);

                DataServiceContext dataContext = this._cloudMediaContext.DataContextFactory.CreateDataServiceContext();

                // Set a MIME type based on the extension of the file name
                string mimeType = AssetFileData.GetMimeType(filePath);

                IngestManifestFileData data = new IngestManifestFileData
                {
                    Name     = info.Name,
                    MimeType = mimeType,
                    ParentIngestManifestId      = ingestManifestAsset.ParentIngestManifestId,
                    ParentIngestManifestAssetId = ingestManifestAsset.Id,
                    Path = filePath,
                };

                SetEncryptionSettings(ingestManifestAsset, info, options, data);

                dataContext.AddObject(EntitySet, data);

                Task <IIngestManifestFile> task = dataContext.SaveChangesAsync(data).ContinueWith <IIngestManifestFile>(t =>
                {
                    t.ThrowIfFaulted();
                    token.ThrowIfCancellationRequested();
                    IngestManifestFileData ingestManifestFile = (IngestManifestFileData)t.AsyncState;
                    return(ingestManifestFile);
                });

                return(task.Result);
            });

            rootTask.Start();
            return(rootTask);
        }
        /// <summary>
        /// Creates the manifest asset file asynchronously.
        /// </summary>
        /// <param name="ingestManifestAsset">The parent manifest asset.</param>
        /// <param name="filePath">The file path.</param>
        /// <param name="token"><see cref="CancellationToken"/></param>
        /// <returns><see cref="Task"/>of type <see cref="IIngestManifestFile"/></returns>
        public Task <IIngestManifestFile> CreateAsync(IIngestManifestAsset ingestManifestAsset, string filePath, CancellationToken token)
        {
            if (ingestManifestAsset == null)
            {
                throw new ArgumentNullException("ingestManifestAsset");
            }

            if (string.IsNullOrWhiteSpace(filePath))
            {
                throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, StringTable.ErrorCreatingIngestManifestFileEmptyFilePath));
            }

            AssetCreationOptions options = ingestManifestAsset.Asset.Options;

            Task <IIngestManifestFile> rootTask = new Task <IIngestManifestFile>(() =>
            {
                token.ThrowIfCancellationRequested();

                IngestManifestAssetCollection.VerifyManifestAsset(ingestManifestAsset);

                IMediaDataServiceContext dataContext = this.MediaContext.MediaServicesClassFactory.CreateDataServiceContext();

                // Set a MIME type based on the extension of the file name
                string mimeType = AssetFileData.GetMimeType(filePath);

                IngestManifestFileData data = new IngestManifestFileData
                {
                    Name     = Path.GetFileName(filePath),
                    MimeType = mimeType,
                    ParentIngestManifestId      = ingestManifestAsset.ParentIngestManifestId,
                    ParentIngestManifestAssetId = ingestManifestAsset.Id,
                    Path = filePath,
                };

                SetEncryptionSettings(ingestManifestAsset, options, data);

                dataContext.AddObject(EntitySet, data);

                MediaRetryPolicy retryPolicy = this.MediaContext.MediaServicesClassFactory.GetSaveChangesRetryPolicy(dataContext as IRetryPolicyAdapter);

                Task <IIngestManifestFile> task = retryPolicy.ExecuteAsync <IMediaDataServiceResponse>(() => dataContext.SaveChangesAsync(data))
                                                  .ContinueWith <IIngestManifestFile>(t =>
                {
                    t.ThrowIfFaulted();
                    token.ThrowIfCancellationRequested();
                    IngestManifestFileData ingestManifestFile = (IngestManifestFileData)t.Result.AsyncState;
                    return(ingestManifestFile);
                });

                return(task.Result);
            });

            rootTask.Start();
            return(rootTask);
        }
        private static Action GetEncryptionAction(
            CancellationToken cancellationToken,
            FileEncryption fileEncryption,
            IngestManifestFileData file,
            string destinationPath,
            FileInfo fileInfo,
            ConcurrentQueue <Tuple <int, int> > queue,
            int maxBlockSize)
        {
            Action action = () =>
            {
                cancellationToken.ThrowIfCancellationRequested();

                if (queue.Count > 0)
                {
                    using (var fs = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read))
                    {
                        Tuple <int, int> blockIdAndLength;
                        while (queue.TryDequeue(out blockIdAndLength))
                        {
                            cancellationToken.ThrowIfCancellationRequested();
                            var buffer       = new byte[blockIdAndLength.Item2];
                            var binaryReader = new BinaryReader(fs);

                            // Move the file system reader to the proper position.
                            fs.Seek(blockIdAndLength.Item1 * (long)maxBlockSize, SeekOrigin.Begin);
                            int readSize = binaryReader.Read(buffer, 0, blockIdAndLength.Item2);

                            while (readSize != blockIdAndLength.Item2)
                            {
                                readSize += binaryReader.Read(buffer, readSize, blockIdAndLength.Item2 - readSize);
                            }

                            bool lockWasTakenForEncode = false;
                            try
                            {
                                Monitor.Enter(fileEncryption, ref lockWasTakenForEncode);
                                using (FileEncryptionTransform encryptor = fileEncryption.GetTransform(file.Name, blockIdAndLength.Item1 * (long)maxBlockSize))
                                {
                                    encryptor.TransformBlock(buffer, 0, readSize, buffer, 0);
                                }
                            }
                            finally
                            {
                                if (lockWasTakenForEncode)
                                {
                                    Monitor.Exit(fileEncryption);
                                }
                            }

                            bool lockWasTakenForWrite = false;
                            try
                            {
                                Monitor.Enter(file, ref lockWasTakenForWrite);
                                using (var writeStream = new FileStream(destinationPath, FileMode.Open, FileAccess.Write))
                                {
                                    writeStream.Seek(blockIdAndLength.Item1 * (long)maxBlockSize, SeekOrigin.Begin);
                                    writeStream.Write(buffer, 0, readSize);
                                }
                            }
                            finally
                            {
                                if (lockWasTakenForWrite)
                                {
                                    Monitor.Exit(file);
                                }
                            }
                        }
                    }
                }
            };

            return(action);
        }
        private static Action GetEncryptionAction(
            CancellationToken cancellationToken,
            FileEncryption fileEncryption,
            IngestManifestFileData file,
            string destinationPath,
            FileInfo fileInfo,
            ConcurrentQueue<Tuple<int, int>> queue,
            int maxBlockSize)
        {
            Action action = () =>
                                {
                                    cancellationToken.ThrowIfCancellationRequested();

                                    if (queue.Count > 0)
                                    {
                                        using (var fs = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read))
                                        {
                                            Tuple<int, int> blockIdAndLength;
                                            while (queue.TryDequeue(out blockIdAndLength))
                                            {
                                                cancellationToken.ThrowIfCancellationRequested();
                                                var buffer = new byte[blockIdAndLength.Item2];
                                                var binaryReader = new BinaryReader(fs);

                                                // Move the file system reader to the proper position.
                                                fs.Seek(blockIdAndLength.Item1*(long) maxBlockSize, SeekOrigin.Begin);
                                                int readSize = binaryReader.Read(buffer, 0, blockIdAndLength.Item2);

                                                while (readSize != blockIdAndLength.Item2)
                                                {
                                                    readSize += binaryReader.Read(buffer, readSize, blockIdAndLength.Item2 - readSize);
                                                }

                                                bool lockWasTakenForEncode = false;
                                                try
                                                {
                                                    Monitor.Enter(fileEncryption, ref lockWasTakenForEncode);
                                                    using (FileEncryptionTransform encryptor = fileEncryption.GetTransform(file.Name, blockIdAndLength.Item1*(long) maxBlockSize))
                                                    {
                                                        encryptor.TransformBlock(buffer, 0, readSize, buffer, 0);
                                                    }
                                                }
                                                finally
                                                {
                                                    if (lockWasTakenForEncode) Monitor.Exit(fileEncryption);
                                                }

                                                bool lockWasTakenForWrite = false;
                                                try
                                                {
                                                    Monitor.Enter(file, ref lockWasTakenForWrite);
                                                    using (var writeStream = new FileStream(destinationPath, FileMode.Open, FileAccess.Write))
                                                    {
                                                        writeStream.Seek(blockIdAndLength.Item1*(long) maxBlockSize, SeekOrigin.Begin);
                                                        writeStream.Write(buffer, 0, readSize);
                                                    }
                                                }
                                                finally
                                                {
                                                    if (lockWasTakenForWrite) Monitor.Exit(file);
                                                }
                                            }
                                        }
                                    }
                                };
            return action;
        }
        private static void SetEncryptionSettings(IIngestManifestAsset ingestManifestAsset, AssetCreationOptions options, IngestManifestFileData data)
        {
            if (options.HasFlag(AssetCreationOptions.StorageEncrypted))
            {
                var contentKeyData = ingestManifestAsset.Asset.ContentKeys.Where(c => c.ContentKeyType == ContentKeyType.StorageEncryption).FirstOrDefault();
                if (contentKeyData == null)
                {
                    throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, StringTable.StorageEncryptionContentKeyIsMissing, ingestManifestAsset.Asset.Id));
                }
                using (var fileEncryption = new FileEncryption(contentKeyData.GetClearKeyValue(), EncryptionUtils.GetKeyIdAsGuid(contentKeyData.Id)))
                {
                    if (!fileEncryption.IsInitializationVectorPresent(data.Name))
                    {
                        fileEncryption.CreateInitializationVectorForFile(data.Name);
                    }
                    ulong iv = fileEncryption.GetInitializationVectorForFile(data.Name);

                    data.IsEncrypted          = true;
                    data.EncryptionKeyId      = fileEncryption.GetKeyIdentifierAsString();
                    data.EncryptionScheme     = FileEncryption.SchemeName;
                    data.EncryptionVersion    = FileEncryption.SchemeVersion;
                    data.InitializationVector = iv.ToString(CultureInfo.InvariantCulture);
                }
            }
            else if (options.HasFlag(AssetCreationOptions.CommonEncryptionProtected))
            {
                data.IsEncrypted       = true;
                data.EncryptionScheme  = CommonEncryption.SchemeName;
                data.EncryptionVersion = CommonEncryption.SchemeVersion;
            }
            else if (options.HasFlag(AssetCreationOptions.EnvelopeEncryptionProtected))
            {
                data.IsEncrypted       = true;
                data.EncryptionScheme  = EnvelopeEncryption.SchemeName;
                data.EncryptionVersion = EnvelopeEncryption.SchemeVersion;
            }
        }