using System;
using System.IO;
using System.Text;

using CommonHelpers;

namespace LnkConverter {

//**************************************************************************************************
partial class Program {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

static string ErrorLogFileName =>
   LnkConverter_Info.AssemblyName+".ErrorLog.txt";
static string ErrorLogTempFileName =>
   ErrorLogFileName+".tmp";

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

static bool IsErrorLogOpen =>
   _ErrorLogWriter_ != null;

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

static int ErrorLogRecordCount =>
   _ErrorLogRecordCount_;
static int ErrorLogErrorCount =>
   _ErrorLogErrorCount_;
static int ErrorLogWarningCount =>
   _ErrorLogWarningCount_;

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

/// <exception cref="OperationFailedException" />
static void EraseErrorLog()
{
   Exception error;
   if ( HFile.CheckExists( AdducePath( ErrorLogFileName ), out error ) )
   {
      try
      {
         File.Delete( AdducePath( ErrorLogFileName ) );
      }
      catch (Exception e)
      {
         throw OpFailedExceptionCreator.Create( HLocal.TEXT(
            "Can not remove error log file: \"{0}\".\n"+
            "{1}",
            "Не удаётся удалить файл протокола ошибок: \"{0}\".\n"+
            "{1}" ), ErrorLogFileName, e.Message );
      }
   }
   else
      HandleCheckFileExistsError( ErrorLogFileName, error );
}

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

/// <exception cref="ErrorLogException" />
static void AddErrorLogErrorRecord([HOptional] string sourceFile,string message)
{
   AddErrorLogRecord( true, sourceFile, new string[]{ message } );
}

/// <exception cref="ErrorLogException" />
static void AddErrorLogErrorRecord( [HOptional] string sourceFile,
                                    string messageFmt, params object[] parameters )
{
   AddErrorLogErrorRecord( sourceFile, string.Format(messageFmt,parameters) );
}

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

/// <exception cref="ErrorLogException" />
static void AddErrorLogWarningsRecord( [HOptional] string sourceFile, string[] messages )
{
   AddErrorLogRecord( false, sourceFile, messages );
}

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

/// <exception cref="ErrorLogException" />
static void AddErrorLogRecord( bool error, [HOptional] string sourceFile, string[] messages )
{
   HArgChecking.VerifyNotNulls( messages );

   if ( messages.Length==0 ||
        error && messages.Length!=1 ||
        !error && sourceFile==null )
      throw new ArgumentException();

   if (!IsErrorLogOpen)
      StartErrorLog();

   _ErrorLogRecordCount_++;
   if ( error )
      _ErrorLogErrorCount_++;
   else
      _ErrorLogWarningCount_++;

   try
   {
      if ( sourceFile != null )
         _ErrorLogWriterConsole_.PrintIntensive( true, HLocal.TEXT(
            "{0}) [File processing: \"{1}\"] >>",
            "{0}) [Обработка файла: \"{1}\"] >>" ),
            _ErrorLogRecordCount_, PathForPrint( sourceFile ) );
      else
         _ErrorLogWriterConsole_.PrintIntensive( true, HLocal.TEXT(
            "{0}) Error, which not allows to perform further file conversion: >>",
            "{0}) Ошибка, не позволяющая вести дальнеюшую конвертацию файлов: >>" ),
         _ErrorLogRecordCount_ );
      if ( error )
         _ErrorLogWriterConsole_.PrintError( messages[0] );
      else
         if ( messages.Length == 1 )
         {
            _ErrorLogWriterConsole_.OutputIntensive( HLocal.TEXT(
               "Warning:", "Предупреждение: " ));
            _ErrorLogWriterConsole_.PrintWarning( messages[0] );
         }
         else
         {
            _ErrorLogWriterConsole_.PrintIntensive( HLocal.TEXT(
               "=== Warnings: ===", "=== Предупреждения: ===" ));
            for (int i=0; i<messages.Length; i++)
            {
               _ErrorLogWriterConsole_.OutputIntensive( ">> {0}: ", i+1 );
               _ErrorLogWriterConsole_.PrintWarning( messages[i] );
            }
         }
      if (sourceFile==null)
         _ErrorLogWriterConsole_.PrintError( HLocal.TEXT(
            "(Reference file conversion was interrupted.)",
            "(Конвертация ссылочных файлов прервана.)" ));
   }
   catch (Exception e)
   {
      throw PrepareLogOperationError( HLocal.TEXT(
         "Can not write to file: \"{0}\".\n"+
         "{1}",
         "Не удаётся писать в файл: \"{0}\".\n"+
         "{1}" ), ErrorLogTempFileName, e.Message );
   }
}

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

/// <exception cref="InvalidOperationException" />
/// <exception cref="ErrorLogException" />
static void StartErrorLog()
{
   if (IsErrorLogOpen)
      throw new InvalidOperationException( HLocal.TEXT(
         "Error log was already started.",
         "Журнал ошибок уже начат." ));
   _ErrorLogRecordCount_ = _ErrorLogErrorCount_ = _ErrorLogWarningCount_ = 0;
   StreamWriter
      writer = null;
   try
   {
      writer = new StreamWriter( AdducePath( ErrorLogTempFileName ),
                                 false, new UTF8Encoding(true) );
   }
   catch (Exception e)
   {
      throw PrepareLogOperationError( HLocal.TEXT(
         "Can not create file: \"{0}\".\n"+
         "{1}",
         "Не удаётся создать файл: \"{0}\".\n"+
         "{1}" ), ErrorLogTempFileName, e.Message );
   }
   _ErrorLogWriterConsole_ = new HConsole(writer);
   try
   {
      var dateTime = DateTime.Now;
      _ErrorLogWriterConsole_.PrintHeader( HLocal.TEXT(
         "CONVERSION ERROR LOG (AT {0} {1} {2}):",
         "ЖУРНАЛ ОШИБОК КОНВЕРТАЦИИ (ОТ {0} {1} {2}):" ),
         dateTime.ToLongDateString().ToUpper(),
         CON.LongDash,
         dateTime.ToLongTimeString() );
      PrintInputInfo(_ErrorLogWriterConsole_);
   }
   catch (Exception e)
   {
      try { writer.Close(); } catch {}
      throw PrepareLogOperationError( e );
   }
   _ErrorLogWriter_ = writer;
}

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

/// <exception cref="ErrorLogException" />
static void EndErrorLog()
{
   if (!IsErrorLogOpen)
      return;
   var writer = HOps.Exchange(ref _ErrorLogWriter_,null);
   var writerConsole = HOps.Exchange(ref _ErrorLogWriterConsole_,null);
   try
   {
      writerConsole.PrintSplitter(true);
      writerConsole.PrintAlignedList( true,
         new string[]
         {
            HLocal.TEXT( "Errors", "Ошибок" ),
            HLocal.TEXT( "Warnings", "Предупреждений" ),
            HLocal.TEXT( "Total records", "Всего записей" )
         },
         new string[]
         {
            LeftPaddedIntegerForPrint( ErrorLogErrorCount ),
            LeftPaddedIntegerForPrint( ErrorLogWarningCount ),
            LeftPaddedIntegerForPrint( ErrorLogRecordCount )
         }
      );
      writerConsole.PrintFooter( true, HLocal.TEXT(
         "END OF CONVERSION ERROR LOG",
         "КОНЕЦ ЖУРНАЛА ОШИБОК КОНВЕРТАЦИИ" ));
   }
   catch (Exception e)
   {
      EscapeErrorLog();
      throw PrepareLogOperationError( e );
   }
   try
   {
      writer.Close();
   }
   catch (Exception e)
   {
      throw PrepareLogOperationError( HLocal.TEXT(
         "Can not close file: \"{0}\".\n"+
         "{1}",
         "Не удаётся закрыть файл: \"{0}\".\n"+
         "{1}" ), ErrorLogTempFileName, e.Message );
   }
   try
   {
      HFile.Move( AdducePath( ErrorLogTempFileName ), AdducePath( ErrorLogFileName ) );
   }
   catch (Exception e)
   {
      try { File.Delete( AdducePath( ErrorLogTempFileName ) ); } catch {}
      throw PrepareLogOperationError( HLocal.TEXT(
         "Can not rename file: \"{0}\" to \"{1}\".\n"+
         "{1}",
         "Не удаётся переименовать файл: \"{0}\" в \"{1}\".\n"+
         "{1}" ), ErrorLogTempFileName, ErrorLogFileName, e.Message );
   }
}

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

static ErrorLogException PrepareLogOperationError(string message)
{
   if (IsErrorLogOpen)
   {
      var writer = HOps.Exchange(ref _ErrorLogWriter_,null);
      _ErrorLogWriterConsole_ = null;
      try
      {
         writer.Close();
         HFile.Move( AdducePath( ErrorLogTempFileName ), AdducePath( ErrorLogFileName ) );
      }
      catch
      {}
   }
   return new ErrorLogException(message);
}

static ErrorLogException PrepareLogOperationError(string messageFmt,params object[] parameters)
{
   return PrepareLogOperationError(string.Format(messageFmt,parameters));
}

static ErrorLogException PrepareLogOperationError(Exception e)
{
   return PrepareLogOperationError(e.Message);
}

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

static void EscapeErrorLog()
{
   if (!IsErrorLogOpen)
      return;
   var writer = HOps.Exchange(ref _ErrorLogWriter_,null);
   _ErrorLogWriterConsole_ = null;
   try
   {
      writer.Close();
      HFile.Move( AdducePath( ErrorLogTempFileName ), AdducePath( ErrorLogFileName ) );
   }
   catch
   {}
}

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

static StreamWriter
   _ErrorLogWriter_;
static HConsole
   _ErrorLogWriterConsole_;
static int
   _ErrorLogRecordCount_,
   _ErrorLogErrorCount_,
   _ErrorLogWarningCount_;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // Program
//**************************************************************************************************

} // LnkConverter
