//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
// CommonHelpers satellite library | Author: Sergei Y.Kitáev
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
using System;
using System.Reflection;

#if !WASM
namespace CommonHelpers {
#else
namespace CommonHelpers.WASM {
#endif

//**************************************************************************************************
/// <summary>
/// </summary>
public static partial class HMethodInfo {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

public static string FullName(MethodBase method)
{
   HArgChecking.VerifyNotNull(method);
   return string.Format("{0}.{1}",method.DeclaringType,method.Name);
}

//==================================================================================================

public static Attribute GetAttribute(MethodBase method,Type attributeType)
{
   HArgChecking.VerifyNotNulls( method, attributeType );
   HArgChecking.VerifyTypeOf<Attribute>( attributeType );

   var attributes =
      (Attribute[])method.GetCustomAttributes( attributeType, false );

   switch (attributes.Length)
   {
   case 0: return null;
   case 1: return attributes[0];
   default:
      throw HOpFailedExceptionCreator.Create(
         "Multiple attribute of type \"{0}\" on method \"{1}\".",
         attributeType, FullName(method) );
   }
}

public static TAttribute GetAttribute<TAttribute>(MethodBase method)
   where TAttribute: Attribute
{
   return (TAttribute)GetAttribute( method, typeof(TAttribute) );
}

//--------------------------------------------------------------------------------------------------

public static bool IsMarkedWithAttribute(MethodBase method,Type attributeType)
{
   return GetAttribute(method,attributeType) != null;
}

//==================================================================================================

public static object InvokeStaticMethod(Type type,string methodName)
{
   return InvokeStaticMethod(type,methodName,null);
}

public static object InvokeStaticMethod( Type type,
                                         string methodName,
                                         [HOptional] params object[] parameters )
{
   return InvokeStaticMethodUsingVisibilityFlags(
      type, methodName, BindingFlags.Public, parameters );
}

//--------------------------------------------------------------------------------------------------

public static object InvokeInstanceMethod(object obj,string methodName)
{
   return InvokeInstanceMethod(obj,methodName,null);
}

public static object InvokeInstanceMethod( object obj,
                                           string methodName,
                                           [HOptional] params object[] parameters )
{
   return InvokeInstanceMethodUsingVisibilityFlags(
      obj, methodName, BindingFlags.Public, parameters );
}

//--------------------------------------------------------------------------------------------------

public static object InvokeStaticMethod(string typeName,string methodName)
{
   return InvokeStaticMethod(typeName,methodName,null);
}

public static object InvokeStaticMethod( string typeName,
                                         string methodName,
                                         [HOptional] params object[] parameters )
{
   return InvokeStaticMethodUsingVisibilityFlags(
      typeName, methodName, BindingFlags.Public, parameters );
}

//--------------------------------------------------------------------------------------------------

public static object InvokeStaticMethod(Assembly assembly,string typeName,string methodName)
{
   return InvokeStaticMethod(assembly,typeName,methodName,null);
}

public static object InvokeStaticMethod( Assembly assembly,
                                         string typeName,
                                         string methodName,
                                         [HOptional] params object[] parameters )
{
   return InvokeStaticMethodUsingVisibilityFlags(
      assembly, typeName, methodName,
      BindingFlags.Public,
      parameters );
}

//==================================================================================================

public static object InvokeStaticMethodUsingVisibilityFlags( Type type,
                                                             string methodName,
                                                             BindingFlags visibilityFlags )
{
   return InvokeStaticMethodUsingVisibilityFlags(type,methodName,visibilityFlags,null);
}

public static object InvokeInstanceMethodUsingVisibilityFlags( object obj,
                                                               string methodName,
                                                               BindingFlags visibilityFlags )
{
   return InvokeInstanceMethodUsingVisibilityFlags(obj,methodName,visibilityFlags,null);
}

//--------------------------------------------------------------------------------------------------

public static object InvokeStaticMethodUsingVisibilityFlags( Type type,
                                                             string methodName,
                                                             BindingFlags visibilityFlags,
                                                             [HOptional] params object[]
                                                             parameters )
{
   return type.InvokeMember( methodName,
      visibilityFlags | BindingFlags.Static | BindingFlags.InvokeMethod,
      null, null, parameters ?? new object[0] );
}

public static object InvokeInstanceMethodUsingVisibilityFlags
(
   object obj,
   string methodName,
   BindingFlags visibilityFlags,
   [HOptional] params object[] parameters
)
{
   return obj.GetType().InvokeMember( methodName,
      visibilityFlags | BindingFlags.Instance | BindingFlags.InvokeMethod,
      null, obj, parameters ?? new object[0] );
}

//--------------------------------------------------------------------------------------------------

public static object InvokeStaticMethodUsingVisibilityFlags( string typeName,
                                                             string methodName,
                                                             BindingFlags visibilityFlags )
{
   return InvokeStaticMethodUsingVisibilityFlags(
      typeName, methodName, visibilityFlags, null );
}

public static object InvokeStaticMethodUsingVisibilityFlags( string typeName,
                                                             string methodName,
                                                             BindingFlags visibilityFlags,
                                                             [HOptional] params object[]
                                                             parameters )
{
   return InvokeStaticMethodUsingVisibilityFlags(
      Type.GetType(typeName,true),
      methodName, visibilityFlags,
      parameters );
}

//--------------------------------------------------------------------------------------------------

public static object InvokeStaticMethodUsingVisibilityFlags( Assembly assembly,
                                                             string typeName,
                                                             string methodName,
                                                             BindingFlags visibilityFlags )
{
   return InvokeStaticMethodUsingVisibilityFlags(
      assembly, typeName, methodName, visibilityFlags, null );
}

public static object InvokeStaticMethodUsingVisibilityFlags( Assembly assembly,
                                                             string typeName,
                                                             string methodName,
                                                             BindingFlags visibilityFlags,
                                                             [HOptional] params object[]
                                                             parameters )
{
   return InvokeStaticMethodUsingVisibilityFlags(
      assembly.GetType(typeName,true),
      methodName, visibilityFlags,
      parameters );
}

//==================================================================================================

static HMethodInfo()
{
   CommonHelpers_Core.Access();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // HMethodInfo
//**************************************************************************************************

} // CommonHelpers (.WASM)
