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

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

//**************************************************************************************************
public static partial class CommonHelpersLibrary {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#if WIN32
public static OperatingSystem GetMinimalSupportedOS()
{
   return new OperatingSystem( PlatformID.Win32NT, new Version(5,1) ); // WindowsXP
}

public static OperatingSystem GetMinimalSupportedOSforFFM()
{
   return new OperatingSystem( PlatformID.Win32NT, new Version(5,1) ); // WindowsXP
}
#endif // WIN32
//--------------------------------------------------------------------------------------------------

public static bool IsInFullFunctionalMode
{
   get { return HOps.Try(delegate{ FFM.Access(); }); }
}

public static bool IsWASM =>
   HEnvironment.IsWASMSpecification == true;

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

/// <exception cref="InvalidOperationException" />
public static void VerifyInFullFunctionalMode()
{
   try
   {
      FFM.Access();
   }
   catch (Exception e)
   {
      const string message = "Operation requires full-functional CommonHelpers mode.";
      for (Exception x=e; x!=null; x=x.InnerException)
         if (!(
            x is TypeInitializationException ||
            x is TargetInvocationException
         ))
            throw new InvalidOperationException( message, x );
      throw new InvalidOperationException( message, e );
   }
}

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

/// <exception cref="InvalidOperationException" />
/// <exception cref="HInvalidEnvironmentException" />
public static void VerifyEnvironmentForFFM()
{
   if ( !HCompilationCH.IsWin32 )
      throw new InvalidOperationException(
         "Win32 compilation is required for full-functional mode (CommonHelpers)." );
#if WIN32
   var minimalOS = GetMinimalSupportedOSforFFM();
   if ( !HOperatingSystem.CheckOperatingSystem( minimalOS ) )
      throw HInvEnvironmentExceptionCreator.Create(
         "CommonHelpers Library requires \"{0}\" minimal OS for full-functional mode.",
         HOperatingSystem.GetNameOrVersionString( minimalOS ) );
#endif // WIN32
}

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

/// <exception cref="Exception" />
/// <exception cref="TypeLoadException" />
/// <exception cref="FileNotFoundException" />
public static void AccessFullFunctionalMode()
{
   try
   {
      FFM.Access();
   }
   catch (Exception e)
   {
      for (Exception x=e; x!=null; x=x.InnerException)
         if (!(
            x is TypeInitializationException ||
            x is TargetInvocationException
         ))
            throw x;
      throw;
   }
}

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

/// <exception cref="Exception" />
public static void Initialize()
{
   DoInitialize( null );
}

/// <exception cref="Exception" />
/// <exception cref="TypeLoadException" />
/// <exception cref="FileNotFoundException" />
[CLSCompliant(false)]
public static void Initialize([HOptional] CommonHelpersInitFlags initializationFlags)
{
   DoInitialize( initializationFlags );
}

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

static void DoInitialize(object initializationFlags)
{
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   CommonHelpersInitFlags flags = initializationFlags != null ?
      (CommonHelpersInitFlags)initializationFlags : 0;
   bool
      specifyMainThread       = ( flags & CommonHelpersInitFlags.SpecifyMainThread           ) != 0,
      isProcessOwner          = ( flags & CommonHelpersInitFlags.IsProcessOwner              ) != 0,
      interactsWithDesktop    = ( flags & CommonHelpersInitFlags.InteractsWithDesktop        ) != 0,
      fullFunctionalMode      = ( flags & CommonHelpersInitFlags.FullFunctionalMode          ) != 0,
      avoidFatalErrorOnUnhandledException =
         ( flags & CommonHelpersInitFlags.AvoidFatalErrorOnUnhandledException                ) != 0,
      avoidFatalErrorOnUnhandledExceptionUnderDebugger =
         ( flags & CommonHelpersInitFlags.AvoidFatalErrorOnUnhandledExceptionUnderDebugger   ) != 0,
      avoidFatalErrorOnAssertion =
         ( flags & CommonHelpersInitFlags.AvoidFatalErrorOnAssertion                         ) != 0,
      ignoreFatalErrorRelatedInit =
         ( flags & CommonHelpersInitFlags.IgnoreFatalErrorRelatedInit                        ) != 0,

      secondAssemblyUsage     = ( flags & CommonHelpersInitFlags.SecondAssemblyUsage         ) != 0,
      thirdAssemblyUsage      = ( flags & CommonHelpersInitFlags.ThirdAssemblyUsage          ) != 0,
      systemAssemblyUsage     = ( flags & CommonHelpersInitFlags.SystemAssemblyUsage         ) != 0,

      userWinAssemblyUsage    = ( flags & CommonHelpersInitFlags.UserWinAssemblyUsage        ) != 0,
      wfxAssemblyUsage        = ( flags & CommonHelpersInitFlags.WFXAssemblyUsage            ) != 0,

      stdAppConWrapperUsage   = ( flags & CommonHelpersInitFlags.StdAppConWrapperUsage       ) != 0,
      soundClassUsage         = ( flags & CommonHelpersInitFlags.SoundClassUsage             ) != 0,
      beeperClassUsage        = ( flags & CommonHelpersInitFlags.BeeperClassUsage            ) != 0;
#if !WIN32 && !WASM
   bool isWASM = ( flags &  CommonHelpersInitFlags.IsWASM ) != 0;
#endif // !WIN32 && !WASM

   if ( stdAppConWrapperUsage && CommonHelpersAssemblyNo_Console==2 ||
        (soundClassUsage || beeperClassUsage) && CommonHelpersAssemblyNo_Plus==2 )
      secondAssemblyUsage = true;
   if ( stdAppConWrapperUsage && CommonHelpersAssemblyNo_Console==3 ||
        (soundClassUsage || beeperClassUsage) && CommonHelpersAssemblyNo_Plus==3 )
      thirdAssemblyUsage = true;
/*
   if ( userWinAssemblyUsage || wfxAssemblyUsage )
      fullFunctionalMode = true;
*/
   if ( fullFunctionalMode )
      systemAssemblyUsage = isProcessOwner = true;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   InitializationFlags = flags;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   try
   {
      CommonHelpers_Core.Access();
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      if ( specifyMainThread )
         HProgram.SpecifyMainThread();
      if ( isProcessOwner )
         HProgram.SpecifyIsProcessOwner();
      if ( interactsWithDesktop )
         HProgram.SpecifyInteractsWithDesktop();
#if !WIN32 && !WASM
      if ( isWASM )
         HEnvironment.SpecifyIsWASM();
#endif // !WIN32 && !WASM
      if ( !ignoreFatalErrorRelatedInit )
      {
         HFatalError.Flags =
            ( HFatalError.Flags |
               ( isProcessOwner ? HFatalErrorFlags.ProcessOwnerDefaults : 0 ) |
               ( avoidFatalErrorOnUnhandledExceptionUnderDebugger ?
                 HFatalErrorFlags.AvoidRaiseOnUnhandledExceptionUnderDebugger : 0 ) ) &
            ( avoidFatalErrorOnUnhandledException ?
              ~HFatalErrorFlags.RaiseOnUnhandledException : (HFatalErrorFlags)(-1) );
         HAssertion.UseExceptions =
            avoidFatalErrorOnAssertion ? (bool?)false : null;
      }

      if ( secondAssemblyUsage )
         GetOrLoadCommonHelpersAssembly_2();
      if ( thirdAssemblyUsage )
         GetOrLoadCommonHelpersAssembly_3();

      if ( fullFunctionalMode )
         FFM.Access();

      if ( userWinAssemblyUsage )
         GetOrLoadUserWinAssembly();
      if ( wfxAssemblyUsage )
         GetOrLoadWFXAssembly();

      if ( stdAppConWrapperUsage )
         HMethodInfo.InvokeStaticMethod( GetOrLoadAssembly_HConsole(),
            "CommonHelpers.HConsole", "InitializeStdAppConWrapper" );
      if ( soundClassUsage )
         HMethodInfo.InvokeStaticMethod( GetOrLoadAssembly_HSound(),
            "CommonHelpers.HSound", "Initialize" );
      if ( beeperClassUsage )
         HMethodInfo.InvokeStaticMethod( GetOrLoadAssembly_HBeeper(),
            "CommonHelpers.HBeeper", "Initialize" );
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   }
   catch (Exception e)
   {
      for (Exception x=e; x!=null; x=x.InnerException)
         if (!(
            x is TypeInitializationException ||
            x is TargetInvocationException
         ))
            throw x;
      throw;
   }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
}

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

static internal CommonHelpersInitFlags? InitializationFlags
{
   get { lock (SychRoot) return _InitializationFlags_; }
   private set { lock (SychRoot) _InitializationFlags_ = value; }
}

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

static readonly object SychRoot = new object();

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

static CommonHelpersInitFlags? _InitializationFlags_;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // CommonHelpersLibrary
//**************************************************************************************************

} // CommonHelpers (.WASM)
