using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using ZeroLevel.Services.Reflection;
using ZeroLevel.Services.Serialization;
namespace ZeroLevel.Services.Config
{
///
/// Упрощенная конфигурация, без разделения параметров по секциям
///
internal sealed class BaseConfiguration :
IConfiguration
{
#region Private members
///
/// Указывает на заморозку конфигурации, все изменения запрещены
///
private bool _freezed = false;
///
/// Указывает на перманентную заморозку конфигурации, разморозка запрещена
///
private bool _permanentFreezed = false;
private readonly object _freezeLock = new object();
///
/// Список вида ключ-значение
///
private readonly ConcurrentDictionary> _keyValues = new ConcurrentDictionary>();
///
/// Пустой список
///
private static readonly IEnumerable EmptyValuesList = new List(0);
private static string GetKey(string key)
{
if (string.IsNullOrWhiteSpace(key))
{
throw new ArgumentNullException("key");
}
return key.Trim().ToLower(CultureInfo.InvariantCulture);
}
#endregion
#region Properties
///
/// Список значений по ключу
///
/// Ключ
/// Список значений
public IEnumerable this[string key]
{
get
{
key = key.ToLower(CultureInfo.CurrentCulture);
IList result;
if (_keyValues.TryGetValue(key, out result))
{
return result;
}
return EmptyValuesList;
}
}
///
/// Список ключей
///
public IEnumerable Keys
{
get { return _keyValues.Keys; }
}
public bool Freezed
{
get
{
return _freezed;
}
}
#endregion
#region Public methods
#region Get
///
/// Получение списка значение соотвествующих указанному ключу
///
/// Ключ
/// Список значений
public IEnumerable Items(string key)
{
return this[key];
}
///
/// Получение первого значения для указанного ключа
///
/// Ключ
/// Первое значение, или null если ключ есть, но нет значений, или KeyNotFoundException если нет ключа
public string First(string key)
{
IList result;
if (_keyValues.TryGetValue(GetKey(key), out result))
{
if (result.Count > 0)
return result[0];
return null;
}
throw new KeyNotFoundException("Key not found: " + key);
}
public void DoWithFirst(string key, Action action)
{
if (Contains(key))
{
action(First(key));
}
}
public void DoWithFirst(string key, Action action)
{
if (Contains(key))
{
action(First(key));
}
}
///
/// Получение первого значения для указанного ключа, с попыткой преобразования в указанный тип
///
/// Ожидаемый тип
/// Ключ
/// Первое значение, или default(T) если ключ есть, но нет значений, или KeyNotFoundException если нет ключа
public T First(string key)
{
IList result;
if (_keyValues.TryGetValue(GetKey(key), out result))
{
if (result.Count > 0)
return (T)StringToTypeConverter.TryConvert(result[0], typeof(T));
return default(T);
}
throw new KeyNotFoundException("Parameter not found: " + key);
}
///
/// Получение первого значения для указанного ключа, или значения по умолчанию
///
/// Ключ
/// Значение по умолчанию
/// Первое значение, или значение по умолчанию если нет значений или ключа
public string FirstOrDefault(string key, string defaultValue)
{
IList result;
if (_keyValues.TryGetValue(GetKey(key), out result))
{
if (result.Count > 0)
return result[0];
}
return defaultValue;
}
///
/// Получение первого значения для указанного ключа, или значения по умолчанию, с попыткой преобразования в указанный тип
///
/// Ожидаемый тип
/// Ключ
/// Первое значение, или default(T) если нет значений или ключа
public T FirstOrDefault(string key)
{
IList result;
if (_keyValues.TryGetValue(GetKey(key), out result))
{
if (result.Count > 0)
return (T)StringToTypeConverter.TryConvert(result[0], typeof(T));
}
return default(T);
}
///
/// Получение первого значения для указанного ключа, или значения по умолчанию, с попыткой преобразования в указанный тип
///
/// Ожидаемый тип
/// Ключ
/// Значение по умолчанию
/// Первое значение, или значение по умолчанию если нет значений или ключа
public T FirstOrDefault(string key, T defaultValue)
{
IList result;
if (_keyValues.TryGetValue(GetKey(key), out result))
{
if (result.Count > 0)
return (T)StringToTypeConverter.TryConvert(result[0], typeof(T));
}
return defaultValue;
}
///
/// Проверка наличия ключа и непустого списка связанных с ним значений
///
/// Ключ
/// true - если существует ключ и есть хотя бы одно значение
public bool Contains(string key)
{
key = GetKey(key);
return _keyValues.ContainsKey(key) && _keyValues[key].Count > 0;
}
///
/// Проверка наличия одного из ключей
///
public bool Contains(params string[] keys)
{
foreach (var key in keys)
if (Contains(key)) return true;
return false;
}
///
/// Проверка наличия ключа и связанного с ним значения
///
///
///
///
public bool ContainsValue(string key, string value)
{
IList result;
if (_keyValues.TryGetValue(GetKey(key), out result))
{
return result.Contains(value);
}
return false;
}
///
/// Количество значений связанных с указанным ключом
///
/// Ключ
/// Количество значений
public int Count(string key)
{
key = GetKey(key);
if (_keyValues.ContainsKey(key))
{
return _keyValues[key].Count;
}
return 0;
}
#endregion
///
/// Добавление ключа и связанного с ним значения
///
/// Ключ
/// Значение
public IConfiguration Append(string key, string value)
{
if (false == _freezed)
{
key = GetKey(key);
if (false == _keyValues.ContainsKey(key))
{
_keyValues.TryAdd(key, new List());
}
_keyValues[key].Add(value?.Trim() ?? null);
}
return this;
}
///
/// Задает значение в единственном числе,
/// существующее значение будет перезаписано
///
public IConfiguration SetUnique(string key, string value)
{
if (false == _freezed)
{
key = GetKey(key);
if (false == _keyValues.ContainsKey(key))
{
_keyValues.TryAdd(key, new List());
}
_keyValues[key].Clear();
_keyValues[key].Add(value?.Trim() ?? null);
}
return this;
}
///
/// Очистка связанного с ключом списка значений
///
/// Ключ
public IConfiguration Clear(string key)
{
if (false == _freezed)
{
key = GetKey(key);
if (_keyValues.ContainsKey(key))
{
_keyValues[key].Clear();
}
}
return this;
}
///
/// Очистка конфигурации
///
public IConfiguration Clear()
{
if (false == _freezed)
{
_keyValues.Clear();
}
return this;
}
///
/// Удаление ключа и связанных с ним значений
///
/// Ключ
public IConfiguration Remove(string key)
{
if (false == _freezed)
{
IList removed;
_keyValues.TryRemove(GetKey(key), out removed);
}
return this;
}
public bool Freeze(bool permanent = false)
{
lock (_freezeLock)
{
if (false == _freezed)
{
_freezed = true;
_permanentFreezed = permanent;
return true;
}
else if (_permanentFreezed == false && permanent)
{
_permanentFreezed = true;
return true;
}
return false;
}
}
public bool Unfreeze()
{
lock (_freezeLock)
{
if (_freezed && _permanentFreezed == false)
{
_freezed = false;
return true;
}
return false;
}
}
#endregion
#region IEquatable
public bool Equals(IConfiguration other)
{
if (other == null)
{
return false;
}
if (this.Keys.NoOrderingEquals(other.Keys) == false)
{
return false;
}
foreach (var key in Keys)
{
if (this[key].NoOrderingEquals(other[key]) == false)
{
return false;
}
}
return true;
}
#endregion
#region Binary Serializable
public void Serialize(IBinaryWriter writer)
{
writer.WriteBoolean(this._freezed);
writer.WriteBoolean(this._permanentFreezed);
writer.WriteInt32(_keyValues.Count);
foreach (var pair in _keyValues)
{
writer.WriteString(pair.Key);
writer.WriteInt32(pair.Value.Count);
foreach (var value in pair.Value)
{
writer.WriteString(value);
}
}
}
public void Deserialize(IBinaryReader reader)
{
this._freezed = reader.ReadBoolean();
this._permanentFreezed = reader.ReadBoolean();
var count = reader.ReadInt32();
_keyValues.Clear();
for (int i = 0; i < count; i++)
{
var key = reader.ReadString();
var count_values = reader.ReadInt32();
var list_values = new List();
for (var k = 0; k < count_values; k++)
{
list_values.Add(reader.ReadString());
}
_keyValues.TryAdd(key, list_values);
}
}
#endregion
}
}