using EasyDevCore.Common;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace EasyDev.Database.EntityTable
{
    /// <summary>
    /// 
    /// </summary>
    public static class DataTableExtensions
    {
        /// <summary>
        /// Loads the asynchronous.
        /// </summary>
        /// <param name="source">The source.</param>
        /// <param name="reader">The reader.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        public static async Task LoadAsync(this DataTable source, DbDataReader reader, CancellationToken cancellationToken = default)
        {
            if (reader.IsClosed) return;
            int totalRows = source.Rows.Count;
            List<Tuple<int, int>> mapRcTcColumns = null;
            bool isFirst = true;
            while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
            {
                if (isFirst)
                {
                    Dictionary<string, int> readerColumns = new Dictionary<string, int>(StringComparer.InvariantCultureIgnoreCase);
                    for (int i = 0; i < reader.FieldCount; i++)
                    {
                        readerColumns[reader.GetName(i)] = i;
                    }
                    if (source.Columns.Count == 0)
                    {
                        for (int col = 0; col < reader.FieldCount; col++)
                        {
                            source.Columns.Add(reader.GetName(col), reader.GetFieldType(col));
                        }
                    }
                    mapRcTcColumns = (from rc in readerColumns
                                      join tc in source.Columns.Cast<DataColumn>() on rc.Key equals tc.ColumnName
                                      select new Tuple<int, int>(rc.Value, tc.Ordinal)).ToList();
                    isFirst = false;
                }
                var newRow = source.NewRow();
                for (int i = 0; i < mapRcTcColumns.Count; i++)
                {
                    newRow[mapRcTcColumns[i].Item2] = reader.GetValue(mapRcTcColumns[i].Item1) ?? DBNull.Value;
                }
                source.Rows.Add(newRow);
            }
            bool hasNextResult = await reader.NextResultAsync(cancellationToken).ConfigureAwait(false);
            if (!hasNextResult) await reader.CloseAsync().ConfigureAwait(false);
        }

        /// <summary>
        /// Firsts the or add.
        /// </summary>
        /// <typeparam name="TSource">The type of the source.</typeparam>
        /// <param name="source">The source.</param>
        /// <returns></returns>
        public static TSource FirstOrAdd<TSource>(this DataTable source) where TSource : DataRow
        {
            if (source.Rows.Count == 0)
            {
                return (TSource)(source as DataTable).DefaultView.AddNew().Row;
            }
            else
            {
                return (TSource)(source as DataTable).DefaultView[0].Row;
            }
        }

        /// <summary>
        /// Ases the enumberable.
        /// </summary>
        /// <param name="source">The source.</param>
        /// <returns></returns>
        public static IEnumerable<DataRow> AsEnumberable(this DataTable source)
        {
            System.Collections.IEnumerator iterator = source.AsEnumberable().GetEnumerator();
            while (iterator.MoveNext())
            {
                yield return (DataRow)iterator.Current;
            }
        }

        /// <summary>
        /// Adds the new row.
        /// </summary>
        /// <param name="source">The source.</param>
        /// <returns></returns>
        public static DataRow AddNewRow(this DataTable source)
        {
            var newRow = source.NewRow();
            source.Rows.Add(newRow);
            return newRow;
        }

        /// <summary>
        /// Finds the DataRow.
        /// </summary>
        /// <param name="source">The source.</param>
        /// <param name="values">The values.</param>
        /// <returns></returns>
        public static DataRow FindDataRow(this DataTable source, params object[] values)
        {
            var argValues = ArgumentHelper.GetArgValues(values);
            DataView view = new DataView(source as DataTable, string.Empty, string.Join(",", argValues.Keys), DataViewRowState.CurrentRows);
            int rowIndex = view.Find(argValues.Values.ToArray());
            return rowIndex == -1 ? null : view[rowIndex].Row;
        }

        /// <summary>
        /// Gets the index of the specified DataRow object.
        /// </summary>
        /// <param name="source">The source.</param>
        /// <param name="DataRow">The DataRow.</param>
        /// <returns></returns>
        public static int IndexOf(this DataTable source, DataRow DataRow)
        {
            return source.IndexOf(DataRow);
        }

        /// <summary>
        /// Gets the matched columns list.
        /// </summary>
        /// <param name="source">The source.</param>
        /// <param name="dest">The dest.</param>
        /// <param name="columnNames">The colum names filter (can be use = for mapping; ex: ColumnName = PropertyName).</param>
        /// <param name="exceptColumnNames">The except column names.</param>
        /// <returns></returns>
        internal static IDictionary<string, string> GetMatchedColumnsList(this DataTable source, DataTable dest, string columnNames = "", string exceptColumnNames = "")
        {
            bool hasMapping = columnNames.Contains("=");
            IEnumerable<string> colNames = columnNames.SplitCommaString(trimSpace: true);
            if (columnNames.Contains("*") || string.IsNullOrWhiteSpace(columnNames))
            {
                colNames = from s in source.Columns.OfType<DataColumn>()
                           join d in dest.Columns.OfType<DataColumn>() on s.ColumnName equals d.ColumnName
                           select s.ColumnName;
            }
            HashSet<string> exceptColNames = new HashSet<string>(exceptColumnNames.SplitCommaString(trimSpace: true));
            Dictionary<string, string> mapColumns = colNames.Where(c => !exceptColNames.Contains(c))
                                                    .Select((s) =>
                                                    {
                                                        if (hasMapping && s.Contains("="))
                                                        {
                                                            var names = s.SplitString("=", trimSpace: true);
                                                            return new { Key = names[0], Value = names[1] };
                                                        }
                                                        return new { Key = s, Value = s };
                                                    }).ToDictionary(k => k.Key, v => v.Value);

            return mapColumns;
        }

        /// <summary>
        /// Gets the matched properties list.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">The source.</param>
        /// <param name="columnNames">The colum names filter (can be use = for mapping; ex: ColumnName = PropertyName).</param>
        /// <param name="exceptColumnNames">The except column names.</param>
        /// <param name="ignorePrefix">The ignore prefix.</param>
        /// <returns>IDictionary&lt;System.String, PropertyDescriptor&gt;.</returns>
        internal static IDictionary<string, PropertyDescriptor> GetMatchedPropertiesList<T>(this DataTable source, string columnNames = "", string exceptColumnNames = "", string ignorePrefix = "")
        {
            if (source == null)
            {
                return new Dictionary<string, PropertyDescriptor>();
            }
            Type DataRowType = typeof(T);
            bool mapAllColumns = columnNames.Contains("*") || string.IsNullOrWhiteSpace(columnNames);
            bool hasIgnorePrefix = !string.IsNullOrWhiteSpace(ignorePrefix);
            string[] ignorePrefixes = ignorePrefix.SplitByCommaOrSemiColon();
            bool hasMapping = columnNames.Contains("=");
            bool hasExceptColumn = !string.IsNullOrWhiteSpace(exceptColumnNames);
            string[] exceptColNames = exceptColumnNames.SplitCommaString(trimSpace: true);
            Dictionary<string, PropertyDescriptor> allProperties = TypeDescriptor.GetProperties(DataRowType).Cast<PropertyDescriptor>().ToDictionary(p =>
            {
                if (hasIgnorePrefix)
                {
                    if (ignorePrefixes.Length > 1)
                    {
                        foreach (var prefix in ignorePrefixes)
                        {
                            if (prefix.StartsWith(prefix))
                            {
                                return p.Name.Substring(prefix.Length);
                            }
                        }
                    }
                    else if (p.Name.StartsWith(ignorePrefix))
                    {
                        return p.Name.Substring(ignorePrefix.Length);
                    }
                }
                return p.Name;
            });
            Dictionary<string, string> colNames = columnNames.SplitCommaString(trimSpace: true)
                                                .Where(c => !mapAllColumns || !c.Contains("*"))
                                                .Select((s) =>
                                                {
                                                    if (hasMapping && s.Contains("="))
                                                    {
                                                        var names = s.SplitString("=", trimSpace: true);
                                                        return new { Key = names[0], Value = names[1] };
                                                    }
                                                    return new { Key = s, Value = s };
                                                }).ToDictionary(k => k.Key, v => v.Value);

            IDictionary<string, PropertyDescriptor> mapProperties = source.Columns.Cast<DataColumn>()
                .Select(c => new { c.ColumnName, PropertyName = colNames.ContainsKey(c.ColumnName) ? colNames[c.ColumnName] : c.ColumnName })
                .Where(c => (mapAllColumns || colNames.ContainsKey(c.ColumnName))
                            && allProperties.ContainsKey(c.PropertyName)
                            && (!hasExceptColumn || Array.IndexOf(exceptColNames, c.ColumnName) == -1)
                       )
                       .ToDictionary(c => c.ColumnName, c => allProperties[c.PropertyName]);
            return mapProperties;
        }

        /// <summary>
        /// Imports from model list.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">The source.</param>
        /// <param name="list">The list.</param>
        /// <param name="columnNames">The colum names filter (can be use = for mapping; ex: ColumnName = PropertyName).</param>
        /// <param name="exceptColumnNames">The except column names.</param>
        /// <param name="ignorePrefix">The ignore prefix.</param>
        public static void ImportFromModel<T>(this DataTable source, IList<T> list, string columnNames = "", string exceptColumnNames = "", string ignorePrefix = "")
        {
            Type DataRowType = typeof(T);
            IDictionary<string, PropertyDescriptor> updateProperties = source.GetMatchedPropertiesList<T>(columnNames, exceptColumnNames, ignorePrefix);
            foreach (T item in list)
            {
                var newRow = source.NewRow();
                newRow.UpdateFromModel(item, updateProperties);
                source.Rows.Add(newRow);
            }
        }

        /// <summary>
        /// Convert to Model List.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">The source.</param>
        /// <param name="columnNames">The colum names filter (can be use = for mapping; ex: ColumnName = PropertyName).</param>
        /// <param name="exceptColumnNames">The except column names.</param>
        /// <param name="modelStatusField">The model status field has receive status of source (field type must be DataRowState).</param>
        /// <param name="ignorePrefix">The ignore prefix.</param>
        /// <param name="method">The method.</param>
        /// <returns>IList&lt;T&gt;.</returns>
        public static IList<T> ConvertToModel<T>(this DataTable source, string columnNames = "", string exceptColumnNames = "", string modelStatusField = "", string ignorePrefix = "", Action<T> method = null)
        {
            Type DataRowType = typeof(T);
            IDictionary<string, PropertyDescriptor> updateProperties = source.GetMatchedPropertiesList<T>(columnNames, exceptColumnNames, ignorePrefix);
            IList<T> list = new List<T>();
            if (source != null)
            {
                foreach (DataRow DataRow in source.Rows)
                {
                    list.Add(DataRow.ConvertToModel(updateProperties, modelStatusField, method: method));
                }
            }
            return list;
        }

        /// <summary>
        /// Updates from DataRow.
        /// </summary>
        /// <param name="source">The source.</param>
        /// <param name="value">The value.</param>
        /// <param name="columnNames">The colum names filter (can be use = for mapping; ex: ColumnName = PropertyName).</param>
        /// <param name="exceptColumnNames">The except column names.</param>
        /// <param name="keyFields">The key fields. (if not include key fields, auto use keys value to fields)</param>
        /// <returns></returns>
        public static bool UpdateFrom(this DataTable source, DataRow value, string columnNames = "", string exceptColumnNames = "", string keyFields = "")
        {
            string keysColumns = string.Empty;
            List<string> columnList = new List<string>();
            List<object> keysValues = new List<object>();

            if (string.IsNullOrWhiteSpace(keyFields))
            {
                if (source.PrimaryKey?.Length > 0)
                {
                    foreach (var key in source.PrimaryKey)
                    {
                        columnList.Add(key.ColumnName);
                        keysColumns += (string.IsNullOrWhiteSpace(keysColumns) ? string.Empty : ",") + key.ColumnName;
                    }
                }
                else
                {
                    foreach (DataColumn col in source.Columns)
                    {
                        if (col.AutoIncrement)
                        {
                            columnList.Add(col.ColumnName);
                            keysColumns += (string.IsNullOrWhiteSpace(keysColumns) ? string.Empty : ",") + col.ColumnName;
                        }
                    }
                }
            }
            else
            {
                keysColumns = keyFields;
                columnList.AddRange(keysColumns.SplitCommaString(trimSpace: true));
            }

            foreach (string columnName in columnList)
            {
                keysValues.Add(value.GetValue(columnName));
            }

            DataRow row = source.FindDataRow(keysColumns, keysValues.ToArray());
            if (row != null)
            {
                row.UpdateFrom(value, columnNames, exceptColumnNames);
                return true;
            }
            return false;
        }

        /// <summary>
        /// Synches from table.
        /// </summary>
        /// <param name="source">The source.</param>
        /// <param name="values">The values.</param>
        /// <param name="columnUpdateNames">The column update names.</param>
        /// <param name="columnAddNewNames">The column add new names.</param>
        /// <param name="exceptUpdateColumnNames">The except update column names.</param>
        /// <param name="exceptAddNewColumnNames">The except add new column names.</param>
        /// <param name="keyFields">The key fields.</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
        public static void SynchFromTable(this DataTable source, DataTable values, string columnUpdateNames = "", string columnAddNewNames = "", string exceptUpdateColumnNames = "", string exceptAddNewColumnNames = "", string keyFields = "")
        {
            string keysColumns = string.Empty;
            List<string> columnList = new List<string>();
            List<object> keysValues = new List<object>();

            if (string.IsNullOrWhiteSpace(keyFields))
            {
                if (source.PrimaryKey?.Length > 0)
                {
                    foreach (var key in source.PrimaryKey)
                    {
                        columnList.Add(key.ColumnName);
                        keysColumns += (string.IsNullOrWhiteSpace(keysColumns) ? string.Empty : ",") + key.ColumnName;
                    }
                }
                else
                {
                    foreach (DataColumn col in source.Columns)
                    {
                        if (col.AutoIncrement)
                        {
                            columnList.Add(col.ColumnName);
                            keysColumns += (string.IsNullOrWhiteSpace(keysColumns) ? string.Empty : ",") + col.ColumnName;
                        }
                    }
                }
            }
            else
            {
                keysColumns = keyFields;
                columnList.AddRange(keysColumns.SplitCommaString(trimSpace: true));
            }

            IDictionary<string, string> updateColumns = values.GetMatchedColumnsList(source, columnUpdateNames, exceptUpdateColumnNames);
            IDictionary<string, string> addNewColumns = values.GetMatchedColumnsList(source, columnAddNewNames, exceptAddNewColumnNames);

            DataView view = new DataView(source, string.Empty, keysColumns, DataViewRowState.CurrentRows);
            List<DataRow> listSynchItems = new List<DataRow>();

            foreach (DataRow item in values.Rows)
            {
                keysValues.Clear();

                foreach (string columnName in columnList)
                {
                    keysValues.Add(item.GetValue(columnName));
                }

                var rows = view.FindRows(keysValues.ToArray());
                DataRow DataRow = rows != null && rows.Length > 0 ? rows[0].Row : null;
                if (DataRow != null)
                {
                    foreach (var map in updateColumns)
                    {
                        DataRow.SetValue(map.Key, item[map.Value]);
                    }
                    listSynchItems.Add(DataRow);
                }
                else
                {
                    DataRow = source.AddNewRow();
                    foreach (var map in addNewColumns)
                    {
                        DataRow.SetValue(map.Key, item[map.Value]);
                    }
                    listSynchItems.Add(DataRow);
                }
            }

            if (listSynchItems.Count != view.Count)
            {
                foreach (var deletedItem in source.AsEnumerable().Where(r => listSynchItems.IndexOf(r) < 0).ToArray())
                {
                    deletedItem.Delete();
                }
            }
        }

        /// <summary>
        /// Synches from model.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">The source.</param>
        /// <param name="values">The values.</param>
        /// <param name="columnUpdateNames">The column update names.</param>
        /// <param name="columnAddNewNames">The column add new names.</param>
        /// <param name="exceptUpdateColumnNames">The except update column names.</param>
        /// <param name="exceptAddNewColumnNames">The except add new column names.</param>
        /// <param name="keyFields">The key fields.</param>
        /// <param name="ignorePrefix">The ignore prefix.</param>
        public static void SynchFromModel<T>(this DataTable source, IEnumerable<T> values, string columnUpdateNames = "", string columnAddNewNames = "", string exceptUpdateColumnNames = "", string exceptAddNewColumnNames = "", string keyFields = "", string ignorePrefix = "")
        {
            string keysColumns = string.Empty;
            List<string> columnList = new List<string>();
            List<object> keysValues = new List<object>();

            if (string.IsNullOrWhiteSpace(keyFields))
            {
                if (source.PrimaryKey?.Length > 0)
                {
                    foreach (var key in source.PrimaryKey)
                    {
                        columnList.Add(key.ColumnName);
                        keysColumns += (string.IsNullOrWhiteSpace(keysColumns) ? string.Empty : ",") + key.ColumnName;
                    }
                }
                else
                {
                    foreach (DataColumn col in source.Columns)
                    {
                        if (col.AutoIncrement)
                        {
                            columnList.Add(col.ColumnName);
                            keysColumns += (string.IsNullOrWhiteSpace(keysColumns) ? string.Empty : ",") + col.ColumnName;
                        }
                    }
                }
            }
            else
            {
                keysColumns = keyFields;
                columnList.AddRange(keysColumns.SplitCommaString(trimSpace: true));
            }

            IDictionary<string, PropertyDescriptor> updateProperties = source.GetMatchedPropertiesList<T>(columnUpdateNames, exceptUpdateColumnNames, ignorePrefix);
            IDictionary<string, PropertyDescriptor> addNewProperties = source.GetMatchedPropertiesList<T>(columnAddNewNames, exceptAddNewColumnNames, ignorePrefix);

            DataView view = new DataView(source, string.Empty, keysColumns, DataViewRowState.CurrentRows);
            List<DataRow> listSynchItems = new List<DataRow>();
            foreach (T item in values)
            {
                keysValues.Clear();

                foreach (string columnName in columnList)
                {
                    keysValues.Add(item.GetPropertyValue(columnName));
                }

                var rows = view.FindRows(keysValues.ToArray());
                DataRow DataRow = rows != null && rows.Length > 0 ? rows[0].Row : null;
                if (DataRow != null)
                {
                    listSynchItems.Add(DataRow);
                    DataRow.UpdateFromModel(item, updateProperties);
                }
                else
                {
                    DataRow = source.AddNewRow();
                    DataRow.UpdateFromModel(item, addNewProperties);
                    listSynchItems.Add(DataRow);
                }
            }

            if (listSynchItems.Count != view.Count)
            {
                foreach (var deletedItem in source.AsEnumerable().Where(r => listSynchItems.IndexOf(r) < 0).ToArray())
                {
                    deletedItem.Delete();
                }
            }
        }

        /// <summary>
        /// Updates from model.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">The source.</param>
        /// <param name="value">The value.</param>
        /// <param name="columnNames">The colum names filter (can be use = for mapping; ex: ColumnName = PropertyName).</param>
        /// <param name="exceptColumnNames">The except column names.</param>
        /// <param name="keyFields">The key fields.</param>
        /// <param name="ignorePrefix">The ignore prefix.</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
        public static bool UpdateFromModel<T>(this DataTable source, T value, string columnNames = "", string exceptColumnNames = "", string keyFields = "", string ignorePrefix = "")
        {
            string keysColumns = string.Empty;
            List<string> columnList = new List<string>();
            List<object> keysValues = new List<object>();

            if (string.IsNullOrWhiteSpace(keyFields))
            {
                if (source.PrimaryKey?.Length > 0)
                {
                    foreach (var key in source.PrimaryKey)
                    {
                        columnList.Add(key.ColumnName);
                        keysColumns += (string.IsNullOrWhiteSpace(keysColumns) ? string.Empty : ",") + key.ColumnName;
                    }
                }
                else
                {
                    foreach (DataColumn col in source.Columns)
                    {
                        if (col.AutoIncrement)
                        {
                            columnList.Add(col.ColumnName);
                            keysColumns += (string.IsNullOrWhiteSpace(keysColumns) ? string.Empty : ",") + col.ColumnName;
                        }
                    }
                }
            }
            else
            {
                keysColumns = keyFields;
                columnList.AddRange(keysColumns.SplitCommaString(trimSpace: true));
            }

            foreach (string columnName in columnList)
            {
                keysValues.Add(value.GetPropertyValue(columnName));
            }

            IDictionary<string, PropertyDescriptor> updateProperties = source.GetMatchedPropertiesList<T>(columnNames, exceptColumnNames, ignorePrefix);

            DataRow row = source.FindDataRow(keysColumns, keysValues.ToArray());
            if (row != null)
            {
                row.UpdateFromModel(value, updateProperties);
                return true;
            }
            return false;
        }

        /// <summary>
        /// Updates from model.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">The source.</param>
        /// <param name="values">The values.</param>
        /// <param name="columnNames">The colum names filter (can be use = for mapping; ex: ColumnName = PropertyName).</param>
        /// <param name="exceptColumnNames">The except column names.</param>
        /// <param name="keyFields">The key fields.</param>
        /// <param name="ignorePrefix">The ignore prefix.</param>
        public static void UpdateFromModel<T>(this DataTable source, IEnumerable<T> values, string columnNames = "", string exceptColumnNames = "", string keyFields = "", string ignorePrefix = "")
        {
            string keysColumns = string.Empty;
            List<string> columnList = new List<string>();
            List<object> keysValues = new List<object>();

            if (string.IsNullOrWhiteSpace(keyFields))
            {
                if (source.PrimaryKey?.Length > 0)
                {
                    foreach (var key in source.PrimaryKey)
                    {
                        columnList.Add(key.ColumnName);
                        keysColumns += (string.IsNullOrWhiteSpace(keysColumns) ? string.Empty : ",") + key.ColumnName;
                    }
                }
                else
                {
                    foreach (DataColumn col in source.Columns)
                    {
                        if (col.AutoIncrement)
                        {
                            columnList.Add(col.ColumnName);
                            keysColumns += (string.IsNullOrWhiteSpace(keysColumns) ? string.Empty : ",") + col.ColumnName;
                        }
                    }
                }
            }
            else
            {
                keysColumns = keyFields;
                columnList.AddRange(keysColumns.SplitCommaString(trimSpace: true));
            }

            IDictionary<string, PropertyDescriptor> updateProperties = source.GetMatchedPropertiesList<T>(columnNames, exceptColumnNames, ignorePrefix);

            DataView view = new DataView(source, string.Empty, keysColumns, DataViewRowState.CurrentRows);
            foreach (T item in values)
            {
                keysValues.Clear();

                foreach (string columnName in columnList)
                {
                    keysValues.Add(item.GetPropertyValue(columnName));
                }

                DataRow DataRow = view.FindRows(keysValues.ToArray())[0].Row;
                DataRow.UpdateFromModel(item, updateProperties);
            }
        }

        ///// <summary>
        ///// Import Raw XML to DataTable
        ///// </summary>
        ///// <param name="source">The source.</param>
        ///// <param name="xml">The XML.</param>
        //public static void ImportFromRawXML(this DataTable source, string xml)
        //{
        //    ImportFromXML(source, null, xml);
        //}

        ///// <summary>
        ///// Import XML to DataTable
        ///// </summary>
        ///// <param name="source">The source.</param>
        ///// <param name="rootName">Name of the root.</param>
        ///// <param name="xml">The XML.</param>
        //public static void ImportFromRawXML(this DataTable source, string rootName, string xml)
        //{
        //    DataTable entities = DataTable.CreateFromRawXML(xml, rootName);
        //    foreach (DataRow DataRow in entities) source.ImportFrom(entities);
        //}

        ///// <summary>
        ///// Import XML to DataTable
        ///// </summary>
        ///// <param name="source">The source.</param>
        ///// <param name="xml">The XML.</param>
        //public static void ImportFromXML(this DataTable source, string xml)
        //{
        //    ImportFromXML(source, null, xml);
        //}

        ///// <summary>
        ///// Import XML to DataTable
        ///// </summary>
        ///// <param name="source">The source.</param>
        ///// <param name="rootName">Name of the root.</param>
        ///// <param name="xml">The XML.</param>
        //public static void ImportFromXML(this DataTable source, string rootName, string xml)
        //{
        //    DataTable entities = DataTable.CreateFromXML(xml, rootName);
        //    foreach (DataRow DataRow in entities) source.ImportFrom(entities);
        //}
    }
}
