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

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;
using System.Linq;
using Framework.Common;

namespace Framework.DomainBase
{
	public static class AuditedLogService
	{
		private static Dictionary<string, TableInfo> _TableInfoDict = null;

		public static List<AuditedLog> Track(this DbContext db)
		{
			List<AuditedLog> AuditedLogs = new List<AuditedLog>();

			if (_TableInfoDict == null)
			{
				InitData(db);
			}

			string account = "";
			string ip = "";
			if (db is IDB)
			{
				IDB idb = db as IDB;
				account = idb.CurrentUser.Name;
				ip = idb.CurrentUser.IP;
			}

			IEnumerable<DbEntityEntry> changeTracker = db.ChangeTracker.Entries().Where(p =>
				p.State == EntityState.Added ||
				p.State == EntityState.Deleted ||
				p.State == EntityState.Modified);
			foreach (DbEntityEntry entry in changeTracker)
			{
				if (entry.Entity == null)
				{
					continue;
				}

				string entityName = ObjectContext.GetObjectType(entry.Entity.GetType()).Name;
				if (entityName == "AuditedLog")
				{
					continue;
				}

				EntityState state = entry.State;
				switch (entry.State)
				{
					case EntityState.Added:
						foreach (string fieldName in entry.CurrentValues.PropertyNames)
						{
							if (fieldName == "Version")
							{
								continue;
							}
							AuditedLogs.Add(NewLog(account, ip, entityName, state, fieldName, "", entry.CurrentValues[fieldName]));
						}
						break;

					case EntityState.Modified:
						foreach (string fieldName in entry.OriginalValues.PropertyNames)
						{
							if (fieldName == "Version")
							{
								continue;
							}

							object currentValue = entry.CurrentValues[fieldName];
							object originalValue = entry.GetDatabaseValues()[fieldName];

							if (!Object.Equals(currentValue, originalValue) && entry.Property(fieldName).IsModified == true)
							{
								AuditedLogs.Add(NewLog(account, ip, entityName, state, fieldName, originalValue, currentValue));
							}
						}
						break;

					case EntityState.Deleted:
						foreach (string fieldName in entry.OriginalValues.PropertyNames)
						{
							if (fieldName == "Version")
							{
								continue;
							}

							object originalValue = entry.GetDatabaseValues()[fieldName];
							if (originalValue != null)
							{
								AuditedLogs.Add(NewLog(account, ip, entityName, state, fieldName, entry.OriginalValues[fieldName], ""));
							}
						}
						break;
				}
			}

			return AuditedLogs;
		}

		private static AuditedLog NewLog(string account, string ip, string tableName, EntityState state, string fieldName, object oldValue, object newValue)
		{
			AuditedLog log = new AuditedLog
			{
				LogId = Guid.NewGuid(),
				Caption = tableName + "." + fieldName,
				TableName = tableName,
				State = state,
				FieldName = fieldName,
				OldValue = oldValue == null ? "" : oldValue.ToString(),
				NewValue = newValue == null ? "" : newValue.ToString(),
				CreatedBy = account,
				CreatedOn = DateTime.Now,
				HostName = ip
			};

			TableInfo tableInfo;
			if (_TableInfoDict.TryGetValue(tableName + fieldName, out tableInfo))
			{
				log.Caption = tableInfo.Desc;
			}

			return log;
		}

		private static void InitData(DbContext db)
		{
			_TableInfoDict = new Dictionary<string, TableInfo>();
			foreach (TableInfo tableInfo in db.Query<TableInfo>(""))
			{
				_TableInfoDict.Add(tableInfo.TableName + tableInfo.FieldName, tableInfo);
			}
		}
	}
}
