//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
// CommonHelpers satellite library | Author: Sergei Y.Kitáev
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#define TRACE

using System;
using System.IO;
using System.Threading;
using System.Diagnostics;
using System.Runtime.CompilerServices;

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

//**************************************************************************************************
partial class HFatalError {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

static string FatalErrorCaption =>
   string.Format( FatalErrorCaptionFmt, _AppSimpleName_ );

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

static bool IsInRaiseThread =>
   Thread.CurrentThread == _RaiseThread_;

static bool IsMainRaiseThread =>
   HProgram.IsMainThreadSpecified ? HProgram.IsMainThread(_RaiseThread_) : false;

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

static DateTime ErrorTime
{
   get
   {
      lock (_ErrorTimeAccessSyncObject_)
         return _ErrorTime_;
   }
}

static bool IsWASM => _IsWASM_ > 0;

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

static void ObtainApplicationName()
{
   if ( !IsWASM )
      try
      {
         _AppSimpleName_ = HProgram.SimpleName;
         _MainModuleName_ = HProgram.MainModuleName;
      }
      catch {}
   if ( _AppSimpleName_==null || _MainModuleName_==null )
   {
      string nameFromAppDomain = "("+(AppDomain.CurrentDomain.FriendlyName ?? "???")+")";
      if ( _AppSimpleName_ == null )
         _AppSimpleName_ = nameFromAppDomain;
      if ( _MainModuleName_ == null )
         _MainModuleName_ = nameFromAppDomain;
   }
}

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

static void OutputTraceMessage(string message)
{
   System.Diagnostics.Trace.IndentLevel = 0;
   System.Diagnostics.Trace.WriteLine( Environment.NewLine + message );
   System.Diagnostics.Trace.Flush();
}

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

static void Trace(string message)
{
   OutputTraceMessage(HString.FormatAsText(
      "=== Breakdown of fatal error performing in \"{0}\": ===\n"+
      "{1}\n"+
      "=== End of message (breakdown). ===",
      _MainModuleName_, message ));
}

static void Trace(Exception e)
{
   Trace(e.ToString());
}

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

[MethodImpl(MethodImplOptions.NoInlining)]
static void FailFast(string message)
{
   HOps.SubstituteIfNull( ref message, "Fatal error breakdown." );
   try {
      Win32_Core.TerminateProcess( Win32_Core.GetCurrentProcess(),
         unchecked( (uint)HProgram.BreakdownExitCode ) ); }
   finally {
      Environment.FailFast( Environment.NewLine + message ); }
}

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

[MethodImpl(MethodImplOptions.NoInlining)]
static void TrySetWaitCursor()
{
   try {
      IntPtr cursorHandle =
         Win32_Core.LoadCursor( IntPtr.Zero, Win32_Core.IDC_WAIT );
      if ( cursorHandle != IntPtr.Zero )
         Win32_Core.SetCursor( cursorHandle );
   } catch {}
}

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

[MethodImpl(MethodImplOptions.NoInlining)]
static void TryBeep()
{
#if WIN32
   try { Console.Beep(880,300); } catch {}
#endif // WIN32
}

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

static bool ShowErrorBox(string errorText,string caption)
{
   return ShowErrorBox( errorText, caption, false );
}

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

[MethodImpl(MethodImplOptions.NoInlining)]
static bool ShowErrorBox(string errorText,string caption,bool yesNoMode)
{
   return Win32_Core.MessageBox( IntPtr.Zero,
      errorText, caption,
      Win32_Core.MB_ICONERROR | Win32_Core.MB_SYSTEMMODAL |
      (yesNoMode ? Win32_Core.MB_YESNO : Win32_Core.MB_OK) ) == Win32_Core.IDYES;
}

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

[MethodImpl(MethodImplOptions.NoInlining)]
static void TryReportToConsole(string cause,string message)
{
   try
   {
      if (Win32_Core.GetStdHandle( Win32_Core.STD_OUTPUT_HANDLE )==Win32_Core.INVALID_HANDLE_VALUE)
         return;
      Console.ResetColor();
      Console.ForegroundColor = ConsoleColor.Red;
      Console.WriteLine
      (
         "\n"+
         "## === Fatal error in <{0}>: ===\n"+
         "{1}"+
         "## {2}\n"+
         "## === The process is terminated! ===",
         _MainModuleName_,
         cause!=null ?
            HString.FormatAsText("## << {0} >>\n",cause) :
            "",
         HString.ConvertAsText(message.Replace(HUnicode.Bullet,'*')).Replace("\r\n","\r\n## ")
      );
      Console.ResetColor();
   }
   catch
   {}
}

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

[MethodImpl(MethodImplOptions.NoInlining)]
static void DetachUnhandledExceptionHandler()
{
   AppDomain.CurrentDomain.UnhandledException -= AppDomainUnhandledException_Handler;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // HFatalError
//**************************************************************************************************

} // CommonHelpers (.WASM)
