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

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

//**************************************************************************************************
partial class HException {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

public static string GetMessage(Exception e)
{
   HArgChecking.VerifyNotNull( e );
   return !string.IsNullOrWhiteSpace( e.Message ) ?
      e.Message : e.GetType().ToString();
}

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

public static string GetSignificantMessage(Exception e)
{
   return GetMessage( BypassPackingExceptions( e ) );
}
public static string GetSignificantMessage(Exception e,params Type[] packingExceptionTypes)
{
   return GetMessage( BypassPackingExceptions( e, packingExceptionTypes ) );
}

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

public static string GetErrorMessage(Exception e)
{
   HArgChecking.VerifyNotNull( e );
   return GetErrorMessage( e, GetPackingExceptionTypes() );
}
public static string GetErrorMessage(Exception e,params Type[] packingExceptionTypes)
{
   HArgChecking.VerifyNotNull( e );
   VerifyExceptionArgTypes( packingExceptionTypes );

   var list = new List<Exception>();

   for (Exception x=e; x!=null; x=x.InnerException)
      if ( !HType.IsValueOneOf( x, packingExceptionTypes ) )
         list.Add( x );

   if ( list.Count == 0 )
      return GetMessage( e );

   var sb = new StringBuilder();
   for (int i=0; i<list.Count; i++)
   {
      if ( i > 0 )
         sb.AppendLine();
      if ( list.Count > 1 )
         sb.Append( $"{HUnicode.Bullet} " );
      sb.Append( GetMessage( list[i] ) );
   }
   return sb.ToString();
}

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

public static string ComposeMessage(Exception e)
{
   return ComposeMessage(e,false);
}
public static string ComposeMessage(Exception e,bool withStackTrace)
{
   string baseMessage = !string.IsNullOrWhiteSpace( e.Message ) ?
      string.Format( "{0}: {1}", e.GetType(), e.Message ) :
      e.GetType().ToString();
   if ( !withStackTrace )
      return baseMessage;
   return baseMessage + (e.StackTrace!=null ? Environment.NewLine+e.StackTrace : "");
}

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

public static string ComposeChainedMessage(Exception e)
{
   return ComposeChainedMessage(e,false);
}
public static string ComposeChainedMessage(Exception e,bool withStackTrace)
{
   return ComposeChainedMessage(e,withStackTrace,false);
}
public static string ComposeChainedMessage(Exception e,bool withStackTrace,bool separateItems)
{
   var sb = new StringBuilder();
   for (Exception x=e; x!=null; x=x.InnerException)
   {
      if ( x != e )
      {
         sb.AppendLine();
         if ( separateItems )
            sb.AppendLine();
      }
      if ( e.InnerException != null )
         sb.Append( $"{HUnicode.Bullet} " );
      sb.Append( ComposeMessage( x, withStackTrace ) );
   }
   return sb.ToString();
}

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

static string NormalizeMessageText(string message)
{
   return message != null ?
      HString.ConvertAsText( message ) :
      null;
}

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

public static bool IsPackingException(Exception e)
{
   HArgChecking.VerifyNotNull( e );
   lock (_StaticSyncRoot_)
      return _PackingRegistration_.ContainsKey( e.GetType() );
}

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

public static Exception BypassPackingExceptions(Exception e)
{
   HArgChecking.VerifyNotNull( e );
   lock (_StaticSyncRoot_)
      for (Exception x=e; x!=null; x=x.InnerException)
         if ( !IsPackingException( x ) )
            return x;
   return e;
}
public static Exception BypassPackingExceptions(Exception e,params Type[] packingExceptionTypes)
{
   HArgChecking.VerifyNotNulls( e, packingExceptionTypes );
   VerifyExceptionArgTypes( packingExceptionTypes );
   for (Exception x=e; x!=null; x=x.InnerException)
      if ( !HType.IsValueOneOf( e, packingExceptionTypes ) )
         return x;
   return e;
}

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

public static Type[] GetPackingExceptionTypes()
{
   lock (_StaticSyncRoot_)
   {
      ICollection keys = _PackingRegistration_.Keys;
      var array = new Type[ keys.Count ];
      keys.CopyTo( array, 0 );
      return array;
   }
}

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

public static void RegisterPackingException(Type exceptionType)
{
   VerifyExceptionArgType( exceptionType );
   lock (_StaticSyncRoot_)
      _PackingRegistration_[ exceptionType ] = null;
}

public static void UnregisterPackingException(Type exceptionType)
{
   VerifyExceptionArgType( exceptionType );
   lock (_StaticSyncRoot_)
      _PackingRegistration_.Remove( exceptionType );
}

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

public static void RegisterPackingExceptions(params Type[] exceptionTypes)
{
   VerifyExceptionArgTypes( exceptionTypes );
   lock (_StaticSyncRoot_)
      foreach (var type in exceptionTypes)
         RegisterPackingException( type );
}

public static void UnregisterPackingExceptions(params Type[] exceptionTypes)
{
   VerifyExceptionArgTypes( exceptionTypes );
   lock (_StaticSyncRoot_)
      foreach (var type in exceptionTypes)
         UnregisterPackingException( type );
}

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

static void VerifyExceptionArgType(Type exceptionType)
{
   HArgChecking.VerifyNotNull( exceptionType );
   HArgChecking.VerifyTypeOf<Exception>( exceptionType );
}

static void VerifyExceptionArgTypes(Type[] exceptionTypes)
{
   HArgChecking.VerifyNotNull( exceptionTypes );
   foreach (var type in exceptionTypes)
      VerifyExceptionArgType( type );
}

//==================================================================================================
/*
public static bool IsThroughException(Exception e)
{
   HArgChecking.VerifyNotNull( e );
return e is HIThroughExceptionMarker;
   var x = e as HException;
   return x != null && x.IsThroughTypeException;
}

/// <exception cref="HException" />
public static void FWD(Exception e)
{
   if (!( IsThroughException( e ) ))
      return;
   Exception newException;
   Type exceptionType = e.GetType();
   try {
      newException = (Exception)HType.CreateInstance( exceptionType,
         string.Format( ThroughExceptionRethrownMessageFmt, exceptionType ),
         e ); }
   catch { throw e; }
   throw newException;
}
*/
//==================================================================================================

static HException()
{
   CommonHelpers_Core.Access();

   RegisterPackingExceptions(
      typeof( TargetInvocationException ),
      typeof( TypeInitializationException ),
      typeof( AggregateException ) );
}

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

static readonly Dictionary<Type,object>
   _PackingRegistration_ = new Dictionary<Type,object>();
static readonly object
   _StaticSyncRoot_ = new object();

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // HException
//**************************************************************************************************

} // CommonHelpers (.WASM)
