//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
// UserRTX.NET satellite library | Author: Sergei Y.Kitáev
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
using System;
using System.IO;
using System.Threading;
using System.Reflection;
using System.Diagnostics;

#if !WASM
namespace user_rtx { using u = user_rtx;
#else
namespace user_rtx.wasm { using u = user_rtx.wasm;
#endif

/// <summary>
/// Program root info
/// </summary>
public static class program {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static readonly object SyncRoot = new object();
//==================================================================================================

[u.volatile_access]
public static string SimpleName =>
   SimpleNameN ?? "???";

[u.volatile_access]
public static string? SimpleNameN {
   get {
      var name = _simpleName;
      if ( name != null )
         return name;
      var moduleName = MainModuleNameN;
      return moduleName != null ?
         u.ops.Try(() => Path.GetFileNameWithoutExtension( moduleName )) :
         null;
   }}

[u.volatile_access]
public static string? ExplicitSimpleName {
   get => _simpleName;
   set => _simpleName = value; }

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

public static string MainModuleName =>
   MainModuleNameN ?? "???";

public static string? MainModuleNameN {
   get {
      var mainModuleName = _mainModuleName ?? _mainModuleNameAuto;
      if ( mainModuleName != null )
         return mainModuleName;
      lock ( SyncRoot ) {
         var processModuleName = u.process.ModuleNameN;
         if ( processModuleName != null )
            _mainModuleNameAuto = processModuleName;
         else {
            var entryAssembly = Assembly.GetEntryAssembly();
            _mainModuleNameAuto = entryAssembly?.ManifestModule.Name;
         }
         return _mainModuleNameAuto;
      }
   }}

[u.volatile_access]
public static string? ExplicitMainModuleName {
   get => _mainModuleName;
   set => _mainModuleName = value; }

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

/// <exception cref="InvalidOperationException" />
[u.strict_result][u.volatile_access]
public static Thread MainThread =>
   u.prop_check.Initialized( _mainThread, MethodBase.GetCurrentMethod() );

[u.volatile_access]
public static Thread? MainThreadValue =>
   _mainThread;
[u.volatile_access]
public static Thread SetMainThreadValue() =>
   SetMainThreadValue( Thread.CurrentThread );
[u.volatile_access]
public static Thread SetMainThreadValue( Thread value ) =>
   _mainThread = value;
[u.volatile_access]
public static void ClearMainThreadValue() =>
   _mainThread = null;

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

[u.thread_local]
public static bool IsInMainThread =>
   Thread.CurrentThread == _mainThread;

[u.thread_local]
public static bool IsInSecondaryThread {
   get {
      var mainThread = _mainThread;
      return mainThread != null &&
         Thread.CurrentThread != mainThread;
   }}

/// <exception cref="InvalidOperationException" />
[u.thread_local]
public static void VerifyInMainThread()
{
   if ( !IsInMainThread )
      throw new InvalidOperationException(
         "Main thread was expected to execute the code." );
}

/// <exception cref="InvalidOperationException" />
[u.thread_local]
public static void VerifyNotInMainThread()
{
   if ( IsInMainThread )
      throw new InvalidOperationException(
         "Main thread was not expected to execute the code." );
}

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

static volatile string?
   _simpleName, _mainModuleName, _mainModuleNameAuto;
[ThreadStatic]
static volatile Thread?
   _mainThread;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // program

} // user_rtx (.wasm)
