using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;

namespace Knoks.Framework.Extentions
{
    public static class GeneralExtentions
    {
        public static IDictionary<K, object> ToAnyObjDictionary<K, V>(this IDictionary<K, V> rawDict)
        {
            if (rawDict == null) return null;
            return rawDict.ToDictionary(p => p.Key, p => (object)p.Value);
        }

        public static T ToEnum<T>(this string value, bool ignoreCase = true) where T : struct
        {
            T result;
            if (Enum.TryParse<T>(value, ignoreCase, out result))
                return result;

            throw new InvalidCastException($"Cast error. String value '{ value ?? "[null]" }' to { typeof(T) } type");
        }

        public static T ToEnum<T>(this string value, T defaultValue, bool ignoreCase = true) where T : struct
        {
            if (string.IsNullOrEmpty(value))
                return defaultValue;

            T result;
            return Enum.TryParse<T>(value, ignoreCase, out result) ? result : defaultValue;
        }

        public static bool IsAnonymousType(this Type type)
        {
            return type.Name.Contains("AnonymousType")
                && (type.Name.StartsWith("<>", StringComparison.OrdinalIgnoreCase) || type.Name.StartsWith("VB$", StringComparison.OrdinalIgnoreCase));
        }

        public static double EvaluateExpression(this string input)
        {
            //https://github.com/nreco/lambdaparser/blob/master/src/NReco.LambdaParser.Tests/LambdaParserTests.cs
            var lambdaParser = new NReco.Linq.LambdaParser();
            IDictionary<string, object> varContext = new Dictionary<string, object>();
            varContext["pow"] = (Func<string, string, double>)((num, power) => Math.Pow(num.EvaluateExpression(), power.EvaluateExpression()));
            varContext["sqrt"] = (Func<string, double>)((num) => Math.Sqrt(num.EvaluateExpression()));
            var ans = lambdaParser.Eval(input, varContext);
            return Convert.ToDouble(ans);
        }

        public static string RemoveNonDigits(this string phoneNumber)
        {
            return new string(phoneNumber.Where(c => char.IsDigit(c)).ToArray());
        }

        public static DataTable ToDataTable<T>(this IEnumerable<T> data)
        {
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));

            var table = new DataTable();
            foreach (PropertyDescriptor prop in properties)
                table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);

            if (data == null) return table;

            foreach (T item in data)
            {
                var row = table.NewRow();
                foreach (PropertyDescriptor prop in properties)
                    row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;

                table.Rows.Add(row);
            }

            return table;
        }
    }
}
