using System;
using System.Text;
using System.Threading;
using System.Reflection;
using System.Globalization;
using System.Configuration;
using System.Runtime.CompilerServices;

using CommonHelpers;

namespace ConsoleCalculator {

//**************************************************************************************************
/// <summary>
/// Application bootup class (it contains application entry point).
/// </summary>
public static class Startup {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static HConsole CON => HConsole.StdConIO;
//==================================================================================================

[MethodImpl(MethodImplOptions.NoInlining)]
static void PrepareToStart()
{
   // Initialization (optional, but useful):
   CommonHelpersLibrary.Initialize(
      //CommonHelpersInitFlags.IgnoreRaiseOnUnhandledExceptionUnderDebugger |
      CommonHelpersInitFlags.InteractiveConsoleApplicationDefaults );

   // Configuring console behaviour:
   CON.HandlesCancelEvent = true;
   //CON.TreatControlCAsInput = true;
   CON.UsePendingNewLine = true;

   // Setting console title:
   if ( HAssembly.IsEntryAssembly() )
   {
      if ( HOperatingSystem.IsWindows )
      {
#pragma warning disable CA1416 // windows:
         _ConsoleTitleToRestore_ = Console.Title;
#pragma warning restore CA1416 // windows.
      }
      Console.Title = string.Format( "{0} {1} {2}",
         HProgram.SimpleName, HUnicode.EmDash,
         "based on CommonHelpers library (DotNetHelpers)" );
   }
   // Applying "Mute" key from "appSettings" section of ".exe.config"
   HSound.IsMute =
      ConfigurationManager.AppSettings[ "Mute" ] == "1";
}

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

[MethodImpl(MethodImplOptions.NoInlining)]
static int Start(string[] args)
{
   // Running the application (the first access to "Program" class):
   try
   {
      // Calling "Program.Run"-function (which is, actually, main function in this application):
      Program.Run();
   }
   catch (HAppExitException e)
   {
      // Processing exception of a special type -- "XAppExitException/XAppFailureException":
      if (e is HAppFailureException)
         if ( e.AssociatedData == AppExitFailureExceptionMarkers.UnexpectedArguments )
            CON.PrintExpressive(e.Message);
         else
         {
            CON.ReportError( e );
            HProgram.ExitCode = e.ExitCode ?? HProgram.FailureExitCode;
         }
      // Performing pause before exit:
      CON.PerformExitionDialog(true);
   }

   // App termination message:
   CON.PrintOperation(true,"Exiting the program");
   CON.FlushPendingNewLine();

   // Completing execution (performing all pending finalizers)
   // and returning exit code to the system:
   return HProgram.PrepareToExit();
}

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

/// <summary>
/// Application entry point
/// </summary>
static int Main(string[] args)
{
   // The program (its main thread and UI) will be insensitive to the current system culture.
   // (Those formatting rules as we have in the EN-culture will be used.)
   // (Default CommonHelpers UI-strings are in english.)
   Thread.CurrentThread.CurrentCulture =
      Thread.CurrentThread.CurrentUICulture =
         CultureInfo.InvariantCulture;
   try
   {
      PrepareToStart();
   }
   catch (Exception e)
   {
      try { Console.WriteLine( e ); RestoreTitle(); return 1; }
      catch { throw; }
   }
   // Setting console IO-encoding to Unicode by default (if possible):
   bool useUnicodeEncoding = true;
   Action restoreEncoding = null;
   if ( useUnicodeEncoding )
   {
      Encoding
         inputEncoding = Console.InputEncoding,
         outputEncoding = Console.OutputEncoding;
      try { Console.OutputEncoding = Encoding.Unicode; }
      catch { useUnicodeEncoding = false; }
      if ( useUnicodeEncoding )
         try { Console.InputEncoding = Encoding.Unicode; }
         catch { useUnicodeEncoding = false; Console.OutputEncoding = outputEncoding; }
      if ( useUnicodeEncoding )
      {
         restoreEncoding = ()=>{
            Console.InputEncoding = inputEncoding;
            Console.OutputEncoding = outputEncoding; };
         Console.CancelKeyPress += (sender,cancelEventArgs) => restoreEncoding();
      }
   }
   // Disabling interruption by Ctrl+C (but Ctrl+Break is always enabled):
   Console.TreatControlCAsInput = true;
   try
   {
      // Calling "quasi-main" subroutine:
      return Start( args );
   }
   finally
   {
      // Restoring console IO-encoding from Unicode:
      restoreEncoding!.Invoke();
      RestoreTitle();
   }
}

static void RestoreTitle()
{
   if ( _ConsoleTitleToRestore_ != null )
      Console.Title = _ConsoleTitleToRestore_;
}

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

static string _ConsoleTitleToRestore_;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // Startup
//**************************************************************************************************

} // ConsoleCalculator
