//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
// CommonHelpers satellite library | Author: Sergei Y.Kitáev
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
using System;
using System.IO;
using System.Reflection;
using System.ComponentModel;
#if LEGACY
using System.Security.Permissions;
#endif // LEGACY

namespace CommonHelpers {

//**************************************************************************************************
[HFullFunctionalModeRequired]
public static class HNativeLib {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

public static bool IsInitialized => _IsInitialized_;

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

/// <exception cref="InvalidOperationException" />
/// <exception cref="Win32Exception" />
#if LEGACY
[PermissionSet(SecurityAction.Demand,Unrestricted=true)]
#endif // LEGACY
public static void Initialize()
{
   lock ( SyncRoot )
      DoInitialize();
}

/// <exception cref="InvalidOperationException" />
public static void VerifyInitialized()
{
   if ( !IsInitialized )
      throw new InvalidOperationException(HLocal.TEXT(
         "Library \"NativeLib\" has not been initialized.",
         "Библиотека \"NativeLib\" не была проинициализирована." ));
}

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

static void DoInitialize()
{
   if ( IsInitialized )
      return;
   CommonHelpersLibrary.VerifyEnvironmentForFFM();
   string
      dllName = "NativeLib.dll",
      dllFolder = Path.GetDirectoryName(
         Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName ),
      dllFilePath = Path.Combine( dllFolder, dllName );
   if ( Win32_Sys.LoadLibrary( dllFilePath ) == IntPtr.Zero )
      try
      {
         throw new Win32Exception();
      }
      catch (Win32Exception e)
      {
         throw new Win32Exception( e.NativeErrorCode, string.Format(
            "{0}: \"{1}\"."+Environment.NewLine+
            "{2}: {3}",
            HLocal.TEXT( "Can not load module",
                         "Не удаётся загрузить модуль" ),
            dllFilePath,
            HLocal.TEXT( "Win32-error",
                         "Ошибка Win32" ),
            HWin32Error.NormalizeErrorMessage( e.Message ) ));
      }
   var initializationFlags = CommonHelpersLibrary.InitializationFlags;
   bool hasFlags = initializationFlags.HasValue;
   var flags = hasFlags ? initializationFlags.Value : 0;
   var ini = new HNLibInitStruct()
   {
      AllowDesktopInteraction =
         HNLibInit.AllowDesktopInteraction ??
            (flags & CommonHelpersInitFlags.InteractsWithDesktop) != 0 ?
            true : HProgram.InteractsWithDesktopSpecification != false,
      SuccessfulExitCode =
         HNLibInit.SuccessfulExitCode ??
         HProgram.SuccessfulExitCode,
      FailureExitCode =
         HNLibInit.FailureExitCode ??
         HProgram.FailureExitCode,
      BreakdownExitCode =
         HNLibInit.BreakdownExitCode ??
         HProgram.BreakdownExitCode
   };
   IntPtr errorMessagePtr;
   if ( !NativeLib_0.Initialize( "A8479F04-8A0E-412B-BD74-D9D6D3A1AEF1",
      HNLibInit.MainModuleName ?? Assembly.GetEntryAssembly().GetModules()[0].Name,
      ref ini, out errorMessagePtr ))
      throw new HOperationFailedException(
         errorMessagePtr != IntPtr.Zero ?
         HNLibAccess.STR_0( ref errorMessagePtr ) : HLocal.TEXT(
         "Initialization of \"NativeLib.dll\" has failed.",
         "Инициализация \"NativeLib.dll\" потерпела неудачу." ));
   _IsInitialized_ = true;
}

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

static HNativeLib()
{
   CommonHelpers_Sys.Access();
}

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

static volatile bool _IsInitialized_;

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

static readonly object SyncRoot = new object();

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // HNativeLib
//**************************************************************************************************

} // CommonHelpers
