#region Using Statements

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using TaskTools.Attributes;

#endregion

namespace TaskTools.Utilities
{
    internal static class EnumTranslator
    {
        /// <summary>
        /// Translates this instance.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        internal static Dictionary<int, string> Translate<T>()
        {
            return Translate<T>(true);
        }

        internal static List<KeyValuePair<int, string>> EnumToList<T>()
        {
            var ans = Translate<T>(string.Empty, true, false);

            return ans.ToList();
        }

        /// <summary>
        /// Translates the specified check private.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="checkPrivate">if set to <c>true</c> [check private].</param>
        /// <returns></returns>
        internal static Dictionary<int, string> Translate<T>(bool checkPrivate)
        {
            return Translate<T>(string.Empty, checkPrivate);
        }

        /// <summary>
        /// Translates the specified default text.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="defaultText">The default text.</param>
        /// <param name="checkPrivate">if set to <c>true</c> [check private].</param>
        /// <returns></returns>
        internal static Dictionary<int, string> Translate<T>(string defaultText, bool checkPrivate)
        {
            return Translate<T>(defaultText, checkPrivate, true);
        }

        /// <summary>
        /// Translates the specified default text.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="defaultText">The default text.</param>
        /// <param name="checkPrivate">if set to <c>true</c> [check private].</param>
        /// <param name="sorting">if set to <c>true</c> [sorting].</param>
        /// <returns></returns>
        internal static Dictionary<int, string> Translate<T>(string defaultText, bool checkPrivate, bool sorting)
        {
            var types = new Dictionary<int, string>();
            var tempTypes = new Dictionary<int, string>();
            if (!String.IsNullOrEmpty(defaultText)) types.Add(-1, defaultText);
#if NETFX_CORE
            foreach (FieldInfo fieldInfo in typeof(T).GetRuntimeFields())
#else
            foreach (FieldInfo fieldInfo in typeof(T).GetFields(BindingFlags.Static | BindingFlags.GetField | BindingFlags.Public))
#endif
            {
                if (fieldInfo.FieldType != typeof(T))
                {
                    continue;
                }
                bool add = true;
                string displayText = string.Empty;
                T type = (T)fieldInfo.GetValue(typeof(T));
#if NETFX_CORE
                var displayTextAttr = fieldInfo.GetCustomAttribute<DisplayTextAttribute>(true);
                displayText = displayTextAttr?.Text ?? type.ToString();
#else
                object[] displayTextObjectArr = fieldInfo.GetCustomAttributes(typeof(DisplayTextAttribute), true);
                displayText = (displayTextObjectArr.Length > 0)
                                 ? ((DisplayTextAttribute)displayTextObjectArr[0]).Text
                                 : type.ToString();
#endif
                if (checkPrivate)
                {
#if NETFX_CORE
                    var privateAttr = fieldInfo.GetCustomAttribute<PrivateAttribute>(true);
                    if (privateAttr != null)
                    {
                        add = !privateAttr.IsPrivate;
                    }
#else
                    object[] privateAttributeObjectArr = fieldInfo.GetCustomAttributes(typeof(PrivateAttribute), true);
                    if (privateAttributeObjectArr.Length > 0)
                    {
                        add = !((PrivateAttribute)privateAttributeObjectArr[0]).IsPrivate;
                    }
#endif
                }
                if (add)
                {
                    tempTypes.Add(Convert.ToInt32(type), displayText);
                }
            }
            if (sorting)
            {
                foreach (var x in tempTypes.OrderBy(x => x.Value).ToDictionary(x => x.Key, x => x.Value)) { types.Add(x.Key, x.Value); }
            }
            else
            {
                foreach (var x in tempTypes.ToDictionary(x => x.Key, x => x.Value)) { types.Add(x.Key, x.Value); }
            }
            return types;
        }

        /// <summary>
        /// Gets the display text.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        internal static string GetDisplayText<T>(T value)
        {
            var displayText = string.Empty;
#if NETFX_CORE
            var fieldInfo = value.GetType().GetRuntimeField(value.ToString());
#else
            var fieldInfo = typeof(T).GetFields(BindingFlags.Static | BindingFlags.GetField | BindingFlags.Public).FirstOrDefault();
#endif
            if (fieldInfo != null)
            {
                T type = (T)fieldInfo.GetValue(typeof(T));
                if (type != null)
                {
#if NETFX_CORE
                    var displayTextAttr = fieldInfo.GetCustomAttribute<DisplayTextAttribute>(true);
                    displayText = displayTextAttr?.Text ?? type.ToString();
#else
                    object[] displayTextObjectArr = fieldInfo.GetCustomAttributes(typeof(DisplayTextAttribute), true);
                    displayText = (displayTextObjectArr.Length > 0)
                                            ? ((DisplayTextAttribute)displayTextObjectArr[0]).Text
                                            : type.ToString();
#endif
                }
            }
            return displayText;
        }

        internal static int GetValue<T>(string item)
        {
            var list = Translate<T>();

            foreach (var kvp in list)
            {
                if (kvp.Value == item)
                    return kvp.Key;
            }

            return -1;
        }

    }

}
