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

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
using System.Configuration;
using Infrastructure.Components;

namespace Framework.BaseUI
{
	/// <summary>
	/// 解析模块信息。
	/// </summary>
	public class ModuleParser
	{
		private Type dllAttributeType;
		private Type moduleAttributeType;

		public List<ModuleInfo> ModuleInfoList = new List<ModuleInfo>();
		public List<RootModuleAttribute> RootModuleList = new List<RootModuleAttribute>();

		#region Instance

		private static ModuleParser instance = new ModuleParser();

		public static ModuleParser Instance
		{
			get
			{
				return instance;
			}
		}

		private ModuleParser()
		{
			dllAttributeType = typeof(RootModuleAttribute);
			moduleAttributeType = typeof(ModuleAttribute);
		}

		#endregion

		public void Analyse(string[] assemblies)
		{
			Clear();

			List<string> modules = GetModuleFileNameList(Application.StartupPath, assemblies);
			foreach (string fileName in modules) //只装载当前路径下的模块。
			{
				Assembly asm = null;
				try
				{
					if (File.Exists(fileName))
					{
						asm = Assembly.LoadFrom(fileName); //装载DLL文件
					}
					else
					{
						MsgBox.Show("文件{0}不存在，请与系统管理员联系！", fileName);
					}
				}
				catch //(Exception ex)
				{
					//MsgBox.Show(String.Format("装载{0}文件错误，请与系统管理员联系！\r\n\r\n", fileName) + ex.Message);
					continue;
				}
				ParseModuleAttribute(asm, fileName);
			}

			//SortModule(); 生成菜单时会排序
		}

		private void SortModule()
		{
			RootModuleList.Sort(delegate(RootModuleAttribute a, RootModuleAttribute b)
			{
				if (a.Order > b.Order)
				{
					return 1;
				}
				else if (a.Order < b.Order)
				{
					return -1;
				}
				return 0;
			});

			ModuleInfoList.Sort(delegate(ModuleInfo a, ModuleInfo b)
			{
				if (a.Attribute.Order > b.Attribute.Order)
				{
					return 1;
				}
				else if (a.Attribute.Order < b.Attribute.Order)
				{
					return -1;
				}
				return 0;
			});
		}

		/// <summary>
		/// 分析当前目前下指定的文件
		/// </summary>
		public void Analyse(string fileName)
		{
			Clear();
			Assembly asm = Assembly.LoadFrom(fileName);
			if (asm != null)
			{
				ParseModuleAttribute(asm, fileName);
			}
		}

		public void Clear()
		{
			ModuleInfoList.Clear();
			RootModuleList.Clear();
		}

		#region - ParseModuleAttribute -

		private void ParseModuleAttribute(Assembly asm, string fileName)
		{
			//如果DLL没有定义RootModuleAttribute属性，或者设置为不分析此DLL，那么忽略此DLL文件
			RootModuleAttribute[] rootModuleAttributes = GetRootModuleAttribute(asm, dllAttributeType);
			foreach (RootModuleAttribute rootModuleAttribute in rootModuleAttributes)
			{
				if (!rootModuleAttribute.AnalyseModule)
				{
					return;
				}
				RootModuleAttribute foundRootModule = IsRootModuleExists(rootModuleAttribute.Name);
				if (foundRootModule == null)
				{
					this.RootModuleList.Add(rootModuleAttribute);
				}
				else if (foundRootModule.Order > rootModuleAttribute.Order)
				{
					foundRootModule.Order = rootModuleAttribute.Order;
				}
				//分析DLL文件中所有的类信息
				Type[] types = null;
				try
				{
					types = asm.GetTypes();

					foreach (Type type in types)
					{
						var r = from a in ModuleInfoList
								where a.FullClassName == type.FullName
								select a;
						if (r.Count() > 0)
						{
							continue;
						}

						//如果类中定义了ModuleInfoAttribute，那么取出属性值
						if (!type.IsDefined(moduleAttributeType, true))
						{
							continue;
						}

						object[] memberInfoes = type.GetCustomAttributes(moduleAttributeType, true);
						if (memberInfoes.Length > 0)
						{
							ModuleAttribute moduleInfo = memberInfoes[0] as ModuleAttribute;
							AddModule(rootModuleAttribute.Name, type, moduleInfo, fileName);
						}
					}
				}
				catch (Exception ex)
				{
					throw new Exception(string.Format("装载{0}发生错误，请与系统管理员联系！\r\n\r\n{1}", asm.FullName, ex.Message));
				}
			}
		}

		private RootModuleAttribute[] GetRootModuleAttribute(Assembly asm, Type dllAttributeType)
		{
			List<RootModuleAttribute> list = new List<RootModuleAttribute>();
			if (asm.IsDefined(dllAttributeType, false)) //如果DLL定义了RootModuleAttribute属性
			{
				object[] memberInfoes = asm.GetCustomAttributes(dllAttributeType, false);
				memberInfoes.ToList().ForEach(a => list.Add(a as RootModuleAttribute));
			}
			return list.ToArray();
		}

		//判断根模块是否已经加载过了
		private RootModuleAttribute IsRootModuleExists(string rootModuleName)
		{
			var r = from a in this.RootModuleList
					where a.Name == rootModuleName
					select a;
			return r.FirstOrDefault();
		}

		private void AddModule(string rootModuleName, Type type, ModuleAttribute moduleAttribute, string moduleName)
		{
			string[] moduleNames = moduleAttribute.Name.Split('.');
			if (!string.IsNullOrEmpty(moduleAttribute.RootModule))
			{
				if (moduleAttribute.RootModule != moduleNames[0])
				{
					moduleAttribute.Name = moduleAttribute.RootModule + "." + moduleAttribute.Name;
				}
			}
			else
			{
				if (!moduleAttribute.Name.StartsWith(rootModuleName))
				{
					moduleAttribute.Name = rootModuleName + "." + moduleAttribute.Name;
				}
			}

			//如果根模块没有加载（通常是因为此根模块没有单独的DLL文件），那么立即加载
			if (!string.IsNullOrEmpty(moduleAttribute.RootModule))
			{
				RootModuleAttribute foundRootModule = IsRootModuleExists(moduleAttribute.RootModule);
				if (foundRootModule == null)
				{
					RootModuleAttribute rootModule = new RootModuleAttribute();
					rootModule.Name = moduleAttribute.RootModule;
					rootModule.Order = 100;
					this.RootModuleList.Add(rootModule);
				}
			}

			if (ModuleInfoList.Any(a => a.Attribute.Name == moduleAttribute.Name)) //菜单重名会导致生成菜单进递归溢出。
			{
				throw new Exception("菜单重名：" + moduleAttribute.Name);
			}

			ModuleInfo moduleInfo = new ModuleInfo()
			{
				Attribute = moduleAttribute,
				DllPath = moduleName,
				FullClassName = type.FullName
			};
			ModuleInfoList.Add(moduleInfo);
		}

		//获取要分析的文件列表
		private List<string> GetModuleFileNameList(string dllPath, string[] assemblies)
		{
			List<string> fileTypeList = new List<string> { "Framework.*.dll", "Framework.*.exe", "Framework.*.dll" };
			fileTypeList.AddRange(assemblies);

			List<string> fileList = new List<string>();
			foreach (string fileType in fileTypeList)
			{
				foreach (string fileName in Directory.GetFiles(dllPath, fileType, SearchOption.TopDirectoryOnly))
				{
					if (Path.GetFileName(fileName).Contains(".Upgrade.exe"))
					{
						continue;
					}
					fileList.Add(fileName);
				}
			}
			return fileList;
		}

		#endregion

		public ModuleInfo GetModuleInfoByModuleName(string fullModuleName)
		{
			return ModuleInfoList.FirstOrDefault(a => a.Attribute.Name == fullModuleName);
		}

		public ModuleInfo GetModuleInfo(string fullClassName)
		{
			return ModuleInfoList.FirstOrDefault(a => a.FullClassName == fullClassName);
		}

		#region 分配模块权限

		//分配运行权限。
		public void AssignRunPermission()
		{
			foreach (ModuleInfo moduleInfo in this.ModuleInfoList)
			{
				//如果是Fix模块（通常用于About窗体、关闭系统），那么任何用户，都可以无条件进入
				//如果是系统模块，并且是系统管理员，那么无条件可进入
				if ((moduleInfo.Attribute.SystemModule && ClientContext.User.IsAdmin) || moduleInfo.Attribute.Fix)
				{
					moduleInfo.CanRun = true;
				}
				else
				{
					moduleInfo.CanRun = PermissionManager.Instance.HasPermission(moduleInfo.Attribute.Name, "运行");
				}
			}
		}

		#endregion

		#region 得到指定窗体中的所有定义了ActionAttribute的属性值列表

		private Dictionary<Type, List<ActionAttribute>> _MethodPropertyDict = new Dictionary<Type, List<ActionAttribute>>();

		public List<ActionAttribute> GetMethodPropertyList(ModuleInfo moduleInfo)
		{
			Type type = ModuleProxy.Instance.LoadType(moduleInfo);
			return GetMethodPropertyList(type);
		}

		public List<ActionAttribute> GetMethodPropertyList(Type formType)
		{
			if (_MethodPropertyDict.ContainsKey(formType)) //如果已经分析过，那么直接从缓存中取出
			{
				return _MethodPropertyDict[formType] as List<ActionAttribute>;
			}

			BindingFlags bindings = BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
			MethodInfo[] methodInfoList = formType.GetMethods(bindings);

			int n = 100; //未设置Sequence属性的方法，默认排到后面

			Type attributeType = typeof(ActionAttribute);
			List<ActionAttribute> propertyList = new List<ActionAttribute>();

			foreach (MethodInfo method in methodInfoList)
			{
				if (method.Name == "RestoreCustomStyle" && !ToolbarBaseForm.AutoSaveLayout)
				{
					continue;
				}

				if (method.IsDefined(attributeType, false)) //如果方法加上了属性
				{
					object[] memberInfoes = method.GetCustomAttributes(false);
					if (memberInfoes.Length > 0)
					{
						ActionAttribute property = memberInfoes[0] as ActionAttribute;
						property.Method = method;
						property.Order = property.Order == -1 ? n++ : property.Order;
						propertyList.Add(property);
					}
				}
			}

			_MethodPropertyDict.Add(formType, propertyList);
			return propertyList;
		}

		public ActionAttribute GetMethodProperty(Type formType, string action)
		{
			List<ActionAttribute> propertyList = GetMethodPropertyList(formType);
			foreach (ActionAttribute att in propertyList)
			{
				if (att.Method.Name == action)
				{
					return att;
				}
			}
			return null;
		}

		//根据方法名称（英文），得到权限名称（中文）
		//注意，此方法仅匹配方法名称，不匹配方法的参数
		public string GetMethodName(Type formType, string action)
		{
			if (action == "Load")
			{
				return "运行";
			}

			ActionAttribute att = GetMethodProperty(formType, action);
			return att == null ? "" : att.Name;
		}

		#endregion

		#region 获取模块（窗体）中所有的工具栏方法

		public List<ActionAttribute> GetActionList(ModuleInfo moduleInfo)
		{
			List<ActionAttribute> actionList = new List<ActionAttribute>();
			Type attributeType = typeof(ActionAttribute);

			Assembly asm = Assembly.LoadFrom(moduleInfo.DllPath);
			Type formType = asm.GetType(moduleInfo.FullClassName, false);
			if (formType == null)
			{
				return actionList;
			}

			BindingFlags bindings = BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
			MethodInfo[] methodInfoList = formType.GetMethods(bindings);
			foreach (MethodInfo method in methodInfoList)
			{
				if (method.IsDefined(attributeType, false)) //如果方法加上了属性
				{
					object[] memberInfoes = method.GetCustomAttributes(false);
					if (memberInfoes.Length > 0)
					{
						ActionAttribute property = memberInfoes[0] as ActionAttribute;
						property.Method = method;
						actionList.Add(property);
					}
				}
			}
			return actionList;
		}

		#endregion
	}
}
