//==============================================================
//  版权所有：深圳杰文科技
//  文件名：SqlServerDao.cs
//  版本：V1.0  
//  创建者：Jay  ( QQ： 85363208 )
//  创建时间：2017-11-28 16:18
//  创建描述：
//  修改者：
//  修改时间：
//  修改说明： 
//==============================================================

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

namespace Infrastructure.Utilities
{
	//有连接池，自动管理事务。
	public class SqlServerDao : IDisposable
	{
		private SqlConnection conn = null;
		private SqlTransaction tran = null;

		public SqlServerDao(DataSourceSetting setting)
		{
			this.Setting = setting;
		}

		public SqlServerDao(string serverName, string account, string password, string dbName)
		{
			this.Setting = new DataSourceSetting()
			{
				Id = Guid.NewGuid(),
				Server = serverName,
				User = account,
				Password = password,
				DbName = dbName,
				DbType = DataSourceSetting.DbTypes.SqlServer
			};
		}

		public DataSourceSetting Setting
		{
			get;
			private set;
		}

		private void InitConnection()
		{
			if (conn == null)
			{
				conn = new SqlConnection(Setting.ConnectionString);
			}

			if (conn.State == ConnectionState.Closed)
			{
				conn.Open();
			}
		}

		public void BeginTransaction()
		{
			InitConnection();
			tran = conn.BeginTransaction();
		}

		public void CommitTransaction()
		{
			if (tran != null)
			{
				tran.Commit();
			}
		}

		public void RollbackTransaction()
		{
			if (tran != null)
			{
				tran.Rollback();
			}
		}

		public List<T> Select<T>() where T : new()
		{
			return SelectTop<T>(0, "");
		}

		public List<T> Select<T>(string where) where T : new()
		{
			return SelectTop<T>(0, where);
		}

		public List<T> SelectTop<T>(int recordNumber, string where) where T : new()
		{
			where = where.Trim();

			string top = "";
			if (recordNumber > 0)
			{
				top = " top " + recordNumber.ToString() + " ";
			}

			if (!where.IsNullOrEmpty() && !where.StartsWith("and"))
			{
				where = "and " + where;
			}

			string sql = "";

			FieldInfo sqlFieldInfo = typeof(T).GetField("SQL");
			if (sqlFieldInfo != null) //如果有手工定义SQL，那么优先采用；
			{
				sql = sqlFieldInfo.GetValue(null).ToString().Fmt(where).Trim();
				if (!top.IsNullOrEmpty())
				{
					sql = sql.Insert(7, top);
				}
			}
			else //否则自动生成select。
			{
				string tableName = DbUtil.GetTableName<T>();
				sql = "select {2} * from {0} where 1=1 {1}".Fmt(tableName, where, top);
			}

			DbUtil.Log(sql);

			List<T> list = null;
			InitConnection();
			using (SqlDataAdapter da = new SqlDataAdapter())
			{
				if (tran != null)
				{
					da.SelectCommand = new SqlCommand(sql, conn, tran);
				}
				else
				{
					da.SelectCommand = new SqlCommand(sql, conn);
				}
				using (DataTable table = new DataTable())
				{
					da.Fill(table);
					list = table.ToList<T>();
				}
			}
			return list;
		}

		public T FirstOrDefault<T>(string where) where T : new()
		{
			List<T> list = SelectTop<T>(1, where);
			if (list.Any())
			{
				return list[0];
			}
			return default(T);
		}

		public int Insert<T>(T entity)
		{
			string sql = DbUtil.GenerateInsertSql(Setting.DbType, typeof(T), entity);
			int cnt = Execut(sql);
			return cnt;
		}

		public int Insert<T>(IEnumerable<T> list)
		{
			int count = 0;
			foreach (T item in list)
			{
				count += Insert<T>(item);
			}
			return count;
		}

		public int Update<T>(T entity)
		{
			return Update<T>(entity, "");
		}

		public int Update<T>(T entity, string where)
		{
			if (!where.IsNullOrEmpty())
			{
				where = where.Trim();
				if (!where.StartsWith("and"))
				{
					where = " and " + where;
				}
			}
			string sql = DbUtil.GenerateUpdateSql(Setting.DbType, typeof(T), entity);
			sql = sql + where;
			int cnt = Execut(sql);
			return cnt;
		}

		public int Delete<T>(object id)
		{
			string sql = DbUtil.GenerateDeleteSql(Setting.DbType, typeof(T), id);
			int cnt = Execut(sql);
			return cnt;
		}

		public int Delete<T>(IEnumerable<T> list)
		{
			int count = 0;
			foreach (T item in list)
			{
				count += Delete<T>(item);
			}
			return count;
		}

		private int Execut(string sql)
		{
			DbUtil.Log(sql);

			InitConnection();
			SqlCommand cmd = null;

			if (tran != null)
			{
				cmd = new SqlCommand(sql, conn, tran);
			}
			else
			{
				cmd = new SqlCommand(sql, conn);
			}

			int cnt = cmd.ExecuteNonQuery();
			return cnt;
		}

		public void Proc(string procName, params DbParameter[] parameters)
		{
			DbUtil.Log("exec {0} ...".Fmt(procName));

			List<SqlParameter> sqlParameters = new List<SqlParameter>();
			foreach (DbParameter parameter in parameters)
			{
				sqlParameters.Add((SqlParameter)parameter);
			}

			InitConnection();
			SqlCommand cmd = conn.CreateCommand();
			cmd.CommandType = CommandType.StoredProcedure;
			cmd.CommandText = procName;
			cmd.Parameters.AddRange(sqlParameters.ToArray());

			if (tran != null)
			{
				cmd.Transaction = tran;
			}

			int cnt = cmd.ExecuteNonQuery();
		}

		public List<T> Proc<T>(string procName, params DbParameter[] parameters) where T : new()
		{
			DbUtil.Log("exec {0} ...".Fmt(procName));

			List<SqlParameter> sqlParameters = new List<SqlParameter>();
			foreach (DbParameter parameter in parameters)
			{
				sqlParameters.Add((SqlParameter)parameter);
			}

			InitConnection();
			SqlCommand cmd = conn.CreateCommand();
			cmd.CommandType = CommandType.StoredProcedure;
			cmd.CommandText = procName;
			cmd.Parameters.AddRange(sqlParameters.ToArray());

			if (tran != null)
			{
				cmd.Transaction = tran;
			}

			List<T> list = null;
			using (SqlDataAdapter da = new SqlDataAdapter())
			{
				if (tran != null)
				{
					da.SelectCommand = new SqlCommand(procName, conn, tran);
				}
				else
				{
					da.SelectCommand = new SqlCommand(procName, conn);
				}
				using (DataTable table = new DataTable())
				{
					da.Fill(table);
					list = table.ToList<T>();
				}
			}

			return list;
		}

		public bool Open(out string exception)
		{
			exception = "";
			using (SqlConnection conn = new SqlConnection(Setting.ConnectionString))
			{
				try
				{
					conn.Open();
				}
				catch (Exception ex)
				{
					exception = ex.InnerException == null ? ex.Message : ex.InnerException.Message;
					return false;
				}
			}
			return true;
		}

		public string GetTimestampWhere(Type type, DateTime startTimestamp, DateTime endTimestamp)
		{
			if (startTimestamp == endTimestamp)
			{
				throw new Exception("时间戳的开始和结束时间不能相等");
			}

			string timestampWhere = "";
			string timestampFieldName = DbUtil.GetTimestampFieldName(type);
			if (!timestampFieldName.IsNullOrEmpty())
			{
				timestampWhere = "({0} >= '{1}' and {0} <= '{2}')".Fmt(timestampFieldName, startTimestamp, endTimestamp);
			}
			return timestampWhere;
		}

		public void Dispose()
		{
			if (tran != null)
			{
				tran.Dispose();
			}

			if (conn != null)
			{
				conn.Dispose();
			}
		}

		public List<T> SqlQuery<T>(string sql) where T : new()
		{
			DbUtil.Log(sql);

			List<T> list = null;
			InitConnection();
			using (SqlDataAdapter da = new SqlDataAdapter())
			{
				if (tran != null)
				{
					da.SelectCommand = new SqlCommand(sql, conn, tran);
				}
				else
				{
					da.SelectCommand = new SqlCommand(sql, conn);
				}
				using (DataTable table = new DataTable())
				{
					da.Fill(table);
					list = table.ToList<T>();
				}
			}
			return list;
		}

	}
}
