using CommonLang;
using CommonLang.Concurrent;
using CommonLang.Property;
using MPQ.Updater;
using System.IO;
using System;
using CommonNetwork.Http;
using CommonLang.Log;

namespace MPQ
{
    public class MPQDirver
    {
        private Logger log = LoggerFactory.GetLogger("MPQDirver");

        /// <summary>
        /// 获取存储空间可用容量
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public virtual long GetAvaliableSpace(string path)
        {
            DriveInfo drive = new DriveInfo(Directory.GetDirectoryRoot(path));
            return drive.AvailableFreeSpace;
        }

        /// <summary>
        /// 获取存储空间总容量
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public virtual long GetTotalSpace(string path)
        {
            DriveInfo drive = new DriveInfo(Directory.GetDirectoryRoot(path));
            return drive.TotalSize;
        }

        /// <summary>
        /// 自定义获取文件MD5方法.
        /// </summary>
        /// <param name="fullname"></param>
        /// <param name="md5"></param>
        /// <returns></returns>
        public virtual bool RunGetFileMD5(string fullname, out string md5)
        {
            using (FileStream fs = new FileStream(fullname, FileMode.Open, FileAccess.Read))
            {
                md5 = CMD5.CalculateMD5(fs);
            }
            return true;
        }

        /// <summary>
        /// 自定义解压缩方法
        /// </summary>
        /// <param name="updater"></param>
        /// <param name="zip">压缩文件</param>
        /// <param name="mpq">解压缩文件</param>
        /// <param name="process">解压进度,process+=readed</param>
        /// <returns></returns>
        public virtual bool RunUnzipSingle(MPQUpdater updater, MPQUpdater.RemoteFileInfo zip, MPQUpdater.RemoteFileInfo mpq, AtomicLong process)
        {
            var type = ReflectionUtil.GetType("CommonMPQ.SharpZipLib.Unzip");
            var method = type.GetMethod("SharpZipLib_RunUnzipMPQ");
            return (bool)method.Invoke(null, new object[] { updater, zip, mpq, process });
        }

        /// <summary>
        /// 自定义下载方法
        /// </summary>
        /// <param name="updater"></param>
        /// <param name="inf">要下载的文件</param>
        /// <param name="exist_size">已下载大小</param>
        /// <param name="need_bytes">需要的大小</param>
        /// <param name="process">下载进度,process+=readed</param>
        /// <returns></returns>
        public virtual bool RunDownloadSingle(MPQUpdater updater, MPQUpdater.RemoteFileInfo inf, long exist_size, long need_bytes, AtomicLong process)
        {
            byte[] io_buffer = new byte[1024 * 1024];
            using (FileStream fos = new FileStream(inf.file.FullName, FileMode.Append, FileAccess.Write))
            {
                Stream input;
                using (WebClient www = connect_url(updater, inf.key, exist_size, need_bytes, out input))
                {
                    try
                    {
                        long total_readed = 0;
                        while (total_readed < need_bytes)
                        {
                            if (updater.IsDisposing) return false;
                            int readed = input.Read(io_buffer, 0, (int)Math.Min(io_buffer.Length, need_bytes - total_readed));
                            total_readed += readed;
                            process += readed;
                            fos.Write(io_buffer, 0, readed);
                        }
                        fos.Flush();
                    }
                    finally
                    {
                        fos.Close();
                    }
                }
            }
            return true;
        }
        protected virtual WebClient connect_url(MPQUpdater updater, string key, long exist_size, long expect_length, out Stream input)
        {
            for (int i = 0; i < updater.UrlRoots.Length; i++)
            {
                string path = updater.UrlRoots[i % updater.UrlRoots.Length] + key;
                path = path.Replace('\\', '/');
                Uri url = new Uri(path);
                WebClient http = new WebClient(url);
                http.TimeoutMS = updater.DownloadTimeoutSEC * 1000;
                if (exist_size > 0)
                {
                    http.Request.Params["Range"] = ("bytes=" + exist_size + "-");
                }
                try
                {
                    input = http.Connect();
                    if ((http.Response.ContentLength != expect_length))
                    {
                        throw new Exception("下载HTTP.ContentLength尺寸不匹配 : "
                            + http.Response.ContentLength + "\n" 
                            + url.ToString() + "\n"
                            + http.Response.Status );
                    }
                }
                catch (Exception err)
                {
                    log.Error("下载出错 : " + url + "\n  " + err.Message, err);
                    try
                    {
                        http.Dispose();
                    }
                    catch (Exception err2)
                    {
                        log.Error(err2.Message, err2);
                    }
                    continue;
                }
                return http;
            }
            throw new Exception("Can not connect to download root : " + CUtils.ArrayToString(updater.UrlRoots));
        }

    }


}