// RuntimeForStatic base library | C+- (SysRoutine) | Author: Sergei Y.Kitáev
#include "Precompiled.h"
#include "SharedIncludes.h"
namespace RuntimeForStatic {
//==================================================================================================

void $FatalError::Raise($CI_REF,PCWSTR message) $not_returns
{
   ::SetThreadPriority( ::GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL );
   if ( !message )
      message = $TEXT(
         L"Fatal error message was not provided by the initiator.",
         L"Сообщение фатальной ошибки не было предоставлено инициатором." );
   DWORD
      currentThreadId = ::GetCurrentThreadId(),
      raiseCallerThreadId = $Interlocked::CompareExchange($,
         &_RaiseCallerThreadId_, currentThreadId, 0 );
   if ( raiseCallerThreadId && currentThreadId != raiseCallerThreadId )
      $Thread::Hang();
   static int entrance_count;
   if ( ++entrance_count > 2 )
   {
      ::OutputDebugString( $TEXT(
         L"Blocking of “$FatalError::Raise” due to looping.",
         L"Блокирование “$FatalError::Raise” в связи с зацикливанием." ));
      $Thread::Hang();
   }
   if ( entrance_count == 1 && UseDesktopInteraction() )
      ::SetCursor( (HCURSOR)IDC_WAIT );
   if ( entrance_count == 2 )
   {
      PCWSTR repeatedCallMessage = $TEXT(
         L"Repeated call of fatal error initiation function.",
         L"Повторный вызов функции инициации фатальной ошибки." );
      message = $_(
         (PCWSTR)HelpersRT::FormatAlloc($, L"%s\r\n%s", repeatedCallMessage, message ),
         repeatedCallMessage );
   }
   TerminationParams tp = {};
   tp.Message = message;
   tp.CallerInfoPtr = &$ci;
   tp.SourceThreadId = currentThreadId;
   tp.UseTerminationThread = $RT::IsInitialized() && !$RT::GetNativeThreadStartForbiddenVCRT();
   ReportError( ReportOutputs::Trace, tp );
   auto raiseTrigger = GetRaiseTrigger();
   if ( raiseTrigger )
   {
      HelpersRT::TraceOperation($$, $TEXT(
         L"Calling fatal error raise trigger",
         L"Вызов триггера фатальной ошибки" ));
      try
      {
         raiseTrigger();
      }
      catch (const std::exception& e)
      {
         TraceExceptionMessage( $TEXT(
            L"Exception in fatal error raise trigger",
            L"Исключение в триггере вызова фатальной ошибки" ),
            e );
      }
   }
   ::MemoryBarrier();
   if ( tp.UseTerminationThread )
   {
      auto hThread = (HANDLE)_beginthreadex( nullptr, 0, TerminationRoutine, &tp,
                                             CREATE_SUSPENDED, nullptr );
      if ( hThread )
      {
         ::SetThreadPriority( hThread, THREAD_PRIORITY_ABOVE_NORMAL );
         if ( ::ResumeThread( hThread ) != (DWORD)-1 )
            $Thread::Hang();
         ::CloseHandle( hThread );
      }
   }
   tp.UseTerminationThread = false;
   TerminationRoutine( &tp );
   $DEAD_CODE_BRANCH();
}

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

void $FatalError::RaiseFmt($CI_REF,PCWSTR messageFmt, ... ) $not_returns
{
   $$VERIFY_POINTER_ARG( messageFmt );
   va_list argList;
   RaiseVA($$CI, $VA_COMPLEMENT( messageFmt, argList ) );
}

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

void $FatalError::RaiseVA($CI_REF,PCWSTR messageFmt,va_list argList) $not_returns
{
   Raise($$CI, VerifyFormatAlloc($$, HelpersRT::FormatAllocVA($ci,$, messageFmt, argList )));
}

//==================================================================================================
} // RuntimeForStatic
