using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Reflection;
using System.Text;

namespace Infrastructure.Utilities
{
	public static class DataTableHelper
	{
		public enum FieldMappingMode
		{
			Same, //表的字段名与实体的属性名完全一致。
			NonUnderline //实体的属性名无下划线。
		}

		public static FieldMappingMode FieldMapping = FieldMappingMode.Same;

		public static int DecimalDigit = 2; //默认Decimal的小数位数是2位。

		public static List<TEntity> Mapping<TEntity>(DbDataReader reader) where TEntity : new()
		{
			List<TEntity> list = new List<TEntity>();
			foreach (object entity in Mapping(typeof(TEntity), reader))
			{
				list.Add((TEntity)entity);
			}
			return list;
		}

		public static List<TEntity> ToList<TEntity>(this DataTable table) where TEntity : new()
		{
			return Mapping<TEntity>(table);
		}

		public static TEntity To<TEntity>(this DataRow row) where TEntity : new()
		{
			Type entityType = typeof(TEntity);
			object obj = Mapping(entityType, row, ReflectHelper.GetPropertyList(entityType));
			return (TEntity)obj;
		}

		public static List<TEntity> Mapping<TEntity>(DataTable table) where TEntity : new()
		{
			List<TEntity> list = new List<TEntity>();
			foreach (object entity in Mapping(typeof(TEntity), table))
			{
				list.Add((TEntity)entity);
			}
			return list;
		}

		public static ArrayList Mapping(Type entityType, DataTable table)
		{
			List<PropertyInfo> pies = ReflectHelper.GetPropertyList(entityType);

			ArrayList list = new ArrayList();
			foreach (DataRow row in table.Rows)
			{
				object entity = Mapping(entityType, row, pies);
				list.Add(entity);
			}
			return list;
		}

		public static object Mapping(Type entityType, DataRow row, IEnumerable<PropertyInfo> pies)
		{
			object entity = Activator.CreateInstance(entityType);
			for (int i = 0; i < row.Table.Columns.Count; i++)
			{
				if (row.IsNull(i))
				{
					continue;
				}
				string fieldName = row.Table.Columns[i].ColumnName.ToLower(); //字段不区分大小写。
				if (FieldMapping == FieldMappingMode.NonUnderline) //如果属性名无下划线，
				{
					fieldName = fieldName.Replace("_", "");
				}
				PropertyInfo pi = pies.FirstOrDefault(a => a.Name.ToLower() == fieldName);
				if (pi == null)
				{
					continue;
				}

				object fieldValue = row[i];
				fieldValue = ReflectHelper.ConvertValue(fieldValue, pi);

				try
				{
					pi.SetValue(entity, fieldValue, null);
				}
				catch (Exception ex)
				{
					throw new Exception("{0}表的{1}字段无法给属性{2}赋值，错误原因：\r\n{3}".Fmt(entityType.Name, fieldName, pi.Name, ex.Message));
				}
			}
			return entity;
		}

		public static ArrayList Mapping(Type entityType, DbDataReader reader)
		{
			PropertyInfo[] pies = entityType.GetProperties();

			ArrayList list = new ArrayList();
			while (reader.Read())
			{
				object entity = Activator.CreateInstance(entityType);
				for (int i = 0; i < reader.FieldCount; i++)
				{
					if (reader.IsDBNull(i))
					{
						continue;
					}
					string fieldName = reader.GetName(i).ToLower(); //字段不区分大小写。
					if (FieldMapping == FieldMappingMode.NonUnderline) //如果属性名无下划线，
					{
						fieldName = fieldName.Replace("_", "");
					}
					PropertyInfo pi = pies.FirstOrDefault(a => a.Name.ToLower() == fieldName);
					if (pi == null)
					{
						continue;
					}

					object fieldValue = reader.GetValue(i);
					fieldValue = ReflectHelper.ConvertValue(fieldValue, pi);

					try
					{
						pi.SetValue(entity, fieldValue, null);
					}
					catch (Exception ex)
					{
						throw new Exception("{0}表的{1}字段无法给属性{2}赋值，错误原因：\r\n{3}".Fmt(entityType.Name, fieldName, pi.Name, ex.Message));
					}
				}
				list.Add(entity);
			}
			reader.Close();
			return list;
		}
		
		public static DataTable ToDataTable(this IList list)
		{
			DataTable result = new DataTable();
			if (list.Count > 0)
			{
				PropertyInfo[] propertys = list[0].GetType().GetProperties();
				foreach (PropertyInfo pi in propertys)
				{
					//获取类型
					Type colType = pi.PropertyType;
					//当类型为Nullable<>时
					if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition() == typeof(Nullable<>)))
					{
						colType = colType.GetGenericArguments()[0];
					}
					result.Columns.Add(pi.Name, colType);
				}
				for (int i = 0; i < list.Count; i++)
				{
					ArrayList tempList = new ArrayList();
					foreach (PropertyInfo pi in propertys)
					{
						object obj = pi.GetValue(list[i], null);
						tempList.Add(obj);
					}
					object[] array = tempList.ToArray();
					result.LoadDataRow(array, true);
				}
			}
			return result;
		}


	}
}
