/******************************************************************************
 * SunnyUI 开源控件库、工具类库、扩展类库、多页面开发框架。
 * CopyRight (C) 2012-2024 ShenYongHua(沈永华).
 * QQ群：56829229 QQ：17612584 EMail：SunnyUI@QQ.Com
 *
 * Blog:   https://www.cnblogs.com/yhuse
 * Gitee:  https://gitee.com/yhuse/SunnyUI
 * GitHub: https://github.com/yhuse/SunnyUI
 *
 * SunnyUI.dll can be used for free under the GPL-3.0 license.
 * If you use this code, please keep this note.
 * 如果您使用此代码，请保留此说明。
 ******************************************************************************
 * 文件名称: UIniConfig.cs
 * 文件说明: INI 配置文件类
 * 当前版本: V3.1
 * 创建日期: 2020-01-01
 *
 * 2020-01-01: V2.2.0 增加文件说明
 * 2022-11-01: V3.2.6 增加文件编码，通过Load传入
 * 2024-02-27: V3.6.3 增加按属性名称进行读写
******************************************************************************/

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Reflection;
using System.Text;
using System.Windows.Forms;

namespace Sunny.UI
{
    /// <summary>
    /// INI 配置文件类
    /// </summary>
    /// <typeparam name="T">类型</typeparam>
    public class IniConfig<T> : BaseConfig<T> where T : IniConfig<T>, new()
    {
        /// <summary>
        /// Ini文件编码格式
        /// </summary>
        [ConfigIgnore]
        public Encoding IniEncoding { get; private set; } = Encoding.Default;

        [ConfigIgnore]
        public object this[string property]
        {
            get
            {
                PropertyInfo info = Current.GetType().GetProperty(property);
                if (info == null)
                {
                    throw new ArgumentNullException("属性名称不存在：" + property);
                }

                return info.GetValue(this, null);
            }
            set
            {
                PropertyInfo info = Current.GetType().GetProperty(property);
                if (info == null)
                {
                    throw new ArgumentNullException("属性名称不存在：" + property);
                }

                try
                {
                    Type propertyType = info.PropertyType;
                    info.SetValue(Current, Convert.ChangeType(value, propertyType), null);
                }
                catch (Exception)
                {
                    throw new ArgumentException("属性值转换失败：" + property + ", " + value);
                }
            }
        }

        public bool Load(string fileName, Encoding encoding)
        {
            IniEncoding = encoding;
            return Load(fileName);
        }

        /// <summary>加载指定配置文件</summary>
        /// <param name="filename">文件名</param>
        /// <returns>结果</returns>
        public override bool Load(string filename)
        {
            if (filename.IsNullOrWhiteSpace())
            {
                filename = Dir.CurrentDir() + ConfigFile;
            }

            if (filename.IsNullOrWhiteSpace())
            {
                throw new ApplicationException($"未指定{typeof(T).Name}的配置文件路径！");
            }

            if (!File.Exists(filename))
            {
                return false;
            }

            try
            {
                ConcurrentDictionary<string, Ident> idents = ConfigHelper.InitIdents(current);
                foreach (var ident in idents.Values)
                {
                    if (ident.Section.IsNullOrEmpty())
                    {
                        ident.Section = "Setup";
                    }
                }

                IniFile ini = new IniFile(filename, IniEncoding);
                foreach (var ident in idents.Values)
                {
                    if (ident.IsList)
                    {
                        ident.Values.Clear();
                        NameValueCollection list = ini.GetSectionValues(ident.Section + "-" + ident.Key);
                        foreach (var pair in list)
                        {
                            ident.Values.Add(ini.Read(ident.Section + "-" + ident.Key, pair.ToString(), ""));
                        }
                    }
                    else
                    {
                        ident.Value = ini.Read(ident.Section, ident.Key, "");
                    }
                }

                ConfigHelper.LoadConfigValue(current, idents);
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return false;
            }
        }

        /// <summary>保存到配置文件中去</summary>
        /// <param name="filename">文件名</param>
        public override void Save(string filename)
        {
            if (filename.IsNullOrWhiteSpace())
            {
                filename = Dir.CurrentDir() + ConfigFile;
            }

            if (filename.IsNullOrWhiteSpace())
            {
                throw new ApplicationException($"未指定{typeof(T).Name}的配置文件路径！");
            }

            ConcurrentDictionary<string, Ident> idents = ConfigHelper.InitIdents(current);
            foreach (var ident in idents.Values)
            {
                if (ident.Section.IsNullOrEmpty())
                {
                    ident.Section = "Setup";
                }
            }

            ConfigHelper.SaveConfigValue(Current, idents);
            StringBuilder strs = new StringBuilder();
            strs.AppendLine(";<?Ini Version=\"" + UIGlobal.Version + "\" Encoding=\"" + IniEncoding.BodyName + "\"?>");
            strs.AppendLine(";<?Update Time=\"" + DateTime.Now.DateTimeString() + "\"?>");
            strs.AppendLine("");
            Dictionary<string, List<Ident>> listidents = new Dictionary<string, List<Ident>>();
            foreach (var ident in idents.Values)
            {
                string section = ident.IsList ? ident.Section + "-" + ident.Key : ident.Section;

                if (!listidents.ContainsKey(section))
                {
                    listidents.Add(section, new List<Ident>());
                }

                listidents[section].Add(ident);
            }

            foreach (var values in listidents)
            {
                strs.AppendLine("[" + values.Key + "]");

                SortedList<int, Ident> slist = new SortedList<int, Ident>();
                foreach (var ident in values.Value)
                {
                    slist.Add(ident.Index, ident);
                }

                foreach (var ident in slist.Values)
                {
                    if (!ident.Description.IsNullOrEmpty())
                    {
                        strs.AppendLine(";<!--" + ident.Description + "-->");
                    }

                    if (ident.IsList)
                    {
                        for (int i = 0; i < ident.Values.Count; i++)
                        {
                            strs.AppendLine("Value" + i + "=" + ident.Values[i]);
                        }
                    }
                    else
                    {
                        strs.AppendLine(ident.Key + "=" + ident.Value);
                    }
                }

                strs.AppendLine("");
            }

            listidents.Clear();
            Dir.CreateDir(Path.GetDirectoryName(filename));
            string filetmp = filename + "." + RandomEx.RandomPureChar(3);
            File.Delete(filetmp);
            StreamWriter sw = new StreamWriter(filetmp, false, IniEncoding);
            sw.WriteLine(strs.ToString());
            sw.Flush();
            sw.Dispose();

            try
            {
                File.Delete(filename);
                File.Move(filetmp, filename);
            }
            catch (Exception ex)
            {
                MessageBox.Show("配置文件存储失败: " + filename + " ," + ex.Message);
            }
        }
    }

    /// <summary>
    /// INI 配置文件类
    /// </summary>
    /// <typeparam name="T">类型</typeparam>
    public class IniUTF8Config<T> : BaseConfig<T> where T : IniUTF8Config<T>, new()
    {
        [ConfigIgnore]
        public object this[string property]
        {
            get
            {
                PropertyInfo info = Current.GetType().GetProperty(property);
                if (info == null)
                {
                    throw new ArgumentNullException("属性名称不存在：" + property);
                }

                return info.GetValue(this, null);
            }
            set
            {
                PropertyInfo info = Current.GetType().GetProperty(property);
                if (info == null)
                {
                    throw new ArgumentNullException("属性名称不存在：" + property);
                }

                try
                {
                    Type propertyType = info.PropertyType;
                    info.SetValue(Current, Convert.ChangeType(value, propertyType), null);
                }
                catch (Exception)
                {
                    throw new ArgumentException("属性值转换失败：" + property + ", " + value);
                }
            }
        }

        /// <summary>加载指定配置文件</summary>
        /// <param name="filename">文件名</param>
        /// <returns>结果</returns>
        public override bool Load(string filename)
        {
            if (filename.IsNullOrWhiteSpace())
            {
                filename = Dir.CurrentDir() + ConfigFile;
            }

            if (filename.IsNullOrWhiteSpace())
            {
                throw new ApplicationException($"未指定{typeof(T).Name}的配置文件路径！");
            }

            if (!File.Exists(filename))
            {
                return false;
            }

            try
            {
                ConcurrentDictionary<string, Ident> idents = ConfigHelper.InitIdents(current);
                foreach (var ident in idents.Values)
                {
                    if (ident.Section.IsNullOrEmpty())
                    {
                        ident.Section = "Setup";
                    }
                }

                IniFile ini = new IniFile(filename, Encoding.UTF8);
                foreach (var ident in idents.Values)
                {
                    if (ident.IsList)
                    {
                        ident.Values.Clear();
                        NameValueCollection list = ini.GetSectionValues(ident.Section + "-" + ident.Key);
                        foreach (var pair in list)
                        {
                            ident.Values.Add(ini.Read(ident.Section + "-" + ident.Key, pair.ToString(), ""));
                        }
                    }
                    else
                    {
                        ident.Value = ini.Read(ident.Section, ident.Key, "");
                    }
                }

                ConfigHelper.LoadConfigValue(current, idents);
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return false;
            }
        }

        /// <summary>保存到配置文件中去</summary>
        /// <param name="filename">文件名</param>
        public override void Save(string filename)
        {
            if (filename.IsNullOrWhiteSpace())
            {
                filename = Dir.CurrentDir() + ConfigFile;
            }

            if (filename.IsNullOrWhiteSpace())
            {
                throw new ApplicationException($"未指定{typeof(T).Name}的配置文件路径！");
            }

            ConcurrentDictionary<string, Ident> idents = ConfigHelper.InitIdents(current);
            foreach (var ident in idents.Values)
            {
                if (ident.Section.IsNullOrEmpty())
                {
                    ident.Section = "Setup";
                }
            }

            ConfigHelper.SaveConfigValue(Current, idents);
            StringBuilder strs = new StringBuilder();
            strs.AppendLine(";<?Ini Version=\"" + UIGlobal.Version + "\" Encoding=\"" + Encoding.UTF8.BodyName + "\"?>");
            strs.AppendLine(";<?Update Time=\"" + DateTime.Now.DateTimeString() + "\"?>");
            strs.AppendLine("");
            Dictionary<string, List<Ident>> listidents = new Dictionary<string, List<Ident>>();
            foreach (var ident in idents.Values)
            {
                string section = ident.IsList ? ident.Section + "-" + ident.Key : ident.Section;

                if (!listidents.ContainsKey(section))
                {
                    listidents.Add(section, new List<Ident>());
                }

                listidents[section].Add(ident);
            }

            foreach (var values in listidents)
            {
                strs.AppendLine("[" + values.Key + "]");

                SortedList<int, Ident> slist = new SortedList<int, Ident>();
                foreach (var ident in values.Value)
                {
                    slist.Add(ident.Index, ident);
                }

                foreach (var ident in slist.Values)
                {
                    if (!ident.Description.IsNullOrEmpty())
                    {
                        strs.AppendLine(";<!--" + ident.Description + "-->");
                    }

                    if (ident.IsList)
                    {
                        for (int i = 0; i < ident.Values.Count; i++)
                        {
                            strs.AppendLine("Value" + i + "=" + ident.Values[i]);
                        }
                    }
                    else
                    {
                        strs.AppendLine(ident.Key + "=" + ident.Value);
                    }
                }

                strs.AppendLine("");
            }

            listidents.Clear();
            Dir.CreateDir(Path.GetDirectoryName(filename));
            string filetmp = filename + "." + RandomEx.RandomPureChar(3);
            File.Delete(filetmp);
            StreamWriter sw = new StreamWriter(filetmp, false, Encoding.UTF8);
            sw.WriteLine(strs.ToString());
            sw.Flush();
            sw.Dispose();

            try
            {
                File.Delete(filename);
                File.Move(filetmp, filename);
            }
            catch (Exception ex)
            {
                MessageBox.Show("配置文件存储失败: " + filename + " ," + ex.Message);
            }
        }
    }
}