//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
// CommonHelpers satellite library | Author: Sergei Y.Kitáev
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Reflection;
using System.Globalization;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.ComponentModel;

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

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

static string ReportDaySubfolderName
{
   get { return string.Format( "{0:yyyy}-{0:MM}-{0:dd}", DateTime.Now ); }
}

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

[MethodImpl(MethodImplOptions.NoInlining)]
static string GenerateReport( Assembly assembly, 
                              string cause, string message, Exception e,
                              StackTrace stackTrace, StackTrace dispatcherCallerStack )
{
   message = (message ?? "").Trim();
   string
      errorModuleName = HAssembly.GetModuleName(assembly),
      reportFolderPath = GetReportFolderPath( true );
   CreateReportDirectory( reportFolderPath );
   string
      filePath = Path.Combine
      (
         reportFolderPath,
         string.Format(
            "{0} - FatalErrorReport {1}.html",
            _AppSimpleName_,
            ErrorTime.ToString("yyyy-MM-dd HH-mm-ss",CultureInfo.InvariantCulture) )
      );
   using (TextWriter writer=new StreamWriter(filePath,false,new UTF8Encoding(true)))
   {
      writer.WriteLine("<html>");

      writer.WriteLine("<head>");
      writer.WriteLine("<meta http-equiv=content-type content=\"text/html; charset=utf-8\">");
      writer.WriteLine("<title>{0}</title>",Path.GetFileName(filePath));
      writer.WriteLine("<style>");
      writer.WriteLine("h4{ font-family: \"Trebuchet MS\"; }");
      writer.WriteLine("</style>");
      writer.WriteLine("</head>");

      writer.WriteLine("<body bgcolor=\"Linen\"><font face=\"Trebuchet MS\" size=2>");

      writer.WriteLine("<div align=\"center\" style=\"font-weight: bold\">");
      writer.WriteLine(
         "<u>Fatal error in <i>&laquo;{0}&raquo;</i> ({1}):</u><br>",
         _MainModuleName_, ErrorTime.ToString("f") );
      if (cause!=null)
         writer.WriteLine(
            "<font color=\"Navy\"><i>{0}</i></font><br>",
            cause );
      if (!HAppDomain.IsInDefaultAppDomain)
         writer.WriteLine(
            "(Application domain: <i>{0}</i>)<br>",
            AppDomain.CurrentDomain.FriendlyName );
      writer.WriteLine(
         "(Source module: <i>{0}</i>)<br>",
         errorModuleName );
      writer.WriteLine(
         "({0}: <i>ID={1}</i>)<br>",
         IsMainRaiseThread ?
            "In main program thread" :
            HProgram.IsMainThreadSpecified ?
               "In secondary program thread" :
               "In following program thread",
         _RaiseThread_.ManagedThreadId );
      writer.WriteLine("</div>");

      writer.WriteLine("<hr><p>");
      if (e!=null)
      {
         if (e.InnerException!=null)
            writer.WriteLine("<ul>");
         for (Exception x=e; x!=null; x=x.InnerException)
         {
            if (x!=e)
               WriteLineToHtml(writer);
            if (e.InnerException!=null)
               writer.Write("<li>");
            WriteLineToHtml( writer,
               "<font color=\"Red\"><b><u>{0}</u></b></font>",
               HException.ComposeMessage(x) );
            if (x.StackTrace!=null)
               WriteLinesToHtml(writer,x.StackTrace);
         }
         if (e.InnerException!=null)
            writer.WriteLine("</ul>");
      }
      else
      {
         writer.WriteLine("<h4><font color=\"Red\"><b>{0}</b></font></h4>",message);
         if ( stackTrace != null )
         {
            if ( message == "" )
            {
               WriteLineToHtml(writer,"=== {0}: ===",Verbose.ErrorStackTrace);
               WriteLineToHtml(writer);
            }
            WriteLinesToHtml(writer,HStackTrace.GetText(stackTrace));
         }
         if ( dispatcherCallerStack != null )
         {
            if ( message != "" || stackTrace != null )
               WriteLineToHtml(writer);
            WriteLineToHtml(writer,"=== {0}: ===",Verbose.DispatcherCallerStack);
            WriteLineToHtml(writer);
            WriteLinesToHtml(writer,HStackTrace.GetText(dispatcherCallerStack));
         }
         if ( message == "" && stackTrace == null && dispatcherCallerStack == null )
         WriteLineToHtml(writer,"({0})",Verbose.NO_STACK_TRACE_INFORMATION_AVAILABLE);
      }
      writer.WriteLine("</p><hr>");

      writer.WriteLine(
         "<p><h4 align=\"Center\"><font color=\"DimGray\" size=3>{0}</font></h4></p>",
         "<i>&laquo; End of fatal error report &raquo;</i>" );

      writer.WriteLine("</body>");

      writer.WriteLine("</html>");
   }
   return filePath;
}

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

[MethodImpl(MethodImplOptions.NoInlining)]
static void ShowReport(string filePath)
{
   try
   {
      Process.Start( new ProcessStartInfo( filePath ) {
         UseShellExecute = true,
         WindowStyle = ProcessWindowStyle.Maximized });
   }
   catch (Exception e)
   {
      throw HOpFailedExceptionCreator.Create(
         Verbose.CAN_NOT_OPEN_FATAL_ERROR_REPORT_HTML_DOCUMENT__0__FILE_1,
         e.Message, filePath );
   }
}

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

static void WriteLineToHtml(TextWriter writer)
{
   WriteLineToHtml(writer,"");
}

static void WriteLineToHtml(TextWriter writer,string line)
{
   writer.WriteLine("{0}<br>",line);
}

static void WriteLineToHtml(TextWriter writer,string lineFmt,params object[] parameters)
{
   WriteLineToHtml(writer,string.Format(lineFmt,parameters));
}

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

static void WriteLinesToHtml(TextWriter writer,string lines)
{
   if (lines=="")
   {
      WriteLineToHtml(writer);
      return;
   }
   int from=0,to;
   while ((to=lines.IndexOf(Environment.NewLine,from))>=0)
   {
      WriteLineToHtml(writer,lines.Substring(from,to-from));
      from=to+2;
   }
   if (from<lines.Length)
      WriteLineToHtml(writer,lines.Substring(from,lines.Length-from));
}

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

static string GetReportFolderPath(bool withDaySubfolder=false)
{
   if ( _ReportFolderFullPath_!=null && !_SecondAttemptToGenerateReport_ )
      return withDaySubfolder ?
         Path.Combine( _ReportFolderFullPath_, ReportDaySubfolderName ) :
         _ReportFolderFullPath_;
   string
      tempFolderPath;
   try
   {
      tempFolderPath = Path.GetTempPath();
   }
   catch (SystemException e)
   {
      throw HOpFailedExceptionCreator.Create(
         Verbose.CAN_NOT_OBTAIN_TEMPORARY_FOLDER_PATH+"\n"+
         "{0}", e.Message );
   }
   try
   {
      var path = Path.Combine( tempFolderPath, HProgram.SimpleName );
      return withDaySubfolder ? Path.Combine( path, ReportDaySubfolderName ) : path;
   }
   catch (Exception e)
   {
      throw HOpFailedExceptionCreator.Create(
         Verbose.CAN_NOT_COMPOSE_FATAL_ERROR_REPORT_PATH_WITH_TEMPORARY_APPLICATION_FOLDER,
         "{0}", e.Message );
   }
}

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

static string GetReportFolderFullPath(string path)
{
   try
   {
      return Path.GetFullPath( path );
   }
   catch (SystemException e)
   {
      throw HOpFailedExceptionCreator.Create(
         Verbose.CAN_NOT_DETERMINE_FATAL_ERROR_REPORT_FOLDER_FULL_PATH+"\n"+
         "{0}", e.Message );
   }
}

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

static string CreateReportDirectory(string path)
{
   try
   {
      Directory.CreateDirectory( path );
   }
   catch (SystemException x)
   {
      throw HOpFailedExceptionCreator.Create(
         Verbose.CAN_NOT_PREPATE_FATAL_ERROR_REPORT_FOLDER+"\n"+
         "{0}", x.Message );
   }
   return path;
}

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

} // CommonHelpers (.WASM)
