using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Reflection;
using System.Globalization;
using System.Runtime.InteropServices;

namespace Howest.SchemaDiscovery.CommonHelpers
{
	public sealed class ReflectionHelper
	{
		// Fields
		private static readonly Regex AssemblyNameRegEx;

		private ReflectionHelper()
		{
		}

		static ReflectionHelper()
		{
			AssemblyNameRegEx = new Regex(@"^(?<assembly>[\w\. ]+)(,\s?Version=(?<version>\d+\.\d+\.\d+\.\d+))?(,\s?Culture=(?<culture>\w+))?(,\s?PublicKeyToken=(?<token>\w+))?$", RegexOptions.Compiled);
		}

		private static string BytesToHex(byte[] bytes)
		{
			StringBuilder builder = new StringBuilder(bytes.Length * 2);
			foreach (byte num in bytes)
			{
				builder.Append(num.ToString("x2", CultureInfo.CurrentCulture));
			}
			return builder.ToString();
		}

		public static string CreateShortQualifiedName(Type value)
		{
			if (value == null)
			{
				throw new ArgumentNullException("value");
			}
			return Assembly.CreateQualifiedName(GetAssemblyName(value), value.FullName);
		}

		public static void EnsureAssignableTo(Type source, Type assignableTo)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (assignableTo == null)
			{
				throw new ArgumentNullException("assignableTo");
			}
			if (!assignableTo.IsAssignableFrom(source))
			{
				throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "Type {0} is not assignable to type {1}.", new object[] { source, assignableTo }));
			}
		}

		public static string GetAssemblyConfiguration(Assembly targetAssembly)
		{
			if (targetAssembly == null)
			{
				throw new ArgumentNullException("targetAssembly");
			}
			object[] customAttributes = targetAssembly.GetCustomAttributes(typeof(AssemblyConfigurationAttribute), false);
			if (customAttributes.Length <= 0)
			{
				return string.Empty;
			}
			return ((AssemblyConfigurationAttribute)customAttributes[0]).Configuration;
		}

		public static string GetAssemblyFileVersion(Assembly targetAssembly)
		{
			if (targetAssembly == null)
			{
				throw new ArgumentNullException("targetAssembly");
			}
			object[] customAttributes = targetAssembly.GetCustomAttributes(typeof(AssemblyFileVersionAttribute), false);
			if (customAttributes.Length <= 0)
			{
				return string.Empty;
			}
			return ((AssemblyFileVersionAttribute)customAttributes[0]).Version;
		}

		public static string GetAssemblyFolder(Assembly targetAssembly)
		{
			if (targetAssembly == null)
			{
				throw new ArgumentNullException("targetAssembly");
			}
			string assemblyPath = GetAssemblyPath(targetAssembly);
			if (assemblyPath.IndexOf('\\') != -1)
			{
				assemblyPath = assemblyPath.Substring(0, assemblyPath.LastIndexOf('\\'));
			}
			return assemblyPath;
		}
		public static string GetAssemblyName(Assembly assembly)
		{
			if (assembly == null)
			{
				throw new ArgumentNullException("assembly");
			}
			return assembly.FullName.Substring(0, assembly.FullName.IndexOf(",")).Trim();
		}

		public static string GetAssemblyName(string qualifiedTypeName)
		{
			if (qualifiedTypeName == null)
			{
				throw new ArgumentNullException("qualifiedTypeName");
			}
			string[] textArray = qualifiedTypeName.Split(new char[] { ',' });
			if (textArray.Length < 2)
			{
				throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "Invalid qualified type name {0}.", new object[] { qualifiedTypeName }));
			}
			return textArray[1].Trim();
		}

		public static string GetAssemblyName(Type type)
		{
			if (type == null)
			{
				throw new ArgumentNullException("type");
			}
			return GetAssemblyName(type.Assembly);
		}

		public static string GetAssemblyPath(Assembly targetAssembly)
		{
			if (targetAssembly == null)
			{
				throw new ArgumentNullException("targetAssembly");
			}
			if ((targetAssembly.CodeBase == null) || (targetAssembly.CodeBase.Length == 0))
			{
				throw new ArgumentException("Argument can not have an empty value.", "targetAssembly.CodeBase");
			}
			Uri uri = new CompatibleUri(targetAssembly.CodeBase);
			return uri.LocalPath;
		}

		public static string GetAssemblyProduct(Assembly targetAssembly)
		{
			if (targetAssembly == null)
			{
				throw new ArgumentNullException("targetAssembly");
			}
			object[] customAttributes = targetAssembly.GetCustomAttributes(typeof(AssemblyProductAttribute), false);
			if (customAttributes.Length <= 0)
			{
				return string.Empty;
			}
			return ((AssemblyProductAttribute)customAttributes[0]).Product;
		}

		public static string GetAssemblyString(string qualifiedTypeName)
		{
			if (qualifiedTypeName == null)
			{
				throw new ArgumentNullException("qualifiedTypeName");
			}
			if (qualifiedTypeName.IndexOf(',') == -1)
			{
				throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "Invalid qualified type name {0}.", new object[] { qualifiedTypeName }));
			}
			return qualifiedTypeName.Substring(qualifiedTypeName.IndexOf(',') + 1).Trim();
		}

		public static string GetAssemblyTitle(Assembly targetAssembly)
		{
			if (targetAssembly == null)
			{
				throw new ArgumentNullException("targetAssembly");
			}
			object[] customAttributes = targetAssembly.GetCustomAttributes(typeof(AssemblyTitleAttribute), false);
			if (customAttributes.Length <= 0)
			{
				return string.Empty;
			}
			return ((AssemblyTitleAttribute)customAttributes[0]).Title;
		}

		public static string GetSimpleTypeName(object target)
		{
			if (target == null)
			{
				throw new ArgumentNullException("target");
			}
			return GetSimpleTypeName(target.GetType());
		}

		public static string GetSimpleTypeName(Type type)
		{
			if (type == null)
			{
				throw new ArgumentNullException("type");
			}
			return (type.FullName + ", " + GetAssemblyName(type));
		}

		private static byte[] HexToBytes(string hex)
		{
			byte[] buffer = new byte[hex.Length / 2];
			int startIndex = 0;
			for (int i = 0; i < buffer.Length; i++)
			{
				buffer[i] = Convert.ToByte(hex.Substring(startIndex, 2), 0x10);
				startIndex += 2;
			}
			return buffer;
		}

		public static bool IsAssignableTo(Type targetType, object value)
		{
			bool flag = false;
			if (value.GetType().IsCOMObject)
			{
				if (targetType.IsInterface)
				{
					IntPtr pUnk = Marshal.GetIUnknownForObject(value);
					Guid iid = targetType.GUID;
					IntPtr ppv = IntPtr.Zero;
					Marshal.QueryInterface(pUnk, ref iid, out ppv);
					flag = ppv == IntPtr.Zero;
					if (!flag)
					{
						Marshal.Release(ppv);
					}
					if (pUnk != IntPtr.Zero)
					{
						Marshal.Release(pUnk);
					}
				}
				else
				{
					flag = true;
				}
			}
			else if ((value.GetType() != targetType) && !targetType.IsAssignableFrom(value.GetType()))
			{
				flag = true;
			}
			return !flag;
		}

		public static Type LoadType(string className)
		{
			if (className == null)
			{
				throw new ArgumentNullException("className");
			}
			return LoadType(className, false);
		}

		public static Type LoadType(string className, bool callingAssembly)
		{
			if (className == null)
			{
				throw new ArgumentNullException("className");
			}
			Type type = null;
			if ((className == null) || (className.Length <= 0))
			{
				return type;
			}
			if (callingAssembly)
			{
				type = Assembly.GetCallingAssembly().GetType(className.Trim(), false, true);
			}
			else
			{
				type = Type.GetType(className.Trim(), false, true);
			}
			if (type != null)
			{
				return type;
			}
			string[] textArray = className.Split(new char[] { ',' });
			Assembly assembly = Assembly.LoadWithPartialName(GetAssemblyName(className));
			if (assembly == null)
			{
				throw new TypeLoadException(string.Format(CultureInfo.CurrentCulture, "Couldn't load assembly {0}. Verify if the type {1} syntax is correct.", new object[] { textArray[1], className }));
			}
			return assembly.GetType(textArray[0].Trim(), true, true);
		}

		public static AssemblyName ParseAssemblyName(string assemblyName)
		{
			if (assemblyName == null)
			{
				throw new ArgumentNullException("assemblyName");
			}
			if (!AssemblyNameRegEx.IsMatch(assemblyName))
			{
				throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "Invalid assembly name {0}.", new object[] { assemblyName }));
			}
			Match match = AssemblyNameRegEx.Match(assemblyName);
			AssemblyName name = new AssemblyName();
			name.Name = match.Groups["assembly"].Value;
			if (match.Groups["version"].Success)
			{
				name.Version = new Version(match.Groups["version"].Value);
			}
			if (match.Groups["culture"].Success)
			{
				if (match.Groups["culture"].Value != "neutral")
				{
					name.CultureInfo = new CultureInfo(match.Groups["culture"].Value);
				}
				else
				{
					name.CultureInfo = CultureInfo.InvariantCulture;
				}
			}
			if (match.Groups["token"].Success)
			{
				if (match.Groups["token"].Value != "null")
				{
					name.SetPublicKeyToken(HexToBytes(match.Groups["token"].Value));
					return name;
				}
				name.SetPublicKeyToken(null);
			}
			return name;
		}
	}
}
