using System;
using System.IO;
using System.Collections;

using CommonHelpers;

namespace LnkConverter {

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

/// <exception cref="ErrorLogException" />
static void ProcessFolder(string sourceDir,string targetDir)
{
   string tempDir = targetDir + ".TMP";

   CON.Print();

   bool? folderCreationFlag = false;

   try
   {
      Exception error;
      if ( HDirectory.CheckExists( AdducePath( tempDir ), out error ) )
      {
         CON.PrintOperation( HLocal.TEXT(
            "Removing temporary folder: \"{0}\"",
            "Удаление временной папки: \"{0}\"" ), PathForPrint( tempDir ) );
         try
         {
            HDirectory.DeleteReadonlyTree( AdducePath( tempDir ) );
         }
         catch (Exception e)
         {
            throw OpFailedExceptionCreator.Create( HLocal.TEXT(
               "Can not remove directory: \"{0}\".\n"+
               "{1}",
               "Не удаётся удалить директорию: \"{0}\".\n"+
               "{1}" ), PathForMessage( tempDir ), e.Message );
         }
      }
      else
         if ( !(error is FileNotFoundException) )
            throw new OperationFailedException( HException.GetErrorMessage( error ) );

      DoProcessFolder(
         sourceDir, tempDir,
         folderCreationFlag );

      folderCreationFlag = false;

      CON.PrintOperation( HLocal.TEXT(
         "Renaming folder: \"{0}\" >> \"{1}\"",
         "Переименование папки: \"{0}\" >> \"{1}\"" ),
         PathForPrint( tempDir ), PathForPrint( targetDir ) );
      try
      {
         HDirectory.Move( AdducePath( tempDir ), AdducePath(  targetDir ) );
      }
      catch (Exception e)
      {
         throw OpFailedExceptionCreator.Create( HLocal.TEXT(
            "Can not rename directory: \"{0}\" >> \"{1}\".\n"+
            "{2}",
            "Не удаётся переименовать директорию: \"{0}\" >> \"{1}\".\n"+
            "{2}" ),
            PathForMessage( tempDir ),
            PathForMessage( targetDir ),
            e.Message );
      }
   }
   catch (OperationFailedException e)
   {
      CON.PrintError( e.Message );
      AddErrorLogErrorRecord( null, e.Message );
      if ( folderCreationFlag.Value )
      {
         CON.PrintOperation( HLocal.TEXT(
            "Removing temporary folder: \"{0}\"",
            "Удаление временной папки: \"{0}\"" ), PathForPrint( tempDir ) );
         try
         {
            HDirectory.DeleteReadonlyTree( AdducePath( tempDir ) );
         }
         catch (Exception x)
         {
            CON.PrintError( HLocal.TEXT(
               "Can not remove directory: \"{0}\".\n"+
               "{1}",
               "Не удаётся удалить директорию: \"{0}\".\n"+
               "{1}" ), PathForMessage( tempDir ), x.Message );
         }
      }
   }
}

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

/// <exception cref="OperationFailedException" />
static void DoProcessFolder(string sourceDir,string targetDir,[HOptional] bool? folderCreationFlag)
{
   FileAttributes attr;
   try
   {
      attr = File.GetAttributes( AdducePath( sourceDir ) );
   }
   catch (Exception e)
   {
      throw OpFailedExceptionCreator.Create( HLocal.TEXT(
         "Can not obtain directory attributes: \"{0}\".\n"+
         "{1}",
         "Не удаётся получить атрибуты директории: \"{0}\".\n"+
         "{1}" ), sourceDir, e.Message );
   }
   if ( folderCreationFlag != null )
      CON.PrintOperation( HLocal.TEXT(
         "Creating temporary folder: \"{0}\"",
         "Создание временной папки: \"{0}\"" ), PathForPrint( targetDir ) );
   else
      CON.PrintFaint( "{0}:", PathForPrint( sourceDir ) );
   try
   {
      Directory.CreateDirectory( AdducePath( targetDir ) );
   }
   catch (Exception e)
   {
      throw OpFailedExceptionCreator.Create( HLocal.TEXT(
         "Can not create directory: \"{0}\".\n"+
         "{1}",
         "Не удаётся создать директорию: \"{0}\".\n"+
         "{1}" ), PathForMessage( targetDir ), e.Message );
   }
   if ( folderCreationFlag != null )
      folderCreationFlag = true;
   try
   {
      File.SetAttributes( AdducePath( targetDir ), attr );
   }
   catch (Exception e)
   {
      throw OpFailedExceptionCreator.Create( HLocal.TEXT(
         "Can not set attributes to directory: \"{0}\".\n"+
         "{1}",
         "Не удаётся установить атрибуты на директории: \"{0}\".\n"+
         "{1}" ), PathForMessage( targetDir ), e.Message );
   }
   string[] directories;
   try
   {
      directories = Directory.GetDirectories( AdducePath( sourceDir ) );
   }
   catch (Exception e)
   {
      CON.PrintOperation( HLocal.TEXT(
         "Querying subfolder list",
         "Запрос списка подпапок" ));
      throw OpFailedExceptionCreator.Create( HLocal.TEXT(
         "Can not obtain subfolder list for \"{0}\".\n"+
         "{1}",
         "Не удаётся получить список вложенных папок для \"{0}\".\n"+
         "{1}" ), PathForMessage( sourceDir ), e.Message );
   }
   foreach (string directory in directories)
   {
      string dirName = Path.GetFileName( directory );
      DoProcessFolder( directory, Path.Combine(targetDir,dirName), null );
   }
   string[] files;
   try
   {
      files = Directory.GetFiles( AdducePath( sourceDir ) );
   }
   catch (Exception e)
   {
      throw OpFailedExceptionCreator.Create( HLocal.TEXT(
         "Can not obtain file list for folder: \"{0}\".\n"+
         "{1}",
         "Не удаётся получить список файлов для папки: \"{0}\".\n"+
         "{1}" ), PathForMessage( sourceDir ), e.Message );
   }
   Array.Sort( files, new CaseInsensitiveComparer() );
   foreach (string file in files)
   {
      string
         fileName = Path.GetFileName( file ),
         extension = Path.GetExtension( fileName );
      switch ( ConvertDirection )
      {
      case ConvertDirection.LnkToTxt:
         if ( extension.ToLower()==".lnk" )
         {
            if ( ProcessFile( file, Path.Combine( targetDir, fileName+".txt" ) ) )
               continue;
            fileName += ".unsuccess";
         }
         break;
      case ConvertDirection.TxtToLnk:
         if ( extension.ToLower()==".txt" )
         {
            string fileNameWithoutExt = Path.GetFileNameWithoutExtension( fileName );
            if ( Path.GetExtension( fileNameWithoutExt ).ToLower() == ".lnk" )
            {
               ProcessFile( file, Path.Combine( targetDir, fileNameWithoutExt ) );
               continue;
            }
         }
         else
            if ( extension.ToLower()==".unsuccess" )
            {
               string origFileName = Path.GetFileNameWithoutExtension( fileName );
               if ( Path.GetExtension( origFileName ).ToLower()==".lnk" )
                  fileName = origFileName;
            }
         break;
      default:
         throw HAssertionFailure.DEAD_BRANCH();
      }
      ProcessFile( file, Path.Combine( targetDir, fileName ), true );
   }
}

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

} // LnkConverter
