Config.cs - escaco95/Charcoal GitHub Wiki

using System.Collections.Generic;
using System.IO;

namespace DiagramEditor.V4
{
    /// <summary>
    /// ์„ค์ • ๊ฐ„ <see cref="Config.Merge(Config)"/> ์—ฐ์‚ฐ์ด ๋ฐœ์ƒํ•  ๋•Œ, ๊ฐ ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ๋ณ‘ํ•ฉ ํ–‰์œ„๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
    /// </summary>
    public enum ConfigMergeOption
    {
        /// <summary>
        /// ์ด์ „ ๋ฐ์ดํ„ฐ๋ฅผ ๋ชจ๋‘ ์ง€์šฐ๊ณ , ์ƒˆ ๋ฐ์ดํ„ฐ๋กœ <see cref="ConfigMergeOption.Replace"/>ํ•ฉ๋‹ˆ๋‹ค.
        /// </summary>
        Clear,
        /// <summary>
        /// ์ด์ „ ๋ฐ์ดํ„ฐ๋ฅผ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ์ค‘๋ณต๋˜๋Š” ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•ด, ์ƒˆ ๋ฐ์ดํ„ฐ๋ฅผ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.
        /// </summary>
        Replace,
        /// <summary>
        /// ์ด์ „ ๋ฐ์ดํ„ฐ๋ฅผ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. ์ค‘๋ณต๋˜๋Š” ๋ฐ์ดํ„ฐ๋Š” ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
        /// </summary>
        Append,
    }
    /// <summary>
    /// ๋ชจ๋“  ๋ฒ„์ „์˜ ์„ค์ • ํŒŒ์ผ์— ๋Œ€์‘ํ•  ์ˆ˜ ์žˆ๋Š” ํŒŒ์ผ โ†” ๋ฉ”๋ชจ๋ฆฌ ์ž๋ฃŒ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.
    /// </summary>
    public class Config
    {
        public Config() { }
        public Config(string filePath) { Read(filePath); }
        public Config(Config source) { Merge(source); }
        /// <summary>
        /// ๊ธฐ๋ณธ ์นดํ…Œ๊ณ ๋ฆฌ๋กœ ์ œ๊ณต๋˜๋Š” ๋ฌธ์ž์—ด ์ƒ์ˆ˜๊ฐ’์ž…๋‹ˆ๋‹ค. ๋ฐ˜๋“œ์‹œ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋”๋ผ๋„ ์ƒ๊ด€์—†์Šต๋‹ˆ๋‹ค.
        /// </summary>
        public static string DefaultCategory = "Default";
        protected Dictionary<ConfigOption, bool> Linear = new Dictionary<ConfigOption, bool>();
        protected Dictionary<string, Dictionary<string, ConfigOption>> Hierarchy = new Dictionary<string, Dictionary<string, ConfigOption>>();
        /// <summary>
        /// ํ•ด๋‹น ์„ค์ • ๊ฐœ์ฒด์— ํฌํ•จ๋œ ๋ชจ๋“  ์˜ต์…˜์˜ IEnumerable์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
        /// </summary>
        public IEnumerable<ConfigOption> Options { get { return Linear.Keys; } }
        /// <summary>
        /// ํ•ด๋‹น ์„ค์ • ๊ฐœ์ฒด์— ํฌํ•จ๋œ ๋ชจ๋“  ์นดํ…Œ๊ณ ๋ฆฌ์˜ IEnumerable์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
        /// </summary>
        public IEnumerable<string> Categories { get { return Hierarchy.Keys; } }
        /// <summary>
        /// ๋‹ค๋ฅธ ์„ค์ • ๊ฐœ์ฒด์˜ ์˜ต์…˜์„ ๋ณ‘ํ•ฉํ•ฉ๋‹ˆ๋‹ค.
        /// </summary>
        public void Merge(Config source, ConfigMergeOption mergeOption = ConfigMergeOption.Replace)
        {
            if (mergeOption == ConfigMergeOption.Clear)
                Clear();
            switch (mergeOption)
            {
                case ConfigMergeOption.Clear:
                case ConfigMergeOption.Replace:
                    foreach (var tuple in source.Linear)
                        Set(tuple.Key.Category, tuple.Key.Name, tuple.Key.Value);
                    break;
                case ConfigMergeOption.Append:
                    foreach (var tuple in source.Linear)
                        if (!ContainsOption(tuple.Key.Category, tuple.Key.Name))
                            Set(tuple.Key.Category, tuple.Key.Name, tuple.Key.Value);
                    break;
            }
        }
        /// <summary>
        /// ํ•ด๋‹น ์„ค์ • ๊ฐœ์ฒด์˜ ๋‚ด์šฉ์„ ๋ณต์‚ฌํ•˜์—ฌ, ์ƒˆ๋กœ์šด ์„ค์ • ๊ฐœ์ฒด๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. (Deep-Copy)
        /// </summary>
        public Config Clone()
        {
            Config temp = new Config();
            temp.Merge(this, ConfigMergeOption.Replace);
            return temp;
        }
        /// <summary>
        /// ํ•ด๋‹น ์„ค์ • ๊ฐœ์ฒด์— ํฌํ•จ๋œ ๋ชจ๋“  ํ•˜์œ„ ์˜ต์…˜ ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
        /// </summary>
        public int Count()
        {
            return Linear.Count;
        }
        /// <summary>
        /// ์นดํ…Œ๊ณ ๋ฆฌ์— ์ €์žฅ๋œ ์˜ต์…˜์ด ๋ช‡ ๊ฐœ์ธ์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
        /// </summary>
        public int Count(string category)
        {
            // ์šฐ์„ , ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€๋ถ€ํ„ฐ ํ™•์ธํ•˜๊ณ .
            // ์กด์žฌ ์—ฌ๋ถ€์— ๋”ฐ๋ผ 0์„ ๋ฐ˜ํ™˜ํ•  ๊ฒƒ์ธ์ง€, ๋‚ด์šฉ์„ ๋ฐ˜ํ™˜ํ•  ๊ฒƒ์ธ์ง€ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค.
            return (Hierarchy.ContainsKey(category)) ? Hierarchy[category].Count : 0;
        }
        /// <summary>
        /// ์˜ต์…˜ ํŒŒ์ผ์˜ ๋‚ด์šฉ์„ ์™„์ „ํžˆ ๋น„์›๋‹ˆ๋‹ค.
        /// </summary>
        public void Clear()
        {
            Linear.Clear();
            Hierarchy.Clear();
        }
        /// <summary>
        /// ํŠน์ • ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์™„์ „ํžˆ ๋น„์›๋‹ˆ๋‹ค.
        /// </summary>
        public void Clear(string category)
        {
            foreach (var tuple in Hierarchy[category])
                Linear.Remove(tuple.Value);
            Hierarchy.Remove(category);
        }
        /// <summary>
        /// ์ง€์ •ํ•œ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ๋Š”์ง€์˜ ์—ฌ๋ถ€๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
        /// </summary>
        public bool ContainsCategory(string category) { return Hierarchy.ContainsKey(category); }
        /// <summary>
        /// ์ง€์ •ํ•œ ์˜ต์…˜์„ ํฌํ•จํ•˜๊ณ  ์žˆ๋Š”์ง€์˜ ์—ฌ๋ถ€๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
        /// </summary>
        public bool ContainsOption(string category, string optionName)
        {
            return (!Hierarchy.ContainsKey(category)) ? false : Hierarchy[category].ContainsKey(optionName);
        }
        /// <summary>
        /// ์„ค์ •์œผ๋กœ๋ถ€ํ„ฐ ํŠน์ • ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. <see cref="Clear(string)"/>์™€ ๋™์ผํ•˜๊ฒŒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.
        /// </summary>
        public void Remove(string category) => Clear(category);
        /// <summary>
        /// ์„ค์ •์œผ๋กœ๋ถ€ํ„ฐ ํŠน์ • ์˜ต์…˜์„ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.
        /// </summary>
        public void Remove(string category, string optionName)
        {
            ConfigOption temp = Hierarchy[category][optionName];
            Hierarchy[category].Remove(optionName);
            Linear.Remove(temp);
            if (Hierarchy[category].Count > 0)
                return;
            Hierarchy.Remove(category);
        }
        /// <summary>
        /// ํ•ด๋‹น ๊ฐœ์ฒด์˜ ํŠน์ • ์นดํ…Œ๊ณ ๋ฆฌ์— ์˜ต์…˜์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
        /// </summary>
        public void Set(string category, string optionName, string value)
        {
            if (!Hierarchy.ContainsKey(category))
                Hierarchy.Add(category, new Dictionary<string, ConfigOption>());
            if (!Hierarchy[category].ContainsKey(optionName))
            {
                ConfigOption temp = new ConfigOption(category, optionName, value);
                Hierarchy[category].Add(optionName, temp);
                Linear.Add(temp, true);
            }
            else
                Hierarchy[category][optionName].Value = value;
        }
        public void SetInt(string category, string optionName, int value)
            => Set(category, optionName, value.ToString());
        public void SetBool(string category, string optionName, bool value)
            => Set(category, optionName, value.ToString());
        public void SetDouble(string category, string optionName, double value)
            => Set(category, optionName, value.ToString());
        public void SetFloat(string category, string optionName, float value)
            => Set(category, optionName, value.ToString());
        /// <summary>
        /// ํ•ด๋‹น ๊ฐœ์ฒด์˜ <see cref="DefaultCategory"/>(๊ธฐ๋ณธ ์นดํ…Œ๊ณ ๋ฆฌ)์— ์˜ต์…˜์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
        /// </summary>
        public void Set(string optionName, string value) => Set(DefaultCategory, optionName, value);
        /// <summary>
        /// ํ•ด๋‹น ๊ฐœ์ฒด๋กœ๋ถ€ํ„ฐ ์ง€์ •๋œ ์นดํ…Œ๊ณ ๋ฆฌ์˜ ์˜ต์…˜ ๊ฐ’์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
        /// </summary>
        /// <param name="defaultValue">์˜ต์…˜ ๊ฐ’์ด ์กด์žฌํ•˜์ง€ ์•Š์•˜์„ ๊ฒฝ์šฐ ๋ฐ˜ํ™˜ํ•  ๊ธฐ๋ณธ๊ฐ’์ž…๋‹ˆ๋‹ค.</param>
        public string Get(string category, string optionName, string defaultValue = "")
        {
            return (ContainsOption(category, optionName)) ? Hierarchy[category][optionName].Value : defaultValue;
        }
        public int GetInt(string category, string optionName, int defaultValue = -1)
        {
            int result; return (int.TryParse(Get(category, optionName), out result)) ? result : defaultValue;
        }
        public bool GetBool(string category, string optionName, bool defaultValue = false)
        {
            bool result; return (bool.TryParse(Get(category, optionName), out result)) ? result : defaultValue;
        }
        public double GetDouble(string category, string optionName, double defaultValue = 0.0)
        {
            double result; return (double.TryParse(Get(category, optionName), out result)) ? result : defaultValue;
        }
        public float GetFloat(string category, string optionName, float defaultValue = 0.0F)
        {
            float result; return (float.TryParse(Get(category, optionName), out result)) ? result : defaultValue;
        }
        /// <summary>
        /// ํ•ด๋‹น ๊ฐœ์ฒด๋กœ๋ถ€ํ„ฐ <see cref="DefaultCategory"/>(๊ธฐ๋ณธ ์นดํ…Œ๊ณ ๋ฆฌ)์˜ ์˜ต์…˜ ๊ฐ’์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
        /// </summary>
        /// <param name="defaultValue">์˜ต์…˜ ๊ฐ’์ด ์กด์žฌํ•˜์ง€ ์•Š์•˜์„ ๊ฒฝ์šฐ ๋ฐ˜ํ™˜ํ•  ๊ธฐ๋ณธ๊ฐ’์ž…๋‹ˆ๋‹ค.</param>
        public string Get(string optionName, string defaultValue = "") => Get(DefaultCategory, optionName, defaultValue);
        /// <summary>
        /// ์ง€์ •๋œ ๋ฌธ์ž์—ด ๊ฒฝ๋กœ์˜ ํŒŒ์ผ์— ์„ค์ •์„ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค.
        /// </summary>
        public void Write(string fileName)
        {
            // ํŒŒ์ผ์— Writeํ•ฉ๋‹ˆ๋‹ค.
            File.WriteAllText(fileName, ToString());
        }
        public override string ToString()
        {
            // ์•„์›ƒํ’‹ ๋ฒ„ํผ์ž…๋‹ˆ๋‹ค.
            string _outputBuffer = string.Empty;
            foreach (var _tuple in Hierarchy)
            {
                _outputBuffer += "[" + _tuple.Key + "]\r\n";
                foreach (var __tuple in _tuple.Value)
                {
                    var ___key = __tuple.Key;
                    var ___value = __tuple.Value.Value;
                    _outputBuffer += ___key + "=" + ___value + "\r\n";
                }
            }
            return _outputBuffer;
        }
        /// <summary>
        /// ์ง€์ •๋œ ํŒŒ์ผ์ŠคํŠธ๋ฆผ์œผ๋กœ๋ถ€ํ„ฐ ์„ค์ •์„ ์ฝ์–ด๋“ค์ž…๋‹ˆ๋‹ค.
        /// </summary>
        public bool Read(string fileName)
        {
            Config _temp = new Config();
            try
            {
                string[] _inputBuffer = System.IO.File.ReadAllLines(fileName);
                // ๊ธฐ๋ณธ ์นดํ…Œ๊ณ ๋ฆฌ๋Š” DefaultCategory ์ž…๋‹ˆ๋‹ค. (์ƒ๋žต๋œ ์นดํ…Œ๊ณ ๋ฆฌ์— ๋Œ€ํ•œ ๋ชจ๋“  ์ฒ˜๋ฆฌ = DefaultCategory๋กœ ๋ถ„๋ฅ˜)
                string _lastCategory = DefaultCategory;
                // ๋ฒ„ํผ๋ฅผ ์ค„ ๋‹จ์œ„๋กœ ์ฝ์–ด๋“ค์ด๋ฉด์„œ ๋ถ„์„ํ•ฉ๋‹ˆ๋‹ค.
                foreach (var __input in _inputBuffer)
                {
                    // ์ฒซ ๋ฒˆ์งธ ๋ฌธ์ž๊ฐ€ [๋กœ ์‹œ์ž‘ํ–ˆ์„ ๋•Œ, ์ด ์ค„์ด ์นดํ…Œ๊ณ ๋ฆฌ์ธ์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
                    int __delimOpenIndex = __input.IndexOf('[');
                    if (__delimOpenIndex == 0)
                    {
                        int __delimCloseIndex = __input.IndexOf(']');
                        if (__delimCloseIndex > __delimOpenIndex)
                        {
                            _lastCategory = __input.Substring(1, __delimCloseIndex - 1);
                            continue;
                        }
                    }
                    // ์ด ์ค„์ด ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ์•„๋‹ˆ์—ˆ์„ ๊ฒฝ์šฐ, '=' ๋ฌธ์ž๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
                    int __eqIndex = __input.IndexOf('=');
                    if (__eqIndex < 0)
                        continue;
                    string __key = __input.Substring(0, __eqIndex);
                    string __value = __input.Substring(__eqIndex + 1, __input.Length - __eqIndex - 1);
                    _temp.Set(_lastCategory, __key, __value);
                }
            }
            catch { return false; }
            // ์–•์€ ๋ณต์‚ฌ๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
            Hierarchy = _temp.Hierarchy;
            Linear = _temp.Linear;
            return true;
        }
    }
    /// <summary>
    /// ๋‹จ์ผ ์„ค์ •์„ ๊ตฌ์„ฑํ•˜๋Š” ๊ฐ€์žฅ ์ž‘์€ ํ˜•ํƒœ์˜ ๊ฐœ์ฒด์ž…๋‹ˆ๋‹ค. ์ž„์˜๋กœ ์ƒ์„ฑํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
    /// </summary>
    public class ConfigOption
    {
        internal ConfigOption(string category, string name, string value)
        {
            Category = category;
            Name = name;
            Value = value;
        }
        internal ConfigOption Clone()
        {
            return new ConfigOption(Category, Name, Value);
        }
        /// <summary>
        /// ํ•ด๋‹น ์„ค์ •์ด ์†ํ•œ ์นดํ…Œ๊ณ ๋ฆฌ ๊ฐ’์ž…๋‹ˆ๋‹ค.
        /// </summary>
        public string Category { get; private set; }
        /// <summary>
        /// ํ•ด๋‹น ์„ค์ •์˜ ์ด๋ฆ„๊ฐ’์ž…๋‹ˆ๋‹ค.
        /// </summary>
        public string Name { get; private set; }
        /// <summary>
        /// ํ•ด๋‹น ์„ค์ •์˜ ๊ฐ’์ž…๋‹ˆ๋‹ค.
        /// </summary>
        public string Value { get; set; }
        public override string ToString() { return $"[{Category}] {Name}={Value}"; }
    }
}
โš ๏ธ **GitHub.com Fallback** โš ๏ธ