using System;
using System.Collections.Generic;
using InABox.Core;

namespace InABox.Configuration
{
    public enum ConfigurationCacheType
    {
        Local,
        Global,
        User
    }

    public static class ConfigurationCache
    {
        private static readonly Dictionary<Type, Dictionary<string, string>> _localcache = new Dictionary<Type, Dictionary<string, string>>();
        private static readonly Dictionary<Type, Dictionary<string, string>> _globalcache = new Dictionary<Type, Dictionary<string, string>>();
        private static readonly Dictionary<Type, Dictionary<string, string>> _usercache = new Dictionary<Type, Dictionary<string, string>>();

        private static Dictionary<Type, Dictionary<string, string>> GetCache(ConfigurationCacheType type)
        {
            return type == ConfigurationCacheType.Local
                ? _localcache
                : type == ConfigurationCacheType.Global
                    ? _globalcache
                    : _usercache;
        }

        public static T Check<T>(ConfigurationCacheType type, string section)
        {
            Logger.Send(LogType.Information, "", string.Format("- Checking {0}({1},{2})", typeof(T), type, section));
            var _cache = GetCache(type);
            if (_cache.ContainsKey(typeof(T)))
            {
                var subcache = _cache[typeof(T)];
                if (subcache.ContainsKey(section))
                {
                    var data = subcache[section];
                    if (!string.IsNullOrWhiteSpace(data))
                    {
                        Logger.Send(LogType.Information, "",
                            string.Format("- Checking: Found {0}({1},{2}) -> {3}", typeof(T), type, section, subcache[section]));
                        var result = Serialization.Deserialize<T>(subcache[section]);
                        return result;
                    }
                }
            }

            return default(T);
        }

        public static void Add<T>(ConfigurationCacheType type, string section, T config)
        {
            Logger.Send(LogType.Information, "", string.Format("- Adding {0}({1},{2})", typeof(T), type, section));
            var _cache = GetCache(type);
            if (!_cache.ContainsKey(typeof(T)))
                _cache[typeof(T)] = new Dictionary<string, string>();
            var subcache = _cache[typeof(T)];
            subcache[section] = Serialization.Serialize(config);
        }

        public static void Clear<T>(ConfigurationCacheType type, string section)
        {
            Logger.Send(LogType.Information, "", string.Format("- Clearing {0}({1},{2})", typeof(T), type, section));
            var _cache = GetCache(type);
            if (_cache.ContainsKey(typeof(T)))
            {
                var subcache = _cache[typeof(T)];
                if (subcache.ContainsKey(section))
                {
                    Logger.Send(LogType.Information, "", string.Format("- Clearing: Removing {0}({1},{2})", typeof(T), type, section));
                    subcache[section] = "";
                }
            }
        }

        /// <summary>
        ///     Clear the entire cache for a given cache type <see cref="ConfigurationCacheType" />. Intended for use when the
        ///     database server has changed and therefore the entire cache needs to be reset.
        /// </summary>
        /// <param name="type">The type of cache to clear. </param>
        public static void ClearAll(ConfigurationCacheType type)
        {
            var _cache = GetCache(type);
            _cache.Clear();
        }
    }
}