using System;
using System.IO;

using CommonHelpers;

namespace LnkConverter {

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

public static void PrintLogoInformationHeader()
{
   CON.PrintTitleHeader( "{0} ({1}):",
      LnkConverter_Info.LTitle.ToUpper(),
      LnkConverter_Info.LCopyrightCON.ToUpper() );
   if ( !ReducedStartInfo )
      CON.PrintFeaturedInscription( true,
         HLocal.TEXT( "Version: {0}", "Версия: {0}" ),
         LnkConverter_Info.VersionStringEx );
}

public static void PrintCompletionStatusFooter(bool? success)
{
   CON.PrintTitleFooter( true,
      "{0} {1} {2}",
      LnkConverter_Info.LSimpleTitle.ToUpper(),
      CON.LongDash,
      success == null ? HLocal.TEXT( "COMPLETED", "ЗАВЕРШЕНО" ) :
         success.Value ? HLocal.TEXT( "SUCCESS", "УСПЕХ" ) :
            HLocal.TEXT( "FAILURE", "НЕУДАЧА" ) );
}

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

static void PrintSyntax()
{
   CON.PrintDashAlignedList( true,
      HLocal.TEXT(
         "Main syntax (without keys):",
         "Основной синтаксис (параметры без ключей):" ),
      new string[]
      {
         string.Format( "LnkConverter <{0}>", HLocal.TEXT( "File.lnk"      , "Файл.lnk"      )),
         string.Format( "LnkConverter <{0}>", HLocal.TEXT( "File.lnk.txt"  , "Файл.lnk.txt"  )),
         string.Format( "LnkConverter <{0}>", HLocal.TEXT( "Folder.LNK"    , "Папка.LNK"     )),
         string.Format( "LnkConverter <{0}>", HLocal.TEXT( "Folder.LNK.TXT", "Папка.LNK.TXT" )),
         "LnkConverter"
      },
      new string[]
      {
         HLocal.TEXT( "transformation of file \".lnk\" to \".lnk.txt\"",
                      "преобразование файла \".lnk\" to \".lnk.txt\"" ),
         HLocal.TEXT( "transformation of file \".lnk.txt\" to \".lnk\"",
                      "преобразование файла \".lnk.txt\" to \".lnk\"" ),
         HLocal.TEXT( "transformation of files \"*.lnk\" to \"*.lnk.txt\"",
                      "преобразование файлов \"*.lnk\" в \"*.lnk.txt\"" ),
         HLocal.TEXT( "transformation of files \"*.lnk.txt\" to \"*.lnk\"",
                      "преобразование файлов \"*.lnk.txt\" в \"*.lnk\"" ),
         HLocal.TEXT( "output of utility call syntax",
                      "вывод синтаксиса вызова утилиты" )
      }
   );
   CON.Print( true, ConsoleColor.Magenta, HLocal.TEXT(
      "Input name of file/folder must not contain path.",
      "Входное имя файла/папки не должно содержать путь." ));
   CON.PrintDashAlignedList( true, HLocal.TEXT(
      "Possible keys (/... or -...; case insensitive):",
      "Возможные ключи (/... либо -...; не чувствительно к регистру):" ),
      new string[]
      {
         "/"+CheckVariablesSwitchKey,
         "/"+ExpandDollarVariablesSwitchKey,
#if NLIB_USE
         "/"+ScreenCorruptionDemoSwitchKey,
#endif // NLIB_USE
         "/"+SyntaxSwitchKey
      },
      new string[]
      {
         HLocal.TEXT( "check environment variables (txt-ref pattern: %...%)",
                      "проверять переменные среды (txt-ссылки вида: %...%)" ),
         HLocal.TEXT( "unfold environment \"dollar\"-variables (txt-ref pattern: $(...))",
                      "раскрывать \"доллар\"-переменные среды (txt-ссылки вида: $(...))" ),
#if NLIB_USE
         HLocal.TEXT( "demonstration of \"screen corruption\" (with subsequent recovery)",
                      "демонстрация \"повреждения экрана\" (с восстанавлением)" ),
#endif // NLIB_USE
         HLocal.TEXT( "utility systax output (same as without parameters)",
                      "вывод синтаксиса утилиты (то же, что и без параметров)" )
      }
   );
   CON.PrintDashAlignedList( true,
      string.Format( HLocal.TEXT(
         "Arguments-options for key /{0}:\"...\",... (case insensitive):",
         "Аргументы-опции для ключа /{0}:\"...\",... (не чувствительно к регистру):" ),
         ExpandDollarVariablesSwitchKey ),
      new string[]
      {
         string.Format( ":{0}", DVKeyArg_AllowEmptyValues )
      },
      new string[]
      {
         HLocal.TEXT( "allow empty values (for undetermined variables)",
                      "разрешить пустые значения (для неопределён. переменных)" )
      }
   );
   CON.PrintFaint( true, HLocal.TEXT(
      "Processing of file/folder (input/output/temporary data) is performed with respect to "+
      "your location in file system (current directory of CMD-processor).",
      "Обработка файла/папки (входные/выходные/временные данные) ведётся относительно "+
      "Вашего месторасположения в файловой системе (текущая директория процессора CMD)." ));
   CON.PrintDashAlignedList( true, HLocal.TEXT(
      "Additional \"weak options\" (environment variables like \"LnkConverter.*\"):",
      "Дополнительные \"тихие опции\" (переменные среды вида \"LnkConverter.*\"):" ),
      new string[]
      {
         ".OutputNormalWidth",
         ".SuppressUnicodeOutput",
         ".ReducedStartInfo",
         ".AvoidLongPaths"
      },
      new string[]
      {
         HLocal.TEXT( "normal width of text ouput",
                      "нормальная ширина текстового вывода" ),
         HLocal.TEXT( "suppress unicode output: 1/0",
                      "подавление вывода в юникод: 1/0" ),
         HLocal.TEXT( "not output version number and input info (file/folder): 1/0",
                      "не выводить номер версии и входную информацию (файл/папка): 1/0" ),
         HLocal.TEXT( "avoid long file paths",
                      "не применять длинные файловые пути" )
      }
   );
#pragma warning disable 0162
   if ( ExeDummyShortcutFileName == FolderDummyShortcutFileName )
   {
      CON.Print( true, HLocal.TEXT(
         "Also, it is possible to place to current directory so-called dummy-file: \"{0}\".",
         "В текущем каталоге возможно, также, разместить так называемый файл-куклу: \"{0}\"." ),
         ExeDummyShortcutFileName );
      CON.Print( HLocal.TEXT(
         "Dummy-file serves as binary prototype for generated program file fererences and "+
         "folder references with explicit path.",
         "Файл-кукла служит бинарным прообразом для генерируемых ссылочных файлов программ "+
         "и папок явного пути." ));
   }
   else
   {
      CON.Print( true, HLocal.TEXT(
         "Also, in current directory, it is possible to place so-called dummy-file:"+
         "\"{0}\" and/or \"{1}\".",
         "В текущем каталоге возможно, также, разместить так называемые файлы-куклы: "+
         "\"{0}\" и/или \"{1}\"." ),
         ExeDummyShortcutFileName, FolderDummyShortcutFileName );
      CON.Print( HLocal.TEXT(
         "Dummy-files serve as binary prototypes for generated program file fererences "+
         "and, correspondently, folder references with explicit path.",
         "Файлы-куклы служат бинарными прообразами для генерируемых ссылочных файлов программ "+
         "и, соответственно, папок явного пути." ));
   }
   CON.Print( ExeDummyShortcutFileName == FolderDummyShortcutFileName ?
      HLocal.TEXT(
         "(By default dummy-file from directory of executable program module is used.)",
         "(По умолчанию используется файл-кукла из директории исполняемого модуля программы.)" ) :
      HLocal.TEXT(
         "(By default dummy-files from directory of executable program module are used.)",
         "(По умолчанию используются файлы-куклы из директории исполняемого модуля программы.)" )
   );
#pragma warning restore 0162
}

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

static void PrintInputInfo(HConsole console)
{
   bool hasSomeInfo = false;
   if ( !ReducedStartInfo )
   {
      hasSomeInfo = true;
      console.PrintDashAlignedBulletedList( true,
         ConversionMode == ConversionMode.SingleFile ?
            new string[]{ HLocal.TEXT( "Source file", "Исходный файл" ),
                          HLocal.TEXT( "Target file", "Целевой файл" ) } :
            new string[]{ HLocal.TEXT( "Source folder", "Исходная папка" ),
                          HLocal.TEXT( "Target folder", "Целевая папка" ) },
         new string[]{ SourceName, TargetName } );
      console.PrintFaint( true, HLocal.TEXT(
         "Name of {0}: \"{1}\"", "Имя {0}: \"{1}\"" ),
         ConversionMode == ConversionMode.SingleFile ?
            HLocal.TEXT( "temporary file", "временного файла" ) :
            HLocal.TEXT( "temporary folder", "временной папки" ),
         TempName );
   }
   if ( ConvertDirection == ConvertDirection.TxtToLnk &&
        (ExeDummyShortcutFromCurrentDirUsage || FolderDummyShortcutFromCurrentDirUsage) )
   {
      hasSomeInfo = true;
      console.Print();
      if ( ExeDummyShortcutFromCurrentDirUsage &&
           FolderDummyShortcutFromCurrentDirUsage &&
           ExeDummyShortcutFileName == FolderDummyShortcutFileName )
         console.PrintIntensive( HLocal.TEXT(
            "Dummy-file from current folder will be used: \"{0}\" "+
            "(for creation of program file and explicit path folder references).",
            "Будет использован файл-кукла из текущего каталога: \"{0}\" "+
            "(для создания ссылок программ и папок явного пути)." ),
            ExeDummyShortcutFileName );
      else
      {
         if ( ExeDummyShortcutFromCurrentDirUsage )
            console.PrintExpressive( HLocal.TEXT(
               "For creation of program file references, dummy-file from current folder "+
               "will be used: \"{0}\".",
               "Для создания программных ссылок явного пути будет использован файл-кукла "+
               "из текущего каталога: \"{0}\"." ),
               ExeDummyShortcutFileName );
         if ( FolderDummyShortcutFromCurrentDirUsage )
            console.PrintExpressive( HLocal.TEXT(
               "For creation of explicit path folder references, dummy-file from current folder "+
               "will be used: \"{0}\".",
               "Для создания ссылок папок явного пути будет использован файл-кукла "+
               "из текущего каталога: \"{0}\"." ),
               FolderDummyShortcutFileName );
      }
   }
   if ( hasSomeInfo )
      console.PrintDoubleSplitter( true );
}

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

/// <exception cref="HAppFailureException" />
static void RaiseSyntaxError()
{
   RaiseSyntaxError( (string)null );
}
/// <exception cref="HAppFailureException" />
static void RaiseSyntaxError([HOptional] string message)
{
   CON.PrintError( true, message != null ?
      HLocal.TEXT( "=== Error of command-line parameters parse: ===\n",
                   "=== Ошибка разбора параметров командной строки: ===\n" ) + message :
      HLocal.TEXT(
         "Incorrect specification of arguments and/or command line keys (look syntax).",
         "Неправильная спецификация аргументов и/или ключей командной строки (смотрите синтаксис)."
      ));
   CON.Print( HLocal.TEXT(
      "For syntax lookup of \"{0}\"-utility use its call without parameters, "+
      "or with key /{1}.",
      "Для просмотра синтаксиса утилиты \"{0}\" используйте вызов без параметров, "+
      "либо с ключом /{1}." ),
      LnkConverter_Info.AssemblyName, SyntaxSwitchKey );
   throw new HAppFailureException("");
}
/// <exception cref="ArgumentNullException" />
/// <exception cref="HAppFailureException" />
static void RaiseSyntaxError(string messageFmt,params object[] args)
{
   HArgChecking.VerifyNotNulls( messageFmt, args );
   RaiseSyntaxError( string.Format(messageFmt,args) );
}
/// <exception cref="ArgumentNullException" />
/// <exception cref="HAppFailureException" />
static void RaiseSyntaxError(Exception error)
{
   HArgChecking.VerifyNotNull( error );
   RaiseSyntaxError( error.Message );
}

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

/// <exception cref="ArgumentNullException" />
/// <exception cref="HAppFailureException" />
static bool CheckSwitchKeySingleOptionValue( HCmdLineParameter parameter,
                                             params string[] expectedValues )
{
   return CheckSwitchKeySingleOptionValueEx( parameter, expectedValues ) >= 0;
}

/// <exception cref="ArgumentNullException" />
/// <exception cref="HAppFailureException" />
[HStrictResult]
static int CheckSwitchKeySingleOptionValueEx( HCmdLineParameter parameter,
                                              params string[] expectedValues )
{
   HArgChecking.VerifyNotNulls( parameter, expectedValues );
   HArgChecking.VerifyNotNulls( expectedValues );
   if ( !parameter.HasSwitchKeyArguments || expectedValues.Length == 0 )
      return -1;
   string optionValue = parameter[ 0 ];
   int idx = HString.ListIndexOf( true, optionValue, expectedValues );
   if ( idx < 0 ) 
      if ( expectedValues.Length == 1 )
         RaiseSyntaxError( parameter.ComposeWrongSwitchKeyArgumentsMessage(
            HLocal.TEXT(
               "Unknown (unsupported) value: \"{0}\".\n"+
               "The only possible option value: \"{1}\".",
               "Неизвестное (неподдерживаемое) значение: \"{0}\".\n"+
               "Единственно возможное значение опции: \"{1}\"." ),
            optionValue, expectedValues[ 0 ] ));
      else
         RaiseSyntaxError( parameter.ComposeWrongSwitchKeyArgumentsMessage(
            HLocal.TEXT(
               "Unknown (unsupported) option value: \"{0}\".\n",
               "Неизвестное (неподдерживаемое) значение опции: \"{0}\".\n" ),
            optionValue ));
   return idx;
}

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

/// <exception cref="HAppFailureException" />
static string GetDummyShortcutFilePath(string fileName,out bool fromCurrentDirUsage)
{
   HArgChecking.VerifyNotNull( fileName );
   Exception error;
   string fullPath = Path.Combine( Directory.GetCurrentDirectory(), fileName );
   if ( HFile.CheckExists( AdducePath( fullPath ), out error ) )
   {
      fromCurrentDirUsage = true;
      return fullPath;
   }
   if ( !(error is FileNotFoundException) )
      throw CreateError_CantCheckDummyShortcutFile( fullPath, error );
   fromCurrentDirUsage = false;
   fullPath = Path.Combine( HProgram.EntryModuleDirectory, fileName );
   if ( HFile.CheckExists( AdducePath( fullPath ), out error ) )
      return fullPath;
   throw error is FileNotFoundException ?
      HAppFailureExceptionCreator.Create( HLocal.TEXT(
         "Reference dummy-file not found: \"{0}\" (program module directory).",
         "Ссылочный файл-кукла не найден: \"{0}\" (директория программного модуля)." ),
         PathForMessage( fullPath ) ) :
      CreateError_CantCheckDummyShortcutFile( fullPath, error );
}

static HAppFailureException CreateError_CantCheckDummyShortcutFile(string filePath,Exception error)
{
   return HAppFailureExceptionCreator.Create( HLocal.TEXT(
      "Can not check existence of reference dummy-file: \"{0}\".\n"+
      "{1}",
      "Не удаётся проверить наличие ссылочного файла-куклы: \"{0}\".\n"+
      "{1}" ), PathForMessage( filePath ), error.ToString() );
}

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

/// <exception cref="HAppFailureException" />
static void AppEraseTemporaryShortcutFile(string fileName)
{
   try
   {
      EraseTemporaryShortcutFile( fileName );
   }
   catch (OperationFailedException e)
   {
      throw HAppFailureExceptionCreator.Create( HLocal.TEXT(
         "Error of temporary reference file removal: \"{0}\".\n"+
         "{1}",
         "Ошибка удаления временного ссылочного файла: \"{0}\".\n"+
         "{1}" ), fileName, e.Message );
   }
}

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

static string LeftPaddedIntegerForPrint(int value)
{
   return value.ToString().PadLeft( 5 );
}

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

} // LnkConverter
