using Common.Model;

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;

namespace Common.system
{
    /// <summary>
    /// 下载方法
    /// 创建人：赵耀
    /// 创建时间：2018年10月30日
    /// </summary>
    public class DownloadManager
    {
        private long fromIndex = 0;//开始下载的位置
        private bool isRun = false;//是否正在进行
        private DownloadInfoModel dlInfo;

        private List<DownloadService> dls = new List<DownloadService>();
        /// <summary>
        /// 开始下载
        /// </summary>
        public event Action OnStart;
        /// <summary>
        /// 停止下载
        /// </summary>
        public event Action OnStop;
        /// <summary>
        /// 下载进度
        /// </summary>
        public event Action<long, long, string> OnDownload;
        /// <summary>
        /// 下载完成
        /// </summary>
        public event Action<string> OnFinsh;
        /// <summary>
        /// 断开网络连接
        /// </summary>
        public event Action<string> OnDisconnect;

        public DownloadManager(DownloadInfoModel dlInfo)
        {
            this.dlInfo = dlInfo;
        }
        /// <summary>
        /// 暂停
        /// </summary>
        public void Stop()
        {
            isRun = false;
            dls.ForEach(dl => dl.Stop());
            OnStopHandler();
        }
        /// <summary>
        /// 开始下载
        /// </summary>
        public void Start()
        {
            dlInfo.isReStart = false;
            WorkStart();
        }
        /// <summary>
        /// 重新下载
        /// </summary>
        public void ReStart()
        {
            dlInfo.isReStart = true;
            WorkStart();
        }
        /// <summary>
        /// 下载
        /// </summary>
        private void WorkStart()
        {
            new Action(() =>
            {
                if (dlInfo.isReStart)
                {
                    Stop();
                }

                while (dls.Where(dl => !dl.isStopped).Count() > 0)
                {
                    if (dlInfo.isReStart)
                    {
                        Thread.Sleep(100);
                    }
                    else
                    {
                        return;
                    }
                }

                isRun = true;
                OnStartHandler();
                //首次任务或者不支持断点续传的进入
                if (dlInfo.isNewTask || (!dlInfo.isNewTask && !dlInfo.IsSupportMultiThreading))
                {
                    try
                    {
                        //第一次请求获取一小块数据，根据返回的情况判断是否支持断点续传
                        using (System.Net.WebResponse rsp = HttpHelper.Download(dlInfo.downloadUrlList[0], 0, 0, dlInfo.method))
                        {

                            //获取文件名，如果包含附件名称则取下附件，否则从url获取名称
                            string Disposition = rsp.Headers["Content-Disposition"];
                            try
                            {
                                if (Disposition != null)
                                {
                                    dlInfo.fileName = Disposition.Split('=')[1];
                                }
                                else
                                {
                                    dlInfo.fileName = Path.GetFileName(rsp.ResponseUri.AbsolutePath);
                                }
                            }
                            catch (Exception)//无法获取文件名时  使用传入保存名称
                            {
                                dlInfo.fileName = dlInfo.saveFileName;
                            }

                            //默认给流总数
                            dlInfo.count = rsp.ContentLength;
                            //尝试获取 Content-Range 头部，不为空说明支持断点续传
                            string contentRange = rsp.Headers["Content-Range"];
                            if (contentRange != null)
                            {
                                //支持断点续传的话，就取range 这里的总数
                                dlInfo.count = long.Parse(rsp.Headers["Content-Range"].Split('/')[1]);
                                dlInfo.IsSupportMultiThreading = true;

                                //生成一个临时文件名
                                //var tempFileName = Convert.ToBase64String(Encoding.UTF8.GetBytes(dlInfo.fileName)).ToUpper();
                                //tempFileName = tempFileName.Length > 32 ? tempFileName.Substring(0, 32) : tempFileName;
                                //dlInfo.tempFileName = "test"; //tempFileName + DateTime.Now.ToString("yyyyMMddHHmmssfff");
                                ///创建线程信息
                                ///
                                GetTaskInfo(dlInfo);

                            }
                            else
                            {
                                //不支持断点续传则一开始就直接读完整流
                                Save(GetRealFileName(dlInfo), rsp.GetResponseStream());
                                OnFineshHandler();
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        string ErrMessage = "【下载】(DownloadManager):" + ex.Message;
                        LogHelper.WriteErrLog(ErrMessage, ex);
                        OnDisconnectHandler();
                        return;
                    }
                    dlInfo.isNewTask = false;
                }
                //如果支持断点续传采用这个
                if (dlInfo.IsSupportMultiThreading)
                {
                    StartTask(dlInfo);

                    //等待合并
                    while (dls.Where(td => !td.isFinish).Count() > 0 && isRun)
                    {
                        Thread.Sleep(100);
                    }
                    if ((dls.Where(td => !td.isFinish).Count() == 0))
                    {

                        CombineFiles(dlInfo);
                        OnFineshHandler();
                    }
                }

            }).BeginInvoke(null, null);
        }
        /// <summary>
        /// 合成文件
        /// </summary>
        /// <param name="dlInfo"></param>
        private void CombineFiles(DownloadInfoModel dlInfo)
        {
            string realFilePath = GetRealFileName(dlInfo);

            //合并数据
            byte[] buffer = new byte[2048];
            int length;
            using (FileStream fileStream = File.Open(realFilePath, FileMode.CreateNew))
            {
                for (int i = 0; i < dlInfo.TaskInfoList.Count; i++)
                {
                    string tempFile = dlInfo.TaskInfoList[i].filePath;
                    using (FileStream tempStream = File.Open(tempFile, FileMode.Open))
                    {
                        while ((length = tempStream.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            fileStream.Write(buffer, 0, length);
                        }
                        tempStream.Flush();
                    }
                    //File.Delete(tempFile);
                }
            }
        }
        /// <summary>
        /// 创建文件
        /// </summary>
        /// <param name="dlInfo"></param>
        /// <returns></returns>
        private static string GetRealFileName(DownloadInfoModel dlInfo)
        {
            //创建正式文件名，如果已存在则加数字序号创建，避免覆盖
            int fileIndex = 0;
            string realFilePath = Path.Combine(dlInfo.saveDir, dlInfo.saveFileName);
            while (File.Exists(realFilePath))
            {
                realFilePath = Path.Combine(dlInfo.saveDir, string.Format("{0}_{1}", fileIndex++, dlInfo.fileName));
            }

            return realFilePath;
        }

        private void StartTask(DownloadInfoModel dlInfo)
        {
            dls = new List<DownloadService>();
            if (dlInfo.TaskInfoList != null)
            {
                foreach (TaskInfoModel item in dlInfo.TaskInfoList)
                {
                    DownloadService dl = new DownloadService();
                    dl.OnDownload += OnDownloadHandler;
                    dl.OnDisconnect += OnDisconnectHandler;
                    dls.Add(dl);
                    try
                    {
                        dl.Start(item, dlInfo.isReStart);
                    }
                    catch (Exception ex)
                    {
                        string ErrMessage = "【下载】(DownloadManager):" + ex.Message;
                        LogHelper.WriteErrLog(ErrMessage, ex);
                    }
                }
            }
        }

        /// <summary>
        /// 创建下载任务
        /// </summary>
        /// <param name="dlInfo"></param>
        private void GetTaskInfo(DownloadInfoModel dlInfo)
        {
            long pieceSize = (dlInfo.count) / dlInfo.taskCount;
            dlInfo.TaskInfoList = new List<TaskInfoModel>();
            //Random rand = new Random();
            int urlIndex = 0;
            for (int i = 0; i <= dlInfo.taskCount + 1; i++)
            {
                long from = (i * pieceSize);

                if (from >= dlInfo.count)
                {
                    break;
                }

                long to = from + pieceSize;
                if (to >= dlInfo.count)
                {
                    to = dlInfo.count;
                }

                dlInfo.TaskInfoList.Add(
                    new TaskInfoModel
                    {
                        method = dlInfo.method,
                        downloadUrl = dlInfo.downloadUrlList[urlIndex++],

                        filePath = Path.Combine(dlInfo.saveDir, dlInfo.tempFileName + ".temp" + i),
                        fromIndex = from,
                        toIndex = to
                    });
                if (urlIndex >= dlInfo.downloadUrlList.Count)
                {
                    urlIndex = 0;
                }
            }
        }

        /// <summary>
        /// 保存内容
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="stream"></param>
        private void Save(string filePath, Stream stream)
        {
            try
            {
                using (FileStream writer = File.Open(filePath, FileMode.Append))
                {
                    using (stream)
                    {
                        int repeatTimes = 0;
                        byte[] buffer = new byte[1024];
                        int length = 0;
                        while ((length = stream.Read(buffer, 0, buffer.Length)) > 0 && isRun)
                        {
                            writer.Write(buffer, 0, length);
                            fromIndex += length;
                            if (repeatTimes % 5 == 0)
                            {
                                writer.Flush();//一定大小就刷一次缓冲区
                                OnDownloadHandler();
                            }
                            repeatTimes++;
                        }
                        writer.Flush();
                        OnDownloadHandler();
                    }
                }
            }
            catch (Exception)
            {
                //异常也不影响
            }
        }

        /// <summary>
        /// 开始下载
        /// </summary>
        private void OnStartHandler()
        {
            new Action(() =>
            {
                OnStart.Invoke();
            }).BeginInvoke(null, null);
        }
        /// <summary>
        /// 暂停下载
        /// </summary>
        private void OnStopHandler()
        {
            new Action(() =>
            {
                OnStop.Invoke();
            }).BeginInvoke(null, null);
        }
        /// <summary>
        /// 下载完成
        /// </summary>
        private void OnFineshHandler()
        {
            new Action(() =>
            {
                for (int i = 0; i < dlInfo.TaskInfoList.Count; i++)
                {
                    string tempFile = dlInfo.TaskInfoList[i].filePath;
                    File.Delete(tempFile);
                }
                OnFinsh.Invoke(dlInfo.saveFileName);
            }).BeginInvoke(null, null);
        }
        /// <summary>
        /// 下载进度
        /// </summary>
        private void OnDownloadHandler()
        {
            new Action(() =>
            {
                long current = GetDownloadLength();
                OnDownload.Invoke(current, dlInfo.count, dlInfo.saveFileName);
            }).BeginInvoke(null, null);
        }
        /// <summary>
        /// 断开网络连接
        /// </summary>
        private void OnDisconnectHandler()
        {
            new Action(() =>
            {
                OnDisconnect.Invoke(dlInfo.saveFileName);
            }).BeginInvoke(null, null);
        }
        /// <summary>
        /// 当前下载进度
        /// </summary>
        /// <returns></returns>
        public long GetDownloadLength()
        {
            if (dlInfo.IsSupportMultiThreading)
            {
                return dls.Sum(dl => dl.GetDownloadedCount());
            }
            else
            {
                return fromIndex;
            }
        }

        /// <summary>
        /// 获取保存文件名
        /// </summary>
        /// <returns></returns>
        public DownloadInfoModel GetFileInfo => dlInfo;

    }
}
