using System;
using System.IO;

using CommonHelpers;

namespace LnkConverter {

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

public static void Run()
{
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   if ( !HProgram.HasEntryPointArguments )
   {
      PrintSyntax();
      throw new HAppExitException();
   }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

   var cmdParamParser = new HCmdLineParametersParser(
      /*new HCmdLineParametersParseOptions(){}*/ );
   cmdParamParser.AddSwitchKeyDef( SyntaxSwitchKey );
   cmdParamParser.AddSwitchKeyDef( CheckVariablesSwitchKey );
   cmdParamParser.AddSwitchKeyDef( ExpandDollarVariablesSwitchKey,
                                   HCmdLineKeyArgumentation.Optional );
#if NLIB_USE
   cmdParamParser.AddSwitchKeyDef( ScreenCorruptionDemoSwitchKey );
#endif // NLIB_USE
   try
      { cmdParamParser.ParseProcessCommandLine(); }
   catch (HCmdLineParametersParseException e)
      { RaiseSyntaxError( e ); }

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// ?:
   _IsSyntaxSwitchSpecified_ = cmdParamParser.ContainsSwitchKey( SyntaxSwitchKey );
// CKV:
   if ( cmdParamParser.ContainsSwitchKey( CheckVariablesSwitchKey ) )
      _TxtFlags_ |= HLnkConverterTxtFlags.CheckVariables;
// XDV:
   var parameter = cmdParamParser[ ExpandDollarVariablesSwitchKey ];
   if ( parameter != null )
   {
      _TxtFlags_ |= HLnkConverterTxtFlags.ExpandDollarVariables;
      if ( CheckSwitchKeySingleOptionValue( parameter, DVKeyArg_AllowEmptyValues ) )
         _TxtFlags_ |= HLnkConverterTxtFlags.UndefinedDollarVarsAsEmpty;
   }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

   if ( IsSyntaxSwitchSpecified )
      if ( cmdParamParser.ParamCount == 1 )
      {
         PrintSyntax();
         throw new HAppExitException();
      }
      else
         RaiseSyntaxError();
#if NLIB_USE
// SCRD:
   if ( cmdParamParser.ContainsSwitchKey( ScreenCorruptionDemoSwitchKey ) )
   {
      if ( cmdParamParser.ParamCount != 1 )
         RaiseSyntaxError( HLocal.TEXT(
            "Key /{0} does not assume presence of parameters nor other keys.",
            "Ключ /{0} не предполагает наличие параметров либо других ключей." ),
            ScreenCorruptionDemoSwitchKey );
      CON.PrintOperation( true, HLocal.TEXT(
         "Performing \"screen corruption\" demo (test)",
         "Выполнение демонстрации \"повреждения экрана\" (тест)" ));
   // Calling "LnkConverter_ScreenCorruptionTest" (API) implemented in "NativeLib.dll":
      if ( !NL.ScreenCorruptionTest( "9C37E9CF-7C4C-46C9-98BB-C5298A046CA1" ) )
         throw new AppFailureException( NL.LAST_ERROR_MSG() );
      throw new HAppExitException();
   }
#endif // NLIB_USE

   if ( cmdParamParser.UnnamedParamCount != 1 )
      RaiseSyntaxError( HLocal.TEXT(
         "Only one command line argument is permitted \x2014 input file/folder name "+
         "for conversion (look syntax).",
         "Допустим лишь один аргумент командной строки \x2014 входящее имя файла/папки "+
         "для конвертации (смотрите синтаксис)." ));

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//throw new ApplicationException( "Message-1.", new ApplicationException( "Message-2." ) );
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

   string
      sourceName = cmdParamParser.GetUnnamedParameter( 0 ),
      baseName, extension;

   if ( HString.IsBlank( sourceName ) )
      throw new HAppFailureException( HLocal.TEXT(
         "Empty name of file/directory.",
         "Пустое имя файла/директории." ));
   if ( HString.HasBoundaryWhiteSpace( sourceName ) )
      throw new HAppFailureException( HLocal.TEXT(
         "Name of input file/directory must not start and/or end with spaces.",
         "Имя входного файла/директории не должно начинаться и/или заканчиваться пробелами." ));
   try
   {
      if ( HPath.ContainsInvalidPathChar( sourceName ) )
         throw new HAppFailureException( HLocal.TEXT(
            "Input name (file/folder) contains invalid characters.",
            "Входное имя (файл/папка) содержит недопустимые символы." ));
      if ( HPath.ContainsInvalidFileNameChar( sourceName ) ||
           Path.GetFileName( sourceName ) != sourceName )
         throw new HAppFailureException( HLocal.TEXT(
            "Input name must be name of file/folder (without path).",
            "Входное имя должно быть именем файла/папки (без пути)." ));
      //if ( sourceName[0] == '.' ) goto INPUT_NAME_EXTENSION_ERROR;
      baseName = Path.GetFileNameWithoutExtension( sourceName );
      extension = Path.GetExtension( sourceName );
      switch ( extension.ToLower() )
      {
      case ".lnk":
         if ( CheckEnviromnentVariables || ExpandDollarVariables )
            throw HAppFailureExceptionCreator.Create( HLocal.TEXT(
               "Keys /{0} and /{1} are permitted only for txt-references "+
               "(file pattern: *.lnk.txt).",
               "Ключи /{0} и /{1} возможны только для txt-ссылок "+
               "(файлы вида: *.lnk.txt)." ),
               CheckVariablesSwitchKey, ExpandDollarVariablesSwitchKey );
         _ConvertDirection_ = ConvertDirection.LnkToTxt;
         break;
      case ".txt":
         _ConvertDirection_ = ConvertDirection.TxtToLnk;
         extension = Path.GetExtension( baseName );
         baseName = Path.GetFileNameWithoutExtension( baseName );
         if ( /*baseName == "" ||*/ extension.ToLower() != ".lnk" )
            goto INPUT_NAME_EXTENSION_ERROR;
         break;
      default:
         goto INPUT_NAME_EXTENSION_ERROR;
      }
   }
   catch (ArgumentException e)
   {
      throw HAppFailureExceptionCreator.Create( e );
   }
   _SourceName_ = sourceName;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/*
   if ( !HPath.IsDriveLetterPath( Directory.GetCurrentDirectory() ) )
      throw new HAppFailureException(
         "Запуск утилиты на путях без дисковой буквы запрещён. " );
*/
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

   FileAttributes sourceAttributes;
   try
   {
      sourceAttributes = File.GetAttributes( AdducePath( SourceName ) );
   }
   catch (FileNotFoundException)
   {
      throw HAppFailureExceptionCreator.Create( HLocal.TEXT(
         "File object (file/folder) was not found by input name: \"{0}\".",
         "Файловый объект (файл/папка) по входному имени не обнаружен: \"{0}\"." ),
         SourceName );
   }
   catch (Exception e)
   {
      throw HAppFailureExceptionCreator.Create( HLocal.TEXT(
         "{0}\n"+
         "(Input name: \"{1}\".)",
         "{0}\n"+
         "(Входное имя: \"{1}\".)" ),
         e.Message, SourceName );
   }
   _ConversionMode_ = (sourceAttributes & FileAttributes.Directory) != 0 ?
      ConversionMode.EntireFolder : ConversionMode.SingleFile;

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

   string
      outputExtension = null,
      tempExtension = ".tmp";
   switch (ConvertDirection)
   {
   case ConvertDirection.LnkToTxt: outputExtension = ".lnk.txt";  break;
   case ConvertDirection.TxtToLnk: outputExtension = ".lnk";      break;
   }
   if (ConversionMode==ConversionMode.EntireFolder)
   {
      outputExtension = outputExtension.ToUpper();
      tempExtension = tempExtension.ToUpper();
   }
   _TargetName_ = baseName + outputExtension;
   _TempName_ = TargetName + tempExtension;

   FileAttributes? attributes=null;
   try
   {
      attributes = File.GetAttributes( AdducePath( TargetName ) );
   }
   catch (Exception e)
   {
      if (!(e is FileNotFoundException))
         throw HAppFailureExceptionCreator.Create( e );
   }
   if (attributes!=null)
      throw HAppFailureExceptionCreator.Create( HLocal.TEXT(
         "Target file name \"{0}\" is occupied by {1}.\n"+
         "Conversion utility requires absence of target file object (file/folder).",
         "Целевое файловое имя \"{0}\" занято {1}.\n"+
         "Утилита конвертации требует отсутствия целевого файлового объекта (файл/папка)." ),
         TargetName,
         (attributes & FileAttributes.Directory) != 0 ?
            HLocal.TEXT( "existed folder", "имеющейся папкой" ) :
            HLocal.TEXT( "existed file", "имеющимся файлом" ) );

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   _LnkConverter_ = ConvertDirection == ConvertDirection.TxtToLnk ?
      new HLnkConverter(new HLnkConverterSettings(){
         ExeDummyShortcutFilePath = GetDummyShortcutFilePath(
            ExeDummyShortcutFileName, out _ExeDummyShortcutFromCurrentDirUsage_ ),
         FolderDummyShortcutFilePath = GetDummyShortcutFilePath(
            FolderDummyShortcutFileName, out _FolderDummyShortcutFromCurrentDirUsage_ ),
         TxtFlags = _TxtFlags_ }) :
      new HLnkConverter();
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   PrintInputInfo( CON );
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

   try
   {
      EraseTemporaryShortcutFile( TemporaryShortcutLnkFileName );
      EraseTemporaryShortcutFile( TemporaryShortcutTxtFileName );
      EraseErrorLog();
      StartErrorLog();
   }
   catch (OperationFailedException e)
   {
      throw HAppFailureExceptionCreator.Create( e );
   }

   try
   {
      switch (ConversionMode)
      {
      case ConversionMode.SingleFile:
         ProcessFile(SourceName,TargetName);
         break;
      case ConversionMode.EntireFolder:
         ProcessFolder(SourceName,TargetName);
         break;
      }
      EndErrorLog();
   }
   catch (ErrorLogException e)
   {
      CON.PrintError( true, HLocal.TEXT(
         "Error of working with error log.\n"+
         "{0}",
         "Ошибка работы с протоколом ошибок.\n"+
         "{0}" ), e.Message );
      HProgram.ExitCode = HProgram.BreakdownExitCode;
      throw new HAppFailureException("");
   }

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

   if ( ErrorLogRecordCount == 0 )
      try
      {
         EraseErrorLog();
      }
      catch (OperationFailedException e)
      {
         throw HAppFailureExceptionCreator.Create( HLocal.TEXT(
            "Error of empty error log removal: \"{0}\".\n"+
            "{1}",
            "Ошибка удаления пустого протокола ошибок: \"{0}\".\n"+
            "{1}" ), ErrorLogFileName, e.Message );
      }
  
   AppEraseTemporaryShortcutFile( TemporaryShortcutLnkFileName );
   AppEraseTemporaryShortcutFile( TemporaryShortcutTxtFileName );

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

   string[]
      summaryCaptions = new string[]
      {
         HLocal.TEXT( "Files passed", "Пройдено файлов" ),
         HLocal.TEXT( "Files created", "Создано файлов" ),
         HLocal.TEXT( "Files failed", "Файлов, потерпевших неудачу" )
      },
      summaryValues = new string[]
      {
         LeftPaddedIntegerForPrint( FilesPassed ),
         LeftPaddedIntegerForPrint( FilesSucceeded ),
         LeftPaddedIntegerForPrint( FilesFailed )
      };

   if ( ErrorLogRecordCount != 0 )
   {
      HArray.Append(
         ref summaryCaptions,
         new string[]
         {
            HLocal.TEXT( "Warnings in error log",
                         "Предупреждений в протоколе ошибок" ),
            HLocal.TEXT( "Total records in error log",
                         "Всего записей в протоколе ошибок" )
         } );
      HArray.Append(
         ref summaryValues,
         new string[]
         {
            LeftPaddedIntegerForPrint( ErrorLogWarningCount ),
            LeftPaddedIntegerForPrint( ErrorLogRecordCount )
         } );
   }

   CON.PrintSplitter( true );
   CON.PrintAlignedList( true, summaryCaptions, summaryValues );

   if ( ErrorLogRecordCount != 0 )
   {
      CON.Print();
      if ( ErrorLogErrorCount != 0 )
         CON.PrintError( HLocal.TEXT(
            "There are conversion {0} (information was saved in the log).",
            "Имеются {0} конвертации (информация сохранена в протоколе)." ),
            ErrorLogWarningCount != 0 ?
               HLocal.TEXT( "errors/warnings", "ошибки/предупреждения" ) :
               HLocal.TEXT( "errors", "ошибки" ) );
      else
         CON.PrintWarning( HLocal.TEXT(
            "There are conversion warnings (information was saved in the log).",
            "Имеются предупреждения конвертации (информация сохранена в протоколе)." ));
      CON.Print( HLocal.TEXT(
         "Look error log file: \"{0}\" (in current directory).",
         "Смотрите файл протокола ошибок: \"{0}\" (в текущей директории)." ),
         ErrorLogFileName );
   }

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

   if ( ErrorLogErrorCount != 0 )
      throw new HAppFailureException("");
   if ( ErrorLogRecordCount != 0 )
      throw new HAppExitException("");

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   return;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
INPUT_NAME_EXTENSION_ERROR:
   throw new HAppFailureException( HLocal.TEXT(
      "Input name of file/folder must have one of following forms: "+
      "\"*.lnk\" either \"*.lnk.txt\".",
      "Входное имя файла/папки должно иметь один из следующих видов: "+
      "\"*.lnk\" либо \"*.lnk.txt\"." ));
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
}

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

} // LnkConverter
