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}"; }
}
}