using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Threading;
using System.Net;
using System.IO;
using System.Windows.Forms;
using System.Reflection;
using ryCommon;
//在线升级类
namespace LiveUpdate
{
    /// <summary>
    /// 
    /// </summary>
    public class ClsLiveUpdate
    {
        /// <summary>
        /// 升级地址
        /// </summary>
        public string UpdateUrl = ""; //升级地址
        private double SoftVer = 0; //软件版本
        private double ReVer = 0; //软件修正版本
        private string SoftDate = "";//软件日期
        private string SoftUpdateDes = "";//软件更新描述
        private string SoftUpdateDesUrl = "";//软件更新描述Url
        private double DataVer = 0;//数据库版本
        private string DataDate = "";//数据库日期
        private string DataUpdateDes = "";//数据库更新描述
        private string FileUpdateUrl = "";//文件更新地址
        private string FileVerUpdateUrl = "";//针对文件版本不同使用不同下载地址
        private string DbUpdateUrl = "";//数据库更新地址
        /// <summary>
        /// 
        /// </summary>
        public string CurUserId = "";//当前用户id
        /// <summary>
        /// 隔多久后再次检查更新
        /// </summary>
        private int UpdateAfterTime =0;
        /// <summary>
        /// 本地保存的配置信息
        /// </summary>
        public string SettingPath = "";//设置地址
        /// <summary>
        /// 当前安装的软件版本
        /// </summary>
        public double MySoftVer = 0; //软件版本
        /// <summary>
        /// 当前安装的软件修正版本
        /// </summary>
        public double MySoftRVer = 0; //软件修正版本
        /// <summary>
        /// 当前安装的数据库版本
        /// </summary>
        public double MyDataVer = 0;//数据库版本
        /// <summary>
        /// 
        /// </summary>
        public string SaveFileName = "tmp.tmp";//下载的文件保存文件
        /// <summary>
        /// 
        /// </summary>
        public string DownUrl = "";//下载地址
        /// <summary>
        /// 
        /// </summary>
        public bool isExit = false;
        private UpdateInfo m_UpdateType;
        /// <summary>
        /// 获取当前更新的类型
        /// </summary>
        public UpdateInfo UpdateType
        {
            get { return m_UpdateType; }
        }
        /// <summary>
        /// 每隔n小时检测一次更新
        /// </summary>
        public int UpdateLoopHours =0;//每隔n小时检测一次
        private delegate void dd1(bool message);
        private Thread threadOne;
        /// <summary>
        /// 读取版本信息完成后激发
        /// </summary>
        [Description("读取版本信息完成后激发")]
        public event EventHandler OnReadComplete;
        /// <summary>
        /// 没有版本更新时激发
        /// </summary>
        [Description("没有版本更新时激发")]
        public event EventHandler OnNoUpdate;
        /// <summary>
        /// 发现新版本时激发
        /// </summary>
        [Description("发现新版本时激发")]
        public event UpdateHandler OnUpdateComplete;
        /// <summary>
        /// 发生错误后激发
        /// </summary>
        [Description("发生错误后激发")]
        public event ErrorHandler OnHappenError;
        /// <summary>
        /// 更新进度变化后激发
        /// </summary>
        [Description("更新进度变化后激发")]
        public event LiveUpdate.LiveUpdateProgressChanged ProgressChanged;
        private LiveUpdate.LiveUpdateEventArgs _LiveUpdateEventArgs = new LiveUpdate.LiveUpdateEventArgs();
        /// <summary>
        /// 开始检测新版本
        /// </summary>
        public void StartLiveUpdate() //开始升级
        {
            if (threadOne != null) { threadOne.Abort(); }
            threadOne = new Thread(new ThreadStart(GetVerInfo));
            threadOne.SetApartmentState(ApartmentState.STA);
            threadOne.IsBackground = true;
            threadOne.Start();
        }
        /// <summary>
        /// 
        /// </summary>
        public Form ParentForm = null;
        /// <summary>
        /// 初始化升级函数
        /// </summary>
        /// <param name="ower">为null,则表示事件运行在多线程模式下，否则,事件是在窗体所在线程下</param>
        public ClsLiveUpdate(Form ower)
        {
            ParentForm = ower;
            MySoftVer = AssemblyVersion;
            MySoftRVer = AssemblyReVersion;
            SettingPath = Application.StartupPath + @"\cUpdate.dat";
            MyDataVer = 0;
        }
        /// <summary>
        /// 
        /// </summary>
        public double AssemblyVersion
        {
            get
            {
                System.Diagnostics.FileVersionInfo info = System.Diagnostics.FileVersionInfo.GetVersionInfo(Application.ExecutablePath);
                string[] ver_item = info.ProductVersion.Split('.');
                if (ver_item.Length == 4)
                {
                    return Convert.ToDouble(ver_item[0]+"."+ver_item[1]);
                }
                else
                {
                    return Convert.ToDouble(info.ProductMajorPart + "." + info.ProductMinorPart);
                }
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public double AssemblyReVersion
        {
            get
            {
                System.Diagnostics.FileVersionInfo info = System.Diagnostics.FileVersionInfo.GetVersionInfo(Application.ExecutablePath);
                string[] ver_item = info.ProductVersion.Split('.');
                if (ver_item.Length == 4)
                {
                    return Convert.ToDouble(ver_item[2] + "." + ver_item[3]);
                }
                else
                {
                    return Convert.ToDouble(info.ProductBuildPart.ToString() + "." + info.ProductPrivatePart);
                }
            }
        }
        private void OnNoUpdate_T()
        {
            if (ParentForm != null)
            {
                ParentForm.Invoke(new Action(() =>
                {
                    OnNoUpdate?.Invoke(this, new EventArgs());
                }));
            }
            else
            {
                OnNoUpdate?.Invoke(this, new EventArgs());
            }
        }
        private void OnReadComplete_T()
        {
            if (ParentForm != null)
            {
                ParentForm.Invoke(new Action(() =>
                {
                    OnReadComplete?.Invoke(this, new EventArgs());
                }));
            }
            else
            {
                OnReadComplete?.Invoke(this, new EventArgs());
            }
        }
        private void OnUpdateComplete_T(UpdateInfo e)
        {
            if (ParentForm != null)
            {
                ParentForm.Invoke(new Action(() =>
                {
                    OnUpdateComplete?.Invoke(e);
                }));
            }
            else
            {
                OnUpdateComplete?.Invoke(e);
            }
        }
        private void OnHappenError_T(UpdateErrorInfo e)
        {
            if (ParentForm != null)
            {
                ParentForm.Invoke(new Action(() =>
                {
                    OnHappenError?.Invoke(e);
                }));
            }
            else
            {
                OnHappenError?.Invoke(e);
            }
        }
        /// <summary>
        /// 获取版本信息
        /// </summary>
        private void GetVerInfo() //获取版本信息
        {
            #region 读取本地配置，判断是否需要更新
            ryCommon.Storage MyXml2 = new ryCommon.Storage();
            int iResult = 0;
            MyXml2.LoadFromFile(SettingPath);
            MyXml2.SelectNode("id", "UpdateAfterTime");
            UpdateAfterTime = MyXml2.GetAttrValue("Value", 0);
            DateTime LastUpdateTime;
            MyXml2.SelectNode("id", "LastUpdateTime");
            LastUpdateTime =MyXml2.GetAttrValue("Value", Convert.ToDateTime("2011-01-01"));
            if (UpdateLoopHours > 0)
            {
                if ((DateTime.Now - LastUpdateTime).TotalHours.ToInt() < UpdateLoopHours)
                {
                    OnNoUpdate_T();
                    return;
                }
            }
            if (UpdateAfterTime > 0)
            {
                if ((DateTime.Now.Date - LastUpdateTime.Date).Days < UpdateAfterTime)
                {
                    OnNoUpdate_T();
                    return;
                }
            }
            MyXml2.SelectNode2("id", "LastUpdateTime");
            MyXml2.SetAttrValue("Value", DateTime.Now.ToString());
            MyXml2.SaveToFile(SettingPath);
            #endregion
            ryCommon.Storage MyXml = new ryCommon.Storage();
            UpdateErrorInfo UpdateError;
            iResult=MyXml.LoadFromFile(UpdateUrl);
            if (iResult == 0)
            {
                UpdateError.ErrorId = 2;
                UpdateError.ErrorStr = "更新错误,读取远程文件失败";
                OnHappenError_T(UpdateError);
                OnNoUpdate_T();
                MyXml.LoadFromXMLText("<root></root>");
                return;
            }
            string SoftVersion = "未知";
            //软件版本
            MyXml.SelectNode2("id", "SoftVer");
            RySoft.GetVerByVerStr(MyXml.GetAttrValue("Value", "0"), out SoftVer, out ReVer);
            //SoftVer = ConvertDouble(MyXml.GetAttrValue("Value","0"),0);
            SoftVersion=MyXml.GetAttrValue("Value","0");
            //数据库版本
            MyXml.SelectNode2("id", "DataVer"); 
            DataVer = MyXml.GetAttrValue("Value", 0d);
            //软件更新地址
            MyXml.SelectNode2("id", "FileUpdateUrl");
            FileUpdateUrl = MyXml.GetAttrValue("Value", "");
            //软件版本更新地址
            MyXml.SelectNode2("id", "FileVerUpdateUrl");
            FileVerUpdateUrl = MyXml.GetAttrValue("Value", "");
            //数据库更新地址
            MyXml.SelectNode2("id", "DbUpdateUrl");
            DbUpdateUrl = MyXml.GetAttrValue("Value", "");
            //软件日期
            MyXml.SelectNode2("id", "SoftDate");
            SoftDate = MyXml.GetAttrValue("Value", "");
            //数据库日期
            MyXml.SelectNode2("id", "DataDate");
            DataDate = MyXml.GetAttrValue("Value", "");
            //软件更新描述
            MyXml.SelectNode2("id", "SoftUpdateDes");
            SoftUpdateDes = MyXml.GetAttrValue("Value", "");
            //软件更新描述Url
            MyXml.SelectNode2("id", "SoftUpdateDesUrl");
            SoftUpdateDesUrl = MyXml.GetAttrValue("Value", "");
            //数据库更新描述
            MyXml.SelectNode2("id", "DataUpdateDes");
            DataUpdateDes = MyXml.GetAttrValue("Value", "");
            //设置
            MyXml.SelectNode2("id", "SettingXML");
            string SettingXML = MyXml.GetAttrValue("Value", "");
            //在下载升级包前首先要下载的内容
            MyXml.SelectNode2("id", "FirstDownList");
            string FirstDownList = MyXml.GetAttrValue("Value", "");
            //允许更新的用户列表
            MyXml.SelectNode2("id", "UpdateUserList");
            string m_UpdateUserList ="|"+ MyXml.GetAttrValue("Value", "").Replace(";","|")+"|";
            if (MyXml.GetAttrValue("Value", "") == "")
            {
                m_UpdateUserList = "";
            }
            //激发事件
            OnReadComplete_T();
            //更新标志,1表示软件更新,2表示数据库更新
            int UpdateMarket = 0;//更新标志
            UpdateInfo myUpdate;
            myUpdate.UpdateDate = "";
            myUpdate.UpdateDes = "";
            myUpdate.UpdateDes_Url = "";
            myUpdate.UpdateVer ="未知";
            myUpdate.UpdateType = "";
            myUpdate.UpdateUrl = "";
            myUpdate.FirstDownList = FirstDownList;
            myUpdate.sxSettingXML = SettingXML;
            if(RySoft.CompareVer(MySoftVer, MySoftRVer, SoftVer, ReVer)==1)
            {
                UpdateMarket = 1;
                myUpdate.UpdateDate = SoftDate;
                myUpdate.UpdateDes = SoftUpdateDes;
                myUpdate.UpdateVer = SoftVersion;
                myUpdate.UpdateType = "soft";
                myUpdate.UpdateDes_Url = SoftUpdateDesUrl;
                if (FileVerUpdateUrl.Length > 0)
                {
                    var list = FileVerUpdateUrl.Replace("\r", "").Split('\n');
                    for (int i = 0; i < list.Length; i++)
                    {
                        var item = list[i].Split('|');
                        if (item.Length < 2) { continue; }
                        var ver = item[0];
                        var url = item[1];
                        RySoft.GetVerByVerStr(ver, out var _softver, out var _rever);
                        if (RySoft.CompareVer(_softver, _rever, MySoftVer, MySoftRVer) <= 0)
                        {
                            FileUpdateUrl = url; break;
                        }
                    }
                }
                myUpdate.UpdateUrl = FileUpdateUrl;
                DownUrl = FileUpdateUrl;
            }
            else
            {
                if (MyDataVer < DataVer) //如果本地数据库版本小于远程服务器版本
                {
                    UpdateMarket = 2;
                    myUpdate.UpdateDate = DataDate;
                    myUpdate.UpdateDes = DataUpdateDes;
                    myUpdate.UpdateVer = DataVer.ToString("0.000");
                    myUpdate.UpdateType = "data";
                    myUpdate.UpdateUrl = DbUpdateUrl;
                    DownUrl = DbUpdateUrl;
                }
            }
            if (UpdateMarket > 0)
            {
                //如果没有指定更新用户，或者包含在指定更新用户里，则有更新
                if (m_UpdateUserList.Length==0 || (m_UpdateUserList).IndexOf("|" + CurUserId + "|") >= 0)
                {
                    if (m_UpdateUserList.Length > 0 && CurUserId.Length == 0)
                    {
                        OnNoUpdate_T();
                    }
                    else
                    {
                        m_UpdateType = myUpdate;
                        OnUpdateComplete_T(myUpdate);
                    }
                }
                else
                {
                    OnNoUpdate_T();
                }
            }
            else
            {
                OnNoUpdate_T();
            }
        }
        Thread threadDown;
        /// <summary>
        /// 开始下载
        /// </summary>
        public void StartDownload()
        {
            isExit = false;
            if (threadDown != null)
            {
                threadDown.Abort();
            }
            threadDown = new Thread(new ThreadStart(_Download))
            {
                IsBackground = true
            };
            threadDown.Start();
        }
        /// <summary>
        /// 开始下载
        /// </summary>
        public void StartDownload(string fileurl, string filename)
        {
            isExit = false;
            if (threadDown != null)
            {
                threadDown.Abort();
            }
            threadDown = new Thread(delegate () { _Download(fileurl, filename); });
            threadDown.IsBackground = true;
            threadDown.Start();
        }
        /// <summary>
        /// 下载,不使用多线程
        /// </summary>
        public bool DownloadInUI(string fileurl, string filename)
        {
          isExit = false;
          return _Download(fileurl, filename);
        }
        /// <summary>
        /// 结束下载
        /// </summary>
        public void StopDownload()
        {
            if (threadDown != null)
            {
                threadDown.Abort();
            }
        }
        private void _Download()
        {
            _Download(DownUrl, Application.StartupPath + "\\Update\\" + SaveFileName);
        }
        private bool _Download(string fileurl, string filename)
        {
            int retry = 0;
        retryits:
            try
            {
                System.Net.ServicePointManager.DefaultConnectionLimit = 512;
                HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(fileurl);
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();

                long totalBytes = response.ContentLength;
                Stream st = response.GetResponseStream();
                Stream so = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);

                _DoEvent(fileurl, filename, totalBytes, 0, false, "开始下载....");

                long totalDownloadedByte = 0;
                byte[] by = new byte[4096];

                int osize = st.Read(by, 0, (int)by.Length);
                while (osize > 0)
                {
                    if (isExit)
                    { break; }
                    totalDownloadedByte = osize + totalDownloadedByte;
                    so.Write(by, 0, osize);
                    osize = st.Read(by, 0, (int)by.Length);

                    double p = totalDownloadedByte * 100.0 / totalBytes;
                    if (p >= 100.0) p = 100.0;

                    _DoEvent(fileurl, filename, totalBytes, p, false, String.Format("正在下载：{0}",RyFiles.GetFileSizeStr(totalDownloadedByte)));
                }

                so.Close();
                st.Close();
                _DoEvent(fileurl, filename, totalBytes, 100, true, "下载完成");
                if (isExit) { return false; }
                return true;
            }
            catch (Exception ex)
            {
                retry++;
                if (retry < 5)
                {
                    _DoEvent(fileurl, filename, 0, 0, false, String.Format("下载失败，第 {0} 次重试", retry));

                    // 休息 5 秒钟然后重试
                    Thread.Sleep(5000);
                    goto retryits;
                }
                else
                {
                    _DoEvent(fileurl, filename, 0, 0, false, "下载失败，原因是：" + ex.Message);
                    return false;
                }
            }
            finally
            {
                Thread.Sleep(100);
            }
        }
        private void _DoEvent(string url, string filename, long filesize, double progress, bool iscompleted, string currentstatus)
        {
            if (ProgressChanged != null)
            {
                _LiveUpdateEventArgs.CurrentFileName = filename;
                _LiveUpdateEventArgs.CurrentFileSize = filesize;
                _LiveUpdateEventArgs.CurrentUrl = url;
                _LiveUpdateEventArgs.CurrProgress = progress;
                _LiveUpdateEventArgs.IsCompleted = iscompleted;
                _LiveUpdateEventArgs.CurrentStatus = currentstatus;
                this.ProgressChanged(this, _LiveUpdateEventArgs);
                Application.DoEvents();
            }
        }

    }
}
