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

using CommonHelpers;

namespace LnkConverter {

//**************************************************************************************************
static class Startup {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static HConsole CON => HConsole.StdConIO;
//==================================================================================================
const CommonHelpersInitFlags
   CHInitializationBaseFlags = CommonHelpersInitFlags.None
// | CommonHelpersInitFlags.AvoidFatalErrorOnUnhandledExceptionUnderDebugger
#if DEBUG
   | CommonHelpersInitFlags.InteractsWithDesktop
#endif // DEBUG
   | CommonHelpersInitFlags.ConsoleApplicationDefaults;
//==================================================================================================

[MethodImpl(MethodImplOptions.NoInlining)]
static void PrepareToStart()
{
   // Configuring console behaviour:
   CON.UsePendingNewLine = true;
   CON.HandlesCancelEvent = true;
   //CON.TreatControlCAsInput = true;
   if ( HAssembly.IsEntryAssembly() )
   {
      _ConsoleTitleToRestore_ = Console.Title;
      Console.Title = string.Format( "{0} {1} {2}",
         HProgram.SimpleName, HUnicode.EmDash, LnkConverter_Info.LTitle );
   }
   var outputNormalWidthStr = Environment.GetEnvironmentVariable(
      "LnkConverter.OutputNormalWidth" );
   int outputNormalWidth;
   if ( outputNormalWidthStr != null &&
        HInt32.TryParseInvariant( outputNormalWidthStr, out outputNormalWidth ) )
      CON.NormalWidth = Math.Max( outputNormalWidth, HConsole.MinNormalWidth );
}

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

[MethodImpl(MethodImplOptions.NoInlining)]
static int Start(string[] args)
{
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   try
   {
      CommonHelpersLibrary.Initialize( CHInitializationBaseFlags
         | CommonHelpersInitFlags.SecondAssemblyUsage
         | CommonHelpersInitFlags.SystemAssemblyUsage
#if LEGACY
         | CommonHelpersInitFlags.CppAssemblyUsage
#endif // LEGACY
         | CommonHelpersInitFlags.FullFunctionalMode );
   }
   catch (Exception e)
   {
      try
      {
         CON.PrintError(
            "=== {0} (\"{1}\"): ===\n\n{2}",
            HLocal.TEXT( "INITIALIZATION ERROR", "ОШИБКА ИНИЦИАЛИЗАЦИИ" ),
            HAssembly.GetCallingAssemblySimpleName(),
            HException.ComposeChainedMessage(e,LnkConverter_Info.IsDebugConfiguration) );
         return HProgram.BreakdownExitCode;
      }
      catch
      {
         throw;
      }
   }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   Program.PrintLogoInformationHeader();

   bool?
      exitSuccess;
   try
   {
      Program.Run();
      exitSuccess = true;
   }
   catch (Exception e)
   {
      exitSuccess = false;
      var x = e as HAppExitException;
      if ( x != null )
      {
         if ( x is HAppFailureException )
         {
            object exceptionMarker =
               x.AssociatedData;
            if ( e.Message != "" )
               CON.PrintError( !(x is AppFailureException), x.Message );
            HProgram.ExitCode = x.ExitCode ?? HProgram.FailureExitCode;
         }
         else
            exitSuccess = null;
      }
      else
      {
#if DEBUG
         try { Program.Escape(); } catch {}
         throw;
#else // !DEBUG:
         CON.PrintError( true,
            "=== {0} (\"{1}\"): ===\n\n{2}",
            HLocal.TEXT( "PROGRAM FAILURE", "СБОЙ В ПРОГРАММЕ" ),
            HAssembly.GetCallingAssemblySimpleName(),
            HException.ComposeChainedMessage(e,LnkConverter_Info.IsDebugConfiguration) );
         HProgram.ExitCode = HProgram.BreakdownExitCode;
#endif // !DEBUG
      }
      Program.Escape();
   }

   Program.PrintCompletionStatusFooter( exitSuccess );

   //CON.PrintOperation(true,"Закрытие программы");
   HProgram.PrepareToExit();
   CON.FlushPendingNewLine();
   return HProgram.ExitCode;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
}

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

static int Main(string[] args)
{
   bool useUnicodeEncoding = true;
   try
   {
//    Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
/*
      Thread.CurrentThread.CurrentCulture =
      //Thread.CurrentThread.CurrentUICulture =
         CultureInfo.InvariantCulture;
*/
      PrepareToStart();
      if ( Environment.GetEnvironmentVariable( "LnkConverter.SuppressUnicodeOutput" ) == "1" )
         useUnicodeEncoding = false;
   }
   catch (Exception e)
   {
      try { Console.WriteLine( e ); RestoreTitle(); return 1; }
      catch { throw; }
   }
   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();
      }
   }
   try
   {
      return Start( args );
   }
   finally
   {
      restoreEncoding!.Invoke();
      RestoreTitle();
   }
}

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

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

static string _ConsoleTitleToRestore_;

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

} // LnkConverter
