public void Download(byte[] data, int bufferSize, DownloadSegmentPositions[] segmentPositionInfos)
        {
            BeforeDownload();

            DownloadStream inputStream = new DownloadStream(data);

            IList<ISegmentDownloadTask> segmentDownloadTasks = new List<ISegmentDownloadTask>(segmentPositionInfos.Length);
            IList<DownloadStream> downloadStreams = new List<DownloadStream>(segmentPositionInfos.Length);
            MemoryStream outputStream = new MemoryStream();
            for (int i = 0; i < segmentPositionInfos.Length; i++)
            {
                DownloadSegmentPositions segmentPosition = segmentPositionInfos[i];
                byte[] dataPart = data.Skip((int) segmentPosition.StartPosition).Take((int)(segmentPosition.EndPosition - segmentPosition.StartPosition + 1)).ToArray();
                DownloadStream downloadStream = new DownloadStream(dataPart);
                segmentDownloadTasks.Add(CreateSegmentDownloadTask(bufferSize, CreateSegmentDownloader(downloadStream, segmentPosition), CreateSegmentWriter(outputStream)));
                downloadStreams.Add(downloadStream);
            }

            SegmentDownloadManager segmentDownloadManager = new SegmentDownloadManager(new SegmentDownloadTaskCollection(segmentDownloadTasks));
            segmentDownloadManager.Start();
            segmentDownloadManager.Finish(true);

            AfterDownload();

            long totalDownloads = downloadStreams.Sum(x => x.TotalDownloads);
            Assert.AreEqual(data.Length, totalDownloads);
            Assert.AreEqual(inputStream.ToArray().Take(data.Length).ToArray(), outputStream.ToArray().Take(data.Length).ToArray());
            Assert.AreEqual(inputStream.ToArray(), outputStream.ToArray());
        }
        /// <summary>
        /// Starts the download task.
        /// </summary>
        public void StartDownload()
        {
            RemoteFileInfo remoteFileInfo = null;

            try
            {
                ChangeState(DownloadTaskState.Preparing);

                m_StartDate = DateTime.Now;

                INetworkProtocolProvider networkProtocolProvider = m_NetworkProtocolProviderFactory.CreateProvider(m_File.Uri);

                remoteFileInfo = networkProtocolProvider.GetRemoteFileInfo(m_File);
                remoteFileInfo.FileName = m_File.FileName;

                m_FileSize = remoteFileInfo.FileSize;
                m_IsResumable = remoteFileInfo.AcceptRanges;

                DownloadSegmentPositions[] segmentPositionInfos;

                if (remoteFileInfo.AcceptRanges)
                {
                    segmentPositionInfos = m_DownloadSegmentCalculator.Calculate(m_Settings.MinimumSegmentSize, m_Settings.MaximumSegmentCount, m_File.SegmentCount, remoteFileInfo.FileSize);                    
                }
                else
                {
                    segmentPositionInfos = new[] { new DownloadSegmentPositions(0, remoteFileInfo.FileSize - 1) };
                }

                using (Stream stream = m_DownloadStreamManager.CreateStream(remoteFileInfo))
                {
                    SegmentWriter segmentWriter = new SegmentWriter(stream);
                    SegmentDownloadTasks = new SegmentDownloadTaskCollection(segmentPositionInfos.Length);
                    for (int i = 0; i < segmentPositionInfos.Length; i++)
                    {
                        DownloadSegmentPositions segmentPosition = segmentPositionInfos[i];
                        SegmentDownloadTasks.Add(new DoubleBufferSegmentDownloadTask(m_Settings.DownloadBufferSize, new SegmentDownloader(m_File, networkProtocolProvider, segmentPosition, new SegmentDownloadRateCalculator(segmentPosition.StartPosition)), segmentWriter));
                    }

                    SegmentDownloadManager segmentDownloadManager = new SegmentDownloadManager(SegmentDownloadTasks);
                    segmentDownloadManager.Start();

                    ChangeState(DownloadTaskState.Working);

                    segmentDownloadManager.Finish(true);

                    ChangeState(DownloadTaskState.Ended);

                    m_EventManager.EventPublisher.Publish(new DownloadTaskFinishedEventMessage(this, stream, remoteFileInfo));
                }
            }
            catch (Exception ex)
            {
                if (m_RetryCount < m_Settings.MaximumRetries)
                {
                    m_RetryCount++;
                    
                    StartDownload();
                }
                else
                {
                    m_LastException = ex;

                    ChangeState(DownloadTaskState.EndedWithError);

                    m_EventManager.EventPublisher.Publish(new DownloadTaskFinishedEventMessage(this, null, remoteFileInfo));
                }
            }
        }