using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace LHDN.CRM.BC.Common
{

    // Extensions that only usable in WebUI level
    public static class Extensions
    {
        //public static void AppendValue(this string strCurrent, string strValue, string strSeparator = " ")
        //{
        //    if (strCurrent.Length == 0)
        //        strCurrent = strValue;
        //    else
        //        strCurrent = strCurrent + strSeparator + strValue;
        //}

        //public static void Append(this string strCurrent, string strValue)
        //{
        //    strCurrent += strValue;
        //}


        /// <summary>
        ///     ''' Gets name of the enum
        ///     ''' </summary>
        ///     ''' <typeparam name="T"></typeparam>
        ///     ''' <param name="value"></param>
        ///     ''' <returns></returns>
        ///     ''' <remarks></remarks>
        public static string GetName<T>(this T value)
        {
            if ((typeof(T) == typeof(string)))
                return value.ToString();

            return Enum.GetName(typeof(T), value);
        }

        //public static object GetEnumValue(this string value, Type enumType)
        //{
        //    return Enum.Parse(enumType, value);
        //}

        ///// <summary>
        /////     ''' Converts to Decimal Object
        /////     ''' </summary>
        /////     ''' <param name="strDatetime"></param>
        /////     ''' <remarks></remarks>
        //public static decimal? ToDecimal(this string strValue)
        //{
        //    decimal dec = 0;
        //    strValue = strValue.Replace(",", "");

        //    if (decimal.TryParse(strValue, ref dec))
        //        return dec;
        //    else
        //        return default(Decimal?);
        //}

        ///// <summary>
        /////     ''' Converts datetime to 20 Sep 2014 format
        /////     ''' </summary>
        /////     ''' <param name="strDatetime"></param>
        /////     ''' <remarks></remarks>
        //public static string ToDateShort(this string strDatetime)
        //{
        //    DateTime dtValue = DateTime.Now;
        //    DateTime.TryParse(strDatetime, ref dtValue);
        //    return dtValue.ToString(Constants.DateTimeFormat.DateFormat);
        //}

        ///// <summary>
        /////     ''' Converts datetime to 20 September 2014 format
        /////     ''' </summary>
        /////     ''' <param name="strDatetime"></param>
        /////     ''' <remarks></remarks>
        //public static string ToDateLong(this ref string strDatetime)
        //{
        //    DateTime dtValue = DateTime.Now;
        //    DateTime.TryParse(strDatetime, ref dtValue);
        //    return dtValue.ToString(Constants.DateTimeFormat.DateFormatLong);
        //}

        ///// <summary>
        /////     ''' Converts datetime to 20 Sep 2014 05:25 PM format
        /////     ''' </summary>
        /////     ''' <param name="strDatetime"></param>
        /////     ''' <remarks></remarks>
        //public static string ToDateTimeShort(this ref string strDatetime)
        //{
        //    DateTime dtValue = DateTime.Now;
        //    DateTime.TryParse(strDatetime, ref dtValue);
        //    return dtValue.ToString(Constants.DateTimeFormat.DateTimeFormat);
        //}

        ///// <summary>
        /////     ''' Converts datetime to 20 September 2014 05:25 PM format
        /////     ''' </summary>
        /////     ''' <param name="strDatetime"></param>
        /////     ''' <remarks></remarks>
        //public static string ToDateTimeLong(this ref string strDatetime)
        //{
        //    DateTime dtValue = DateTime.Now;
        //    DateTime.TryParse(strDatetime, ref dtValue);
        //    return dtValue.ToString(Constants.DateTimeFormat.DateTimeFormatLong);
        //}


        ///// <summary>
        /////     ''' Converts String to Boolean value. If the value is invalid, it will return as False
        /////     ''' </summary>
        /////     ''' <param name="value"></param>
        /////     ''' <returns></returns>
        /////     ''' <remarks></remarks>
        //public static bool ToBoolean(this string value)
        //{
        //    bool blnValue = false;

        //    if (bool.TryParse(value, out blnValue))
        //        return blnValue;

        //    return blnValue;
        //}

        /// <summary>
        ///     ''' Converts String to Boolean value. If the value is invalid, it will return as False
        ///     ''' </summary>
        ///     ''' <param name="value"></param>
        ///     ''' <returns></returns>
        ///     ''' <remarks></remarks>
        public static bool ToBooleanSafe(this string value)
        {
            if (string.IsNullOrEmpty(value))
                return false;
            else
                return Convert.ToBoolean(value);
        }

        /// <summary>
        ///     ''' Converts object to int value. If the value is null, it will return as 0
        ///     ''' </summary>
        ///     ''' <param name="value"></param>
        ///     ''' <returns></returns>
        ///     ''' <remarks></remarks>
        public static int ToIntSafe(this object obj)
        {
            if (obj != null && obj != DBNull.Value && !string.IsNullOrEmpty(obj.ToStringSafe()))
                return System.Convert.ToInt32(obj);
            else
                return 0;
        }

        /// <summary>
        ///     ''' Converts object to string value. If the value is null, it will return as string.empty
        ///     ''' </summary>
        ///     ''' <param name="value"></param>
        ///     ''' <returns></returns>
        ///     ''' <remarks></remarks>
        public static string ToStringSafe(this object obj)
        {
            if (obj != null && obj != DBNull.Value)
                return obj.ToString();
            else
                return string.Empty;
        }

        public static string ToStringDash(this object obj)
        {
            if (obj != null && obj != DBNull.Value && !string.IsNullOrEmpty(obj.ToString()))
                return obj.ToString();
            else
                return "-";
        }


        ///// <summary>
        /////     ''' Converts object to string html friendly characters. If the value is null, it will return as string.empty
        /////     ''' </summary>
        /////     ''' <param name="value"></param>
        /////     ''' <returns></returns>
        /////     ''' <remarks></remarks>
        //public static string ToHTML(this object obj)
        //{
        //    if (obj != null && obj != DBNull.Value)
        //    {
        //        string strValue = obj.ToString();
        //        strValue = strValue.Replace(Constants.vbCrLf, Constants.HTMLNextRow);
        //        return strValue;
        //    }
        //    else
        //        return string.Empty;
        //}

        ///// <summary>
        /////     ''' Converts object to dbvalue value. If the value is null, it will return as dbnull.value
        /////     ''' </summary>
        /////     ''' <param name="value"></param>
        /////     ''' <returns></returns>
        /////     ''' <remarks></remarks>
        //public static object ToDBObjectSafe(this object obj)
        //{
        //    if (obj == null)
        //        return DBNull.Value;
        //    else
        //        return obj;
        //}

        public static DataTable ToDataTable<T>(this List<T> list, string strColumnName, string strTblName)
        {
            DataTable dTblNew = new DataTable();
            dTblNew.TableName = strTblName;
            dTblNew.Columns.Add(strColumnName, typeof(T));

            foreach (T obj in list)
                dTblNew.Rows.Add(obj);

            return dTblNew;
        }

        //public static bool CompareObj<T>(this T obj, T objToCompare, out DataTable dTblCompareResult)
        //{
        //    bool blnIsSame = true;
        //   DataTable dTblCompareResult = new DataTable();

        //    if (dTblCompareResult == null)
        //    {
        //        dTblCompareResult.Columns.Add("FieldName");
        //        dTblCompareResult.Columns.Add("OldValue");
        //        dTblCompareResult.Columns.Add("NewValue");
        //    }

        //    System.Reflection.PropertyInfo[] prop = obj.GetType().GetProperties();

        //    foreach (System.Reflection.PropertyInfo p in prop)
        //    {
        //        DataRow dRowData = dTblCompareResult.NewRow();

        //        dRowData["FieldName"] = p.Name;
        //        dRowData["OldValue"] = p.GetValue(obj, null);
        //        dRowData["NewValue"] = p.GetValue(objToCompare, null);

        //        if (!dRowData["OldValue"].Equals(dRowData["NewValue"]))
        //        {
        //            dTblCompareResult.Rows.Add(dRowData);
        //            blnIsSame = false;
        //        }
        //    }

        //        return blnIsSame;
        //}

        public static DataTable ToDataTable<T>(this IList<T> data)
        {
            PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(T));
            bool blnIsRemoveCol = false;
            DataTable table = new DataTable();
            for (int i = 0; i <= props.Count - 1; i++)
            {
                PropertyDescriptor prop = props[i];
                if (prop.ComponentType.Name == "FieldValueViewModel")
                {
                    if (prop.Name == "FieldValue")
                    {
                        table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? typeof(string));
                        continue;
                    }
                }
                else if (prop.ComponentType.Name == "DisplayColumnViewModel")
                {
                    blnIsRemoveCol = true;
                }
                table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
            }
        
            object[] values = new object[props.Count - 1 + 1];
            foreach (T item in data)
            {
                for (int i = 0; i <= values.Length - 1; i++)
                    values[i] = props[i].GetValue(item) ?? DBNull.Value;
                table.Rows.Add(values);
            }
            if (blnIsRemoveCol && table.Columns.Contains("IsSystemUse"))
                table.Columns.Remove("IsSystemUse");
            return table;
        }

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

            DataTable table = new DataTable();
            for (int i = 0; i < props.Count; i++)
            {
                PropertyDescriptor prop = props[i];
                table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
            }

            object[] values = new object[props.Count];

            for (int i = 0; i < values.Length; i++)
            {
                values[i] = props[i].GetValue(data) ?? DBNull.Value;
            }

            table.Rows.Add(values);

            return table;
        }

        public static DataTable ToDataTable<T>()
        {
            PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(T));

            DataTable table = new DataTable();
            for (int i = 0; i <= props.Count - 1; i++)
            {
                PropertyDescriptor prop = props[i];
                table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
            }

            return table;
        }

        public static string[] Split(this string value, string delimiter)
        {
            if (value.HasValue())
            {
                return value.Split(new string[] { delimiter }, StringSplitOptions.RemoveEmptyEntries);
            }

            return new string[] { };
        }

        public static bool HasValue(this string value)
        {
            return !string.IsNullOrEmpty(value) && value != "null"; // To handle the calendar value
        }

        public static bool HasValue(this JValue value)
        {
            return value.Value.ToString("").HasValue();
        }

        public static string ToString(this object value, string defaultValue = "")
        {
            if (value != null && value.ToString().HasValue())
            {
                return value.ToString();
            }

            return defaultValue;
        }

        //public static Dictionary<T1, T2> ToDictionary<T1, T2>(this DataTable dTbl, string strKeyColumnName, string strValueColumnName)
        //{
        //    Dictionary<T1, T2> dic = new Dictionary<T1, T2>();

        //    foreach (DataRow dRow in dTbl.Rows)
        //    {
        //        T1 objKey = (T1)dRow[strKeyColumnName];
        //        T2 objVal = (T2)dRow[strValueColumnName];

        //        if (!dic.ContainsKey(objKey))
        //            dic.Add(objKey, objVal);
        //        else
        //            dic[objKey] = objVal;
        //    }

        //    return dic;
        //}

        //public static void SetColumnsOrder(this DataTable table, params String[] columnNames)
        //{
        //    for (int columnIndex = 0; columnIndex <= columnNames.Length - 1; columnIndex++)
        //        table.Columns(columnNames[columnIndex]).SetOrdinal(columnIndex);
        //}

        //public static void Add<T>(this ref T[] arr, T item)
        //{
        //    Array.Resize(ref arr, arr.Length + 1);
        //    arr[arr.Length - 1] = item;
        //}


    }

}
