using System;
using System.Globalization;
using System.Reflection;
using System.Runtime.InteropServices.WindowsRuntime;

namespace System.Reactive
{
	internal static class ReflectionUtils
	{
		public static T CreateDelegate<T>(object o, MethodInfo method)
		{
			return (T)((object)Delegate.CreateDelegate(typeof(T), o, method));
		}

		public static Delegate CreateDelegate(Type delegateType, object o, MethodInfo method)
		{
			return Delegate.CreateDelegate(delegateType, o, method);
		}

		public static void GetEventMethods<TSender, T>(Type targetType, object target, string eventName, out MethodInfo addMethod, out MethodInfo removeMethod, out Type delegateType, out bool isWinRT)
		{
			EventInfo eventInfo;
			if (target == null)
			{
				eventInfo = targetType.GetEventEx(eventName, true);
				if (eventInfo == null)
				{
					throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings_Linq.COULD_NOT_FIND_STATIC_EVENT, eventName, targetType.FullName));
				}
			}
			else
			{
				eventInfo = targetType.GetEventEx(eventName, false);
				if (eventInfo == null)
				{
					throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings_Linq.COULD_NOT_FIND_INSTANCE_EVENT, eventName, targetType.FullName));
				}
			}
			addMethod = eventInfo.GetAddMethod();
			removeMethod = eventInfo.GetRemoveMethod();
			if (addMethod == null)
			{
				throw new InvalidOperationException(Strings_Linq.EVENT_MISSING_ADD_METHOD);
			}
			if (removeMethod == null)
			{
				throw new InvalidOperationException(Strings_Linq.EVENT_MISSING_REMOVE_METHOD);
			}
			ParameterInfo[] parameters = addMethod.GetParameters();
			if (parameters.Length != 1)
			{
				throw new InvalidOperationException(Strings_Linq.EVENT_ADD_METHOD_SHOULD_TAKE_ONE_PARAMETER);
			}
			ParameterInfo[] parameters2 = removeMethod.GetParameters();
			if (parameters2.Length != 1)
			{
				throw new InvalidOperationException(Strings_Linq.EVENT_REMOVE_METHOD_SHOULD_TAKE_ONE_PARAMETER);
			}
			isWinRT = false;
			if (addMethod.ReturnType == typeof(EventRegistrationToken))
			{
				isWinRT = true;
				if (parameters2[0].ParameterType != typeof(EventRegistrationToken))
				{
					throw new InvalidOperationException(Strings_Linq.EVENT_WINRT_REMOVE_METHOD_SHOULD_TAKE_ERT);
				}
			}
			delegateType = parameters[0].ParameterType;
			MethodInfo method = delegateType.GetMethod("Invoke");
			ParameterInfo[] parameters3 = method.GetParameters();
			if (parameters3.Length != 2)
			{
				throw new InvalidOperationException(Strings_Linq.EVENT_PATTERN_REQUIRES_TWO_PARAMETERS);
			}
			if (!typeof(TSender).IsAssignableFrom(parameters3[0].ParameterType))
			{
				throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings_Linq.EVENT_SENDER_NOT_ASSIGNABLE, typeof(TSender).FullName));
			}
			if (!typeof(T).IsAssignableFrom(parameters3[1].ParameterType))
			{
				throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings_Linq.EVENT_ARGS_NOT_ASSIGNABLE, typeof(T).FullName));
			}
			if (method.ReturnType != typeof(void))
			{
				throw new InvalidOperationException(Strings_Linq.EVENT_MUST_RETURN_VOID);
			}
		}

		public static EventInfo GetEventEx(this Type type, string name, bool isStatic)
		{
			return type.GetEvent(name, isStatic ? (BindingFlags.Static | BindingFlags.Public) : (BindingFlags.Instance | BindingFlags.Public));
		}
	}
}
