using Tiobon.Core.OPS.Tool.OPS.Tool.Model;
using ICSharpCode.SharpZipLib.Core;
using ICSharpCode.SharpZipLib.Zip;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Net;
using System.Net.NetworkInformation;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Runtime.Serialization.Formatters.Binary;
using System.Dynamic;

namespace Tiobon.Core.OPS.Tool.OPS.Tool.Helper
{
    public static class Const
    {
        public static Config config { get; set; }
        public static List<MultiEnvInfo> MultiEnvs { get; set; }
        public static string Version { get; set; }
        public static string Script_path { get; set; }
        private static string Task_log = "";
        public static string Port { get; set; }

        #region 写日志
        private static string LastLog;
        public static void write_log(string log)
        {
            lock (config)
            {
                try
                {
                    if (LastLog != log)
                    {
                        Directory.CreateDirectory("Logs");
                        string filename = "Logs/" + DateTime.Now.ToString("yyyy-MM-dd") + ".log";
                        using (StreamWriter fs = new StreamWriter(filename, true))
                        {
                            fs.Write(DateTime.Now.ToString("yy-MM-dd HH:mm:ss") + $":  {log}\n");
                        }
                        LastLog = log;
                    }
                }
                catch { }
            }
        }
        #endregion

        #region 写运行状态
        public static void write_task_log(string taskinfo)
        {
            Task_log = taskinfo;
            write_log(taskinfo);
        }
        #endregion

        #region 读取运行状态
        public static string read_task_log()
        {
            return Task_log;
        }
        #endregion

        #region 获取文件md5值
        public static string GetMD5(string filePath)
        {
            FileStream file = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            byte[] hash_byte = md5.ComputeHash(file);
            string str = System.BitConverter.ToString(hash_byte);
            str = str.Replace("-", "");
            return str;
        }
        #endregion

        #region aes加密解密
        /// <summary>
        /// aes加密
        /// </summary>
        /// <param name="text"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string AesEncrypt(string text, string key)
        {
            if (string.IsNullOrEmpty(text)) return null;
            Byte[] toEncryptArray = Encoding.UTF8.GetBytes(text);

            RijndaelManaged rm = new RijndaelManaged
            {
                Key = Encoding.UTF8.GetBytes(key),
                Mode = CipherMode.ECB,
                Padding = PaddingMode.PKCS7
            };

            ICryptoTransform cTransform = rm.CreateEncryptor();
            Byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);

            return Convert.ToBase64String(resultArray, 0, resultArray.Length);
        }

        /// <summary>
        ///  AES 解密
        /// </summary>
        /// <param name="str">明文（待解密）</param>
        /// <param name="key">密文</param>
        /// <returns></returns>
        public static string AesDecrypt(string str, string key)
        {
            if (string.IsNullOrEmpty(str)) return null;
            Byte[] toEncryptArray = Convert.FromBase64String(str);

            RijndaelManaged rm = new RijndaelManaged
            {
                Key = Encoding.UTF8.GetBytes(key),
                Mode = CipherMode.ECB,
                Padding = PaddingMode.PKCS7
            };

            ICryptoTransform cTransform = rm.CreateDecryptor();
            Byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);

            return Encoding.UTF8.GetString(resultArray);
        }
        #endregion

        #region zip解压
        /// <summary>
        /// 检查文件是否已损坏
        /// </summary>
        /// <param name="comment"></param>
        /// <returns></returns>
        public static bool Is_BadZip(string fname, out string comment)
        {
            comment = string.Empty;
            try
            {
                using (FileStream fs = new FileStream(fname, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                {
                    ZipFile entry = new ZipFile(fname);
                    comment = entry.ZipFileComment;
                }
                return true;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 快速解压
        /// </summary>
        /// <param name="zipFilePath">压缩文件路径</param>
        /// <param name="extractPath">解压路径</param>
        /// <param name="pwd">压缩密码</param>
        /// <param name="progressFun">进程</param>
        /// <param name="seconds">触发时间</param>
        /// <param name="comment">注释</param>
        public static void ExtractZipFile(string zipFilePath, string extractPath, string pwd, ProcessFileHandler progressFun)
        {
            FastZipEvents events = new FastZipEvents();
            if (progressFun != null)
            {
                //events.ProcessDirectory = 
                events.ProcessFile += progressFun;
                events.ProgressInterval += TimeSpan.FromSeconds(0.2);
            }
            FastZip zip = new FastZip(events);
            zip.CreateEmptyDirectories = true;
            if (!string.IsNullOrEmpty(pwd))
                zip.Password = pwd;
            zip.UseZip64 = UseZip64.On;
            zip.RestoreAttributesOnExtract = true;
            zip.RestoreDateTimeOnExtract = true;
            zip.ExtractZip(zipFilePath, extractPath, FastZip.Overwrite.Always, null, "", "", true);
        }


        /// <summary>
        /// 解压指定文件
        /// </summary>
        /// <param name="zipFilePath">压缩文件路径</param>
        /// <param name="extractPath">解压路径</param>
        /// <param name="pwd">压缩密码</param>
        /// <param name="progressFun">进程</param>
        /// <param name="seconds">触发时间</param>
        public static void ExtractSpecifyZipFile(string zipFilePath, string extractPath, string pwd, List<string> files)
        {
            using (ZipInputStream s = new ZipInputStream(File.OpenRead(zipFilePath)))
            {
                ZipEntry theEntry;
                while ((theEntry = s.GetNextEntry()) != null)
                {
                    if (files.Contains(theEntry.Name))
                    {
                        Directory.CreateDirectory(extractPath);
                        using (FileStream streamWriter = File.Create(extractPath + "//" + theEntry.Name))
                        {
                            int size = 2048;
                            byte[] data = new byte[2048];
                            while (true)
                            {
                                size = s.Read(data, 0, data.Length);
                                if (size > 0)
                                {
                                    streamWriter.Write(data, 0, size);
                                }
                                else
                                {
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
        #endregion

        #region 递归删除目录
        /// <summary>
        /// 递归删除目录
        /// </summary>
        /// <param name="strPath"></param>
        /// <returns></returns>
        public static bool DeleteADirectory(string strPath)
        {
            string[] strTemp;
            try
            {
                //先删除该目录下的文件  
                strTemp = System.IO.Directory.GetFiles(strPath);
                foreach (string str in strTemp)
                {
                    System.IO.File.Delete(str);
                }
                //删除子目录，递归  
                strTemp = System.IO.Directory.GetDirectories(strPath);
                foreach (string dir in strTemp)
                {
                    if (Path.GetDirectoryName(dir + "\\").ToLower() == Path.GetDirectoryName(strPath + "/files/").ToLower() || Path.GetDirectoryName(dir + "\\").ToLower() == Path.GetDirectoryName(strPath + "/Logs/").ToLower())
                    {
                        continue;
                    }
                    if (Path.GetDirectoryName(dir + "\\").ToLower() == Path.GetDirectoryName($"{config.install_dir}/app/hfs/wwwroot/").ToLower())
                    {
                        continue;
                    }
                    DeleteADirectory(dir);
                }
                //删除该目录  
                System.IO.Directory.Delete(strPath);
                return true;
            }
            catch
            {
                return false;
            }
        }
        #endregion

        #region 检测端口占用
        public static bool PortInUse(int port)
        {
            bool inUse = false;
            IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
            IPEndPoint[] ipEndPoints = ipProperties.GetActiveTcpListeners();

            foreach (IPEndPoint endPoint in ipEndPoints)
            {
                if (endPoint.Port == port)
                {
                    inUse = true;
                    break;
                }
            }

            return inUse;
        }
        #endregion

        #region 复制目录
        public static void CopyDirectory(string sourceDirPath, string saveDirPath)
        {
            try
            {
                if (!Directory.Exists(sourceDirPath))
                {
                    Console.WriteLine("源目录不存在，请核对！");
                }

                if (!Directory.Exists(saveDirPath))
                {
                    Directory.CreateDirectory(saveDirPath);
                }
                string[] files = Directory.GetFiles(sourceDirPath);

                foreach (string file in files)
                {
                    string pFilePath = saveDirPath + @"\" + Path.GetFileName(file);

                    //if (File.Exists(pFilePath))
                    //    continue;
                    write_task_log($"正在复制文件:{Path.GetFileName(file)}");
                    File.Copy(file, pFilePath, true);
                }

                string[] dirs = Directory.GetDirectories(sourceDirPath);
                foreach (string dir in dirs)
                {
                    if (Path.GetDirectoryName(dir + "\\").ToLower() == Path.GetDirectoryName(sourceDirPath + "/files/").ToLower() || Path.GetDirectoryName(dir + "\\").ToLower() == Path.GetDirectoryName(sourceDirPath + "/Logs/").ToLower())
                    {
                        continue;
                    }
                    if (Path.GetDirectoryName(dir + "\\").ToLower() == Path.GetDirectoryName($"{config.install_dir}/app/hfs/wwwroot/").ToLower())
                    {
                        continue;
                    }
                    CopyDirectory(dir, saveDirPath + @"\" + Path.GetFileName(dir));
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        #endregion

        #region 关闭指定目录的程序
        /// <summary>
        /// 检测指定目录程序是否运行
        /// </summary>
        /// <param name="name"></param>
        /// <param name="path"></param>
        /// <returns></returns>
        public static void Kill_Exe(string name, string path = "")
        {
            Process[] ps = Process.GetProcesses();
            foreach (Process process in ps)
            {
                if (process.ProcessName.ToLower() == name.ToLower())
                {
                    try
                    {
                        if (path == "")
                        {
                            process.Kill();
                            process.WaitForExit();
                        }
                        else if (process.MainModule.FileName.ToLower().Contains(Path.GetDirectoryName(path).ToLower()))
                        {
                            process.Kill();
                            process.WaitForExit();
                        }
                    }
                    catch (System.ComponentModel.Win32Exception)
                    {
                        continue;
                    }
                    catch (InvalidOperationException)
                    {
                        continue;
                    }
                }
            }
        }
        #endregion

        #region 关闭指定目录的句柄
        /// <summary>
        /// 关闭指定目录的句柄
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static void Kill_Path(string path)
        {
            Process[] ps = Process.GetProcesses();
            try
            {
                foreach (Process process in ps)
                {
                    try
                    {
                        if (Path.GetDirectoryName(process.MainModule.FileName).ToLower().Contains(Path.GetDirectoryName(path).ToLower()))
                        {
                            process.Kill();
                            Thread.Sleep(500);
                        }
                    }
                    catch (System.ComponentModel.Win32Exception)
                    {
                        continue;
                    }
                    catch (InvalidOperationException)
                    {
                        continue;
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }

        }
        #endregion

        #region  重启应用程序
        /// <summary>
        /// 重启应用程序
        /// </summary>
        public static void ReStart()
        {
            Application.ExitThread();
            Application.Exit();
            Application.Restart();
            Process.GetCurrentProcess().Kill();
        }
        #endregion

        #region 多环境管理
        /// <summary>
        /// 保存多环境数据
        /// </summary>
        public static void SaveMultiEnv()
        {
            try
            {
                string fname = AppDomain.CurrentDomain.BaseDirectory + "\\Config\\MultiEnv.dat";
                if (File.Exists(fname))
                    File.Delete(fname);
                using (FileStream fs = new FileStream(fname, FileMode.Create))
                {
                    BinaryFormatter bf = new BinaryFormatter();
                    //将list序列化到文件中
                    bf.Serialize(fs, MultiEnvs);
                }
            }
            catch (Exception E)
            {

            }
        }

        /// <summary>
        /// 读取多环境数据
        /// </summary>
        public static void ReadMultiEnv()
        {
            try
            {
                string fname = AppDomain.CurrentDomain.BaseDirectory + "\\Config\\MultiEnv.dat";
                if (File.Exists(fname))
                {
                    using (FileStream fs = new FileStream(fname, FileMode.Open))
                    {
                        fs.Seek(0, SeekOrigin.Begin);
                        BinaryFormatter bf = new BinaryFormatter();
                        //将list序列化到文件中
                        MultiEnvs = bf.Deserialize(fs) as List<MultiEnvInfo>;
                    }
                }
            }
            catch (Exception E)
            {

            }

            if (MultiEnvs is null)
            {
                MultiEnvs = new List<MultiEnvInfo>
                {
                    new MultiEnvInfo{ Ip = config.ip, Name = "生产",FileName="produse" ,DefaultPort = "600", DefaultMask = "60" },
                    new MultiEnvInfo{ Ip = config.ip, Name = "测试1",FileName="test1" , DefaultPort = "601", DefaultMask = "61" },
                    new MultiEnvInfo{ Ip = config.ip, Name = "测试2", FileName="test2" ,DefaultPort = "602", DefaultMask = "62" },
                    new MultiEnvInfo{ Ip = config.ip, Name = "测试3", FileName="test3" ,DefaultPort = "603", DefaultMask = "63" },
                    new MultiEnvInfo{ Ip = config.ip, Name = "测试4",FileName="test4" , DefaultPort = "604", DefaultMask = "64" },
                };
            }
        }
        #endregion

        #region 判断匿名类属性是否存在

        public static bool DoesPropertyExist(dynamic settings, string name)
        {
            if (settings is ExpandoObject)
                return ((IDictionary<string, object>)settings).ContainsKey(name);

            return settings.GetType().GetProperty(name) != null;
        }

        #endregion

        #region 将指定文件夹下面的所有内容copy到目标文件夹下面 果目标文件夹为只读属性就会报错。
        /****************************************
         * 函数名称：CopyDir
         * 功能说明：将指定文件夹下面的所有内容copy到目标文件夹下面 果目标文件夹为只读属性就会报错。
         * 参    数：srcPath:原始路径,aimPath:目标文件夹
         * 调用示列：
         *           string srcPath = Server.MapPath("test/");  
         *           string aimPath = Server.MapPath("test1/");
         *           Utilities.FileOperate.CopyDir(srcPath,aimPath);   
        *****************************************/
        /// <summary>
        /// 指定文件夹下面的所有内容copy到目标文件夹下面
        /// </summary>
        /// <param name="srcPath">原始路径</param>
        /// <param name="aimPath">目标文件夹</param>
        public static void CopyDir(string srcPath, string aimPath)
        {
            try
            {
                // 检查目标目录是否以目录分割字符结束如果不是则添加之
                if (aimPath[aimPath.Length - 1] != Path.DirectorySeparatorChar)
                    aimPath += Path.DirectorySeparatorChar;
                // 判断目标目录是否存在如果不存在则新建之
                if (!Directory.Exists(aimPath))
                    Directory.CreateDirectory(aimPath);
                // 得到源目录的文件列表，该里面是包含文件以及目录路径的一个数组
                //如果你指向copy目标文件下面的文件而不包含目录请使用下面的方法
                string[] fileList = Directory.GetFileSystemEntries(srcPath);
                //遍历所有的文件和目录
                foreach (string file in fileList)
                {
                    //先当作目录处理如果存在这个目录就递归Copy该目录下面的文件

                    if (Directory.Exists(file))
                        CopyDir(file, aimPath + Path.GetFileName(file));
                    //否则直接Copy文件
                    else
                        File.Copy(file, aimPath + Path.GetFileName(file), true);
                }
            }
            catch (Exception ee)
            {
                throw new Exception(ee.ToString());
            }
        }
        #endregion

    }
}
