//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
// 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 HType {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

public static bool IsTypeOf<TComparand>(Type type)
{
   return IsTypeOf( type, typeof(TComparand) );
}

public static bool IsTypeOf(Type type,Type comparandType)
{
   HArgChecking.VerifyNotNulls( type, comparandType );
   return type==comparandType || type.IsSubclassOf(comparandType);
}

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

public static bool IsValueOf(object value,Type comparandType)
{
   HArgChecking.VerifyNotNull( comparandType );
   return value!=null ?
      IsTypeOf(value.GetType(),comparandType) :
      false;
}

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

/// <exception cref="ArgumentException" />
public static bool ImplementsInterface(Type type,Type interfaceType)
{
   HArgChecking.VerifyNotNulls( type, interfaceType );
   if ( type.IsInterface || !interfaceType.IsInterface )
      throw new ArgumentException();
   return interfaceType.IsAssignableFrom( type );
}

/// <exception cref="ArgumentException" />
public static bool ImplementsInterface<I>(Type type)
{
   return ImplementsInterface( type, typeof(I) );
}

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

public static bool IsOneOf(Type type,params Type[] comparandTypes)
{
   HArgChecking.VerifyNotNull( type );
   HArgChecking.VerifyNotNulls( comparandTypes );
   return !HOps.ForEach( comparandTypes, delegate (Type ct) {
      return !HType.IsTypeOf( type, ct ); });
}

public static bool IsOneOf<T>(params Type[] comparandTypes)
{
   return IsOneOf( typeof(T), comparandTypes );
}

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

public static bool IsValueOneOf(object value,params Type[] comparandTypes)
{
   HArgChecking.VerifyNotNull( value );
   HArgChecking.VerifyNotNulls( comparandTypes );
   return !HOps.ForEach( comparandTypes, delegate (Type ct) {
      return !HType.IsValueOf( value, ct ); });
}

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

public static object CreateInstance(Type type)
{
   return CreateInstance(type,null);
}

public static object CreateInstance(Type type,[HOptional] params object[] parameters)
{
   return CreateInstanceUsingVisibilityFlags(type,BindingFlags.Public,parameters);
}

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

public static T CreateInstance<T>()
{
   return (T)CreateInstance(typeof(T));
}

public static T CreateInstance<T>([HOptional] params object[] parameters)
{
   return (T)CreateInstance(typeof(T),parameters);
}

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

public static object CreateInstanceUsingVisibilityFlags(Type type,BindingFlags visibilityFlags)
{
   return CreateInstanceUsingVisibilityFlags(type,visibilityFlags,null);
}

public static object CreateInstanceUsingVisibilityFlags( Type type,
                                                         BindingFlags visibilityFlags,
                                                         [HOptional] params object[] parameters )
{
   return type.InvokeMember( null,
      visibilityFlags | BindingFlags.Instance | BindingFlags.CreateInstance,
      null, null, parameters ?? new object[0] );
}

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

public static T CreateInstanceUsingVisibilityFlags<T>(BindingFlags visibilityFlags)
{
   return (T)CreateInstanceUsingVisibilityFlags(typeof(T),visibilityFlags);
}

public static T CreateInstanceUsingVisibilityFlags<T>( BindingFlags visibilityFlags,
                                                       [HOptional] params object[] parameters )
{
   return (T)CreateInstanceUsingVisibilityFlags(typeof(T),visibilityFlags,parameters);
}

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

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

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

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

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

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

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

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

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // HType
//**************************************************************************************************

} // CommonHelpers (.WASM)
