using ryCommon;
using ryCommonDb;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;

namespace 开发辅助工具.Manager
{
    class RyProject
    {
        /// <summary>
        /// C#基准项目路径
        /// </summary>
        public string CshapeBasePath { get; private set; } = "";

        /// <summary>
        /// 引用dll文件夹列表
        /// </summary>
        public string ReferenceDllPath { get; private set; } = "";
        /// <summary>
        /// 是否将dll复制到Bin目录，并修改引用
        /// </summary>
        public bool CopyDllToBin { get; set; } = false;
        /// <summary>
        /// Bin目录相对于项目文件所在的位置,可使用相对路径或绝对路径
        /// </summary>
        public string BinFolder { get; set; } = "..\\..\\Bin";
        /// <summary>
        /// 是否修改输出路径
        /// </summary>
        public bool ChangedOutputPath { get; set; } =true;
        public delegate void StringEventHandler(object sender, string e);
        /// <summary>
        /// 状态变化时激发
        /// </summary>
        [Description("状态变化时激发")]
        public event StringEventHandler OnStateChanged;
        public RyProject()
        {
            UpdateSetting();
        }
        /// <summary>
        /// 更新设置
        /// </summary>
        public void UpdateSetting()
        {
            DataProvider mydb = new DataProvider();
            IDbInterface db = Itrycn_Db.CreateDataProvider(Itrycn_Db.dataType);
            if (db.ConnDb(Itrycn_Db.User_SQLConn) == 1)
            {
                var ds = db.ReadData("select * from Settings where name='Setting'");
                if (mydb.HaveData(ds))
                {
                    var row = mydb.GetData(ds);
                    ryCommon.Storage mStor = new ryCommon.Storage(row["value"].ToString());
                    mStor.SelectNodeBySet();
                    CshapeBasePath = mStor.GetAttrValue("CshapeBasePath");
                    ReferenceDllPath = mStor.GetAttrValue("ReferenceDll");
                }
            }
            db.Free();
        }
        /// <summary>
        /// 通过dll名称来寻找dll路径
        /// </summary>
        /// <param name="_ReferenceDllPath"></param>
        /// <param name="dll_name"></param>
        /// <returns></returns>
        public string GetDllPath(string dll_name)
        {
            var path_list = ReferenceDllPath.Replace("\r", "").Split('\n');
            var find = false;
            var result = "";
            #region 在引用文件夹查找是否有该dll,有则使用引用文件夹里的dll
            for (int m = 0; m < path_list.Length; m++)
            {
                if (path_list[m].Trim() == "") { continue; }
                if (!System.IO.Directory.Exists(path_list[m])) { continue; }
                var files = System.IO.Directory.GetFiles(path_list[m]);
                for (int z = 0; z < files.Length; z++)
                {
                    if (System.IO.Path.GetFileName(files[z]).ToLower() == dll_name.ToLower())
                    {
                        result = files[z];
                        find = true;
                        break;
                    }
                }
                if (find) { break; }
            }
            #endregion
            return result;
        }
        /// <summary>
        /// 相对路径转绝对路径,相对项目文件的路径
        /// </summary>
        /// <returns></returns>
        public string RelToAbsPath(string project_path,string rel_path)
        {
            string folder = System.IO.Path.GetDirectoryName(project_path);
            var _rel_path = rel_path;
            while (true)
            {
                if (_rel_path.IndexOf("..\\") == 0)
                {
                    folder = System.IO.Path.GetDirectoryName(folder.TrimEnd('\\'));
                    _rel_path = _rel_path.Substring(3);
                }
                else { break; }
                if (folder == "") { break; }
            }
            return folder+"\\"+ _rel_path;
        }
        /// <summary>
        /// 绝对路径转相对路径,相对项目文件的路径
        /// </summary>
        /// <returns></returns>
        public string AbsToRelPath(string project_path, string abs_path)
        {
            string folder = System.IO.Path.GetDirectoryName(project_path);
            var _rel_path = "";
            var _rel_path2 = "";
            while (true)
            {
                if (abs_path.IndexOfEx(folder) == 0)
                {
                    if (_rel_path2 == "")
                    { _rel_path = abs_path.Substring(folder.Length); }
                    else
                    {
                        _rel_path = _rel_path2.TrimEnd('\\') + abs_path.Substring(folder.Length);
                    }
                    break;
                }
                else
                {
                    folder = System.IO.Path.GetDirectoryName(folder.TrimEnd('\\'));
                    _rel_path2 += "..\\";
                }
                if (folder == "") { break; }
            }
            return _rel_path;
        }
        /// <summary>
        /// 更新dll版本,如果全部复制成功，则返回0,否则返回错误个数
        /// </summary>
        public int UpdateDlls(string folder,out string error_str)
        {
            error_str = "";
            var _error_str = "";
            int error = 0;
            Updates(folder);
            void Updates(string _path)
            {
                var files = System.IO.Directory.GetFiles(_path, "*.dll");
                for (int i = 0; i < files.Length; i++)
                {
                    string filename = System.IO.Path.GetFileName(files[i]);
                    var dllpath = GetDllPath(filename);
                    if (dllpath != "")
                    {
                        if (RyFiles.CopyFile(dllpath, files[i]) != 0)
                        { _error_str += files[i]+ "\r\n"; error++; }
                        var dll_xml_path = System.IO.Path.GetDirectoryName(dllpath) +"\\"+ System.IO.Path.GetFileNameWithoutExtension(dllpath) + ".xml";
                        if (System.IO.File.Exists(dll_xml_path))
                        {
                            if (RyFiles.CopyFile(dll_xml_path, System.IO.Path.GetDirectoryName(files[i]) + "\\" + System.IO.Path.GetFileNameWithoutExtension(files[i]) + ".xml") != 0)
                            { _error_str += files[i] + "\r\n"; error++; }
                        }
                    }
                }
                var dirs = System.IO.Directory.GetDirectories(_path);
                for (int i = 0; i < dirs.Length; i++)
                {
                    Updates(dirs[i]);
                }
            }
            error_str = _error_str;
            return error;
        }
        /// <summary>
        /// 更新项目引用,定向为本地dll,如果全部复制成功，则返回0,否则返回错误个数
        /// </summary>
        public int UpdateCSproj(string folder)
        {
            int error = 0;
            Updates(folder);
            void Updates(string _path)
            {
                var files = System.IO.Directory.GetFiles(_path, "*.csproj");
                for (int i = 0; i < files.Length; i++)
                {
                    SetCSproj(files[i], "");
                }
                var dirs = System.IO.Directory.GetDirectories(_path);
                for (int i = 0; i < dirs.Length; i++)
                {
                    Updates(dirs[i]);
                }
            }
            return error;
        }
        /// <summary>
        /// 自动设置csproj文件,将dll引用修改为指定区域的dll、修改命名空间
        /// </summary>
        /// <param name="path">项目文件(*.csproj)</param>
        /// <param name="_project_Eng_name">项目英文名</param>
        public void SetCSproj(string path, string _project_Eng_name)
        {
            System.Xml.XmlDocument xml = new System.Xml.XmlDocument();
            xml.Load(path);
            var xmlnsm = new XmlNamespaceManager(xml.NameTable);
            xmlnsm.AddNamespace("d", xml.DocumentElement.NamespaceURI);
            //var root = @"d:Project//d:ItemGroup//d:Reference";
            if (_project_Eng_name != "")
            {
                SetValue(@"d:Project//d:PropertyGroup//d:RootNamespace", _project_Eng_name.Replace(" ", ""));//命名空间名
                SetValue(@"d:Project//d:PropertyGroup//d:AssemblyName", _project_Eng_name.Replace(" ", ""));//程序集名称
            }
            var OutputPath = GetValue(@"d:Project//d:PropertyGroup[2]//d:OutputPath").TrimEnd('\\')+"\\";
            if (ChangedOutputPath)
            {
                SetValue(@"d:Project//d:PropertyGroup[2]//d:OutputPath", BinFolder.TrimEnd('\\') + "\\Debug\\"+ (_project_Eng_name==""?"": _project_Eng_name +"\\"));//Debug输出路径
                SetValue(@"d:Project//d:PropertyGroup[3]//d:OutputPath", BinFolder.TrimEnd('\\') + "\\Release\\" + (_project_Eng_name == "" ? "" : _project_Eng_name + "\\"));//Release输出路径
            }
            if (OutputPath == "") { OutputPath = BinFolder.TrimEnd('\\') + "\\Debug\\" + (_project_Eng_name == "" ? "" : _project_Eng_name + "\\"); }
            var list = xml.SelectNodes(@"d:Project//d:ItemGroup//d:Reference//d:HintPath", xmlnsm);
            for (int i = 0; i < list.Count; i++)
            {
                var HintPath = list[i].InnerText;
                var iPos = HintPath.LastIndexOf("\\");
                if (iPos > 0)
                {
                    var Reference_Name = HintPath.Substring(iPos + 1);//引用的dll名称 
                    var dll_path = GetDllPath(Reference_Name);
                    if (dll_path != "")
                    {
                        if (CopyDllToBin)
                        {
                            list[i].InnerText = OutputPath + Reference_Name;
                            RyFiles.CopyFile(dll_path,RelToAbsPath(path, OutputPath + Reference_Name));
                        }
                        else
                        {
                            list[i].InnerText = dll_path;
                        }
                    }
                }
            }
            var ProjectReference_list = xml.SelectNodes(@"d:Project//d:ItemGroup//d:ProjectReference", xmlnsm);//项目引用
            for (int i = 0; i < ProjectReference_list.Count; i++)
            {
                var element = (XmlElement)ProjectReference_list[i];
                var IncludePath = element.GetAttribute("Include");
                var iPos = IncludePath.LastIndexOf("\\");
                if (iPos > 0)
                {
                    var Reference_FileName = IncludePath.Substring(iPos + 1).ToLower();//引用的项目文件名称 
                    string dll_name = "";
                    if (Reference_FileName == "MyDbV4.csproj".ToLower())
                    { dll_name = "MyDb.dll"; }
                    else if (Reference_FileName == "MyDb_SQLiteV4.csproj".ToLower())
                    { dll_name = "MyDb_SQLite.dll"; }
                    else if (Reference_FileName == "ryControlsV4.csproj".ToLower())
                    { dll_name = "ryControls.dll"; }
                    else if (Reference_FileName == "RyPrint.csproj".ToLower())
                    { dll_name = "RyPrint.dll"; }
                    else if (Reference_FileName == "ryUpdateV4.csproj".ToLower())
                    { dll_name = "ryUpdate.dll"; }
                    if (dll_name != "")
                    {
                        var dll_path = GetDllPath(dll_name);
                        if (dll_path != "")
                        {
                            if (CopyDllToBin)
                            {
                                MoveReference(System.IO.Path.GetFileNameWithoutExtension(dll_name), OutputPath + dll_name);
                                RyFiles.CopyFile(dll_path, RelToAbsPath(path, OutputPath + dll_name));
                            }
                            else
                            {
                                MoveReference(System.IO.Path.GetFileNameWithoutExtension(dll_name), dll_path);
                            }
                        }
                    }
                    //将项目引用转换为dll引用
                    void MoveReference(string reference_name, string dll_path)
                    {
                        ProjectReference_list[i].ParentNode.RemoveChild(ProjectReference_list[i]);
                        var node = xml.SelectSingleNode(@"d:Project//d:ItemGroup", xmlnsm);
                        XmlNode childXmlNode = xml.CreateElement("Reference");
                        XmlNode childXmlNode2 = xml.CreateElement("HintPath");
                        childXmlNode2.InnerText = dll_path;
                        childXmlNode.AppendChild(childXmlNode2);
                        node.AppendChild(childXmlNode);
                        XmlElement element2 = (XmlElement)childXmlNode;
                        element2.SetAttribute("Include", reference_name);
                    }
                }
            }
            xml.InnerXml = xml.InnerXml.Replace(" xmlns=\"\"", "");
            xml.Save(path);
            string GetValue(string xpath)
            {
                var node = xml.SelectSingleNode(xpath, xmlnsm);
                if (node != null)
                {
                    return node.InnerText;
                }
                return "";
            }
            bool SetValue(string xpath, string value)
            {
                var node = xml.SelectSingleNode(xpath, xmlnsm);
                if (node != null)
                {
                    node.InnerText = value; return true;
                }
                return false;
            }
        }
        /// <summary>
        /// 获取版本号
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public string GetAssemblyVersion(string path)
        {
            var AssemblyInfo_Path = System.IO.Path.GetDirectoryName(path) + "\\Properties\\AssemblyInfo.cs";
            if (System.IO.File.Exists(AssemblyInfo_Path))
            {
                var AssemblyInfo = ryCommon.RyFiles.ReadAllLines(AssemblyInfo_Path);
                for (int i = 0; i < AssemblyInfo.Length; i++)
                {
                    if (AssemblyInfo[i].StartsWith("//")) { continue; }
                    if (AssemblyInfo[i].StartsWith("[assembly: AssemblyVersion"))
                    {
                        return AssemblyInfo[i].GetStr("AssemblyVersion(\"", "\")");
                    }
                }
                return "";
            }
            else
            {
                return "";
            }           
        }
        /// <summary>
        /// 更新版本号
        /// </summary>
        /// <param name="AssemblyInfo_Path"></param>
        public static void UpdateVer(string AssemblyInfo_Path)
        {
            string AssemblyInfo_path = AssemblyInfo_Path;
            if (System.IO.File.Exists(AssemblyInfo_path))
            {
                string[] AssemblyInfo_list = ryCommon.RyFiles.ReadAllLines(AssemblyInfo_path);
                string text = "";
                string Revision_Ver = DateTime.Now.ToString("yyMM");
                string Build_Ver = DateTime.Now.ToString("dd00");
                for (int i = 0; i < AssemblyInfo_list.Length; i++)
                {
                    string item = AssemblyInfo_list[i];
                    if (item.IndexOf("[assembly: AssemblyVersion(\"") == 0)
                    {

                        ChangeVer("[assembly: AssemblyVersion(\"");
                    }
                    else if (item.IndexOf("[assembly: AssemblyFileVersion(\"") == 0)
                    {
                        ChangeVer("[assembly: AssemblyFileVersion(\"");
                    }
                    if (text != "") { text += "\r\n"; }
                    text += item;
                    void ChangeVer(string id)
                    {
                        string ver = item.GetStr(id, "\")]", 0, out int pos, "");
                        if (ver != "")
                        {
                            string[] ver_list = ver.Split('.');
                            if (ver_list.Length == 4)
                            {
                                if (ver_list[2] != Revision_Ver)
                                {
                                    ver = ver_list[0] + "." + ver_list[1] + "." + Revision_Ver + "." + (Build_Ver.ToInt() + 1).ToString("0000");
                                }
                                else
                                {
                                    if (ver_list[3].IndexOf(DateTime.Now.ToString("dd")) == 0)
                                    {
                                        ver = ver_list[0] + "." + ver_list[1] + "." + Revision_Ver + "." + (ver_list[3].ToInt() + 1).ToString("0000");
                                    }
                                    else
                                    {
                                        ver = ver_list[0] + "." + ver_list[1] + "." + Revision_Ver + "." + (Build_Ver.ToInt() + 1).ToString("0000");
                                    }
                                }
                                item = id + ver + "\")]";
                            }
                        }
                    }
                }
                ryCommon.RyFiles.WriteAllText(AssemblyInfo_path, text, Encoding.UTF8);
            }
        }
        /// <summary>
        /// 等待进程执行完毕
        /// </summary>
        /// <param name="cmd_text"></param>
        /// <returns></returns>
        public string Read_Prog(string exe, string cmd_text)
        {
            String cmd = exe;
            Process p = new Process
            {
                StartInfo = new System.Diagnostics.ProcessStartInfo
                {
                    FileName = cmd,//设定程序名
                    Arguments = cmd_text,
                    UseShellExecute = false, //关闭shell的使用
                    RedirectStandardInput = true, //重定向标准输入
                    RedirectStandardOutput = true, //重定向标准输出
                    RedirectStandardError = false, //重定向错误输出
                    CreateNoWindow = true//设置不显示窗口
                }
            };
            p.Start();
            string result = p.StandardOutput.ReadToEnd();
            p.WaitForExit(20000);
            p.Close();
            return result;
        }
        /// <summary>
        /// 进行打包
        /// </summary>
        /// <param name="project_folder">项目根目录</param>
        public void Pack(string project_folder)
        {
            var com_mode = "Debug";
            DataProvider mydb = new DataProvider();
            IDbInterface db = Itrycn_Db.CreateDataProvider(Itrycn_Db.dataType);
            if (db.ConnDb(Itrycn_Db.User_SQLConn) == 1)
            {
                var ds = db.ReadData("select * from Settings where name='Setting'");
                if (mydb.HaveData(ds))
                {
                    var row = mydb.GetData(ds);
                    ryCommon.Storage mStor = new ryCommon.Storage(row["value"].ToString());
                    mStor.SelectNodeBySet();
                    var ReactorPath = mStor.GetAttrValue("ReactorPath");
                    var WinRARPath = mStor.GetAttrValue("WinRARPath");
                    if (WinRARPath == "")
                    {
                        if (System.IO.File.Exists(@"C:\Program Files\WinRAR\WinRAR.exe"))
                        {
                            WinRARPath = @"C:\Program Files\WinRAR\WinRAR.exe";
                        }
                    }
                    var bf_folder = project_folder;
                    if (bf_folder != "")
                    {
                        ryCommon.Ini ini = new ryCommon.Ini(bf_folder + "\\查看项目.ryp");
                        var eng_name = ini.ReadIni("project", "engname");
                        var proglang = ini.ReadIni("project", "proglang");
                        var ouput_folder = bf_folder + "\\Bin\\" + com_mode + "\\" + eng_name;
                        if(!System.IO.Directory.Exists(ouput_folder))
                        {
                            ouput_folder = bf_folder + "\\Bin\\" + com_mode;
                        }
                        var file_ver = "";
                        if (System.IO.File.Exists(ouput_folder + "\\" + eng_name + ".exe"))
                        {
                            FileVersionInfo fileVerInfo = System.Diagnostics.FileVersionInfo.GetVersionInfo(ouput_folder + "\\" + eng_name + ".exe");
                            file_ver = fileVerInfo.ProductVersion;
                        }
                        if (proglang == "c#")
                        {
                            ShowState("正在进行混淆...");
                            if (System.IO.File.Exists(bf_folder + "\\Bin\\混淆_" + com_mode + ".nrproj"))
                            {
                                var cmd = Read_Prog(ReactorPath, "-project \"" + bf_folder + "\\Bin\\混淆_" + com_mode + ".nrproj\"");
                                MessageBox.Show(cmd, "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                            }
                        }
                        ShowState("正在清理不重要的缓存...");
                        ryCommon.RyFiles.DeleteFile(ouput_folder + "\\Secure\\*.pdb");
                        ShowState("复制混淆文件到底包目录...");
                        ryCommon.RyFiles.CopyFile(ouput_folder + "\\Secure\\*", bf_folder + "\\Publish\\OriginalFiles\\");
                        #region 复制自定义规则文件到底包目录
                        ShowState("复制自定义规则文件到底包目录...");
                        var Publish = ryCommon.RyFiles.ReadAllLines(bf_folder + "\\Publish\\Publish.set");
                        for (int m = 0; m < Publish.Length; m++)
                        {
                            var line = Publish[m].Trim();
                            if (line == "" || line.IndexOf("#") == 0) { continue; }
                            if (line.IndexOfEx("del:") == 0)
                            {
                                ryCommon.RyFiles.DeleteFile(bf_folder + "\\Publish\\OriginalFiles\\" + line.Substring(4));
                            }
                            else if (line.IndexOfEx("copy:") == 0)
                            {
                                var item = line.Substring(5);
                                if(item.Contains("<") && item.Contains(">"))
                                {
                                    DataSet ds_var = db.ReadData("select * from VarInfo");
                                    if (mydb.HaveData(ds_var))
                                    {
                                        for (int n = 0; n < ds_var.Tables[0].Rows.Count; n++)
                                        {
                                            DataRow row_var = ds_var.Tables[0].Rows[n];
                                            item = item.Replace("<" + row_var["VarName"].ToString() + ">", row_var["VarValue"].ToString());
                                            if (!item.Contains("<") || !item.Contains(">"))
                                            {
                                                break;
                                            }
                                        }
                                    }
                                }
                                var from_to = item.Replace("->", "|").Split('|');
                                if (from_to.Length == 2)
                                {
                                    var from_path = from_to[0];
                                    var to_path = from_to[1];
                                    ryCommon.RyFiles.CopyFile(ouput_folder + "\\" + from_path, bf_folder + "\\Publish\\OriginalFiles\\" + to_path);
                                }
                            }
                        }
                        #endregion
                        ShowState("正在打包...");
                        var cmd2 = Read_Prog(WinRARPath, "-r -ep1 a \"" + bf_folder + "\\Publish\\Green\\" + eng_name + ".zip\" \"" + bf_folder + "\\Publish\\OriginalFiles\\\"");
                        RyFiles.CopyFile(bf_folder + "\\Publish\\Green\\" + eng_name + ".zip", bf_folder + "\\Publish\\Green\\HistoryVer\\" + eng_name + "_" + file_ver + ".zip");
                        ShowState("打包完成...");
                    }
                }
            }
            db.Free();
            void ShowState(string text)
            {
                OnStateChanged?.Invoke(this,text);
            }
        }
    }
}
