//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
// CommonHelpers satellite library | Author: Sergei Y.Kitáev
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
using System;
using System.IO;
using System.ComponentModel;

#if !WASM
namespace CommonHelpers {
#else
namespace CommonHelpers.WASM {
#endif

//**************************************************************************************************
partial class HFile {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/// <exception cref="ArgumentNullException" />
/// <exception cref="HIncorrectFilePathException" />
internal static void VerifyPath(string path,bool? directory)
{
   HArgChecking.VerifyNotNull( path );
   try
   {
      HPath.VerifyNotContainsWildcardChars( HPath.WithoutLongNamePrefix( path ) );
   }
   catch (HIncorrectFilePathException e)
   {
      throw new HIncorrectFilePathException(string.Format(
         "{0}\n"+
         "{1}: \"{2}\".",
         e.Message,
         directory.HasValue ? (directory.Value ? Verbose.Folder : Verbose.File) : Verbose.Path,
         HPath.GetFullPathIfPossible( path ) ));
   }
}

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

/// <exception cref="ArgumentNullException" />
internal static bool CheckExists(string path,bool? directory,out Exception error)
{
   HArgChecking.VerifyNotNull( path );
   return HOps.Try(delegate{ VerifyExists( path, directory ); },out error);
}

/// <exception cref="ArgumentNullException" />
internal static bool CheckNotExists(string path,bool? directory,out Exception error)
{
   HArgChecking.VerifyNotNull( path );
   try { VerifyNotExists( path, directory ); }
   catch (Exception e) {
      error = e is HUnsuccessException ? null : e;
      return false; }
   error = null; return true;
}

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

/// <exception cref="ArgumentNullException" />
/// <exception cref="HOperationFailedException" />
internal static bool CheckIfExistsOrThrow(string path,bool? directory)
{
   HArgChecking.VerifyNotNull( path );
   Exception err;
   if ( CheckExists( path, directory, out err ) )
      return true;
   if ( err is FileNotFoundException )
      return false;
   if (err is ArgumentException)
      CreateOpFailedException_CantCheckIfExists( err, path, directory );
   if (err is IOException)
      throw HOpFailedExceptionCreator.Create(
         "{0}\n"+
         Verbose.Path+": \"{1}\".",
         err.Message, HPath.GetFullPathIfPossible( path ) );
   throw HOpFailedExceptionCreator.Create( err );
}

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

/// <exception cref="ArgumentNullException" />
/// <exception cref="ArgumentException" />
/// <exception cref="FileNotFoundException" />
/// <exception cref="HIncorrectFilePathException" />
internal static void VerifyExists(string path,bool? directory)
{
   VerifyPath( path, directory );

   var attributes = File.GetAttributes( path );

   if (directory.HasValue)
   {
      bool isDirectory = (attributes & FileAttributes.Directory) != 0;

      if (directory.Value && !isDirectory || !directory.Value && isDirectory)
         throw CreateFileNotFoundException( path, directory.Value );
   }
}

/// <exception cref="ArgumentNullException" />
/// <exception cref="ArgumentException" />
/// <exception cref="HIncorrectFilePathException" />
/// <exception cref="HUnsuccessException" />
internal static void VerifyNotExists(string path,bool? directory)
{
   VerifyPath( path, directory );

   FileAttributes attributes;

   try
   {
      attributes = File.GetAttributes( path );
   }
   catch (FileNotFoundException)
   {
      return;
   }

   bool isDirectory = (attributes & FileAttributes.Directory) != 0;

   if (!directory.HasValue)
      throw CreateUnsuccessException_FileNameIsOccupied( path, isDirectory );

   if (directory.Value && isDirectory || !directory.Value && !isDirectory)
      throw CreateUnsuccessException_FileNameIsOccupied( path, directory.Value );
}

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

/// <exception cref="ArgumentNullException" />
/// <exception cref="ArgumentException" />
/// <exception cref="FileNotFoundException" />
/// <exception cref="HIncorrectFilePathException" />
internal static bool ExamineIsReadonly(string path,bool directory)
{
   VerifyPath( path, directory );
   return (GetAttributes(path,directory) & FileAttributes.ReadOnly) != 0;
}

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

/// <exception cref="ArgumentNullException" />
/// <exception cref="ArgumentException" />
/// <exception cref="FileNotFoundException" />
/// <exception cref="HIncorrectFilePathException" />
/// <exception cref="HOperationFailedException" />
internal static void SetReadonlyAttribute(string path,bool directory)
{
   VerifyPath( path, directory );
   ModifyAttributes( path, directory, FileAttributes.ReadOnly, 0 );
}

/// <exception cref="ArgumentNullException" />
/// <exception cref="ArgumentException" />
/// <exception cref="FileNotFoundException" />
/// <exception cref="HIncorrectFilePathException" />
/// <exception cref="HOperationFailedException" />
internal static void ResetReadonlyAttribute(string path,bool directory)
{
   VerifyPath( path, directory );
   ModifyAttributes( path, directory, 0, FileAttributes.ReadOnly );
}

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

/// <exception cref="ArgumentNullException" />
/// <exception cref="ArgumentException" />
/// <exception cref="FileNotFoundException" />
/// <exception cref="HIncorrectFilePathException" />
internal static FileAttributes GetAttributes(string path,bool directory)
{
   VerifyPath( path, directory );

   var attributes = File.GetAttributes( path );

   bool isDirectory = (attributes & FileAttributes.Directory) != 0;

   if (directory && !isDirectory || !directory && isDirectory)
      throw CreateFileNotFoundException( path, directory );

   return attributes;
}

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

/// <exception cref="ArgumentNullException" />
/// <exception cref="ArgumentException" />
/// <exception cref="FileNotFoundException" />
/// <exception cref="HIncorrectFilePathException" />
/// <exception cref="HOperationFailedException" />
internal static void SetAttributes(string path,bool directory,FileAttributes attributes)
{
   VerifyPath( path, directory );
   try
   {
      File.SetAttributes( path, attributes );
      if ( File.GetAttributes( path ) != attributes )
         throw CreateOpFailedException_CantSetAttributes( path, directory );
   }
   catch (FileNotFoundException)
   {
      throw CreateFileNotFoundException( path, directory );
   }
}

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

/// <exception cref="ArgumentNullException" />
/// <exception cref="ArgumentException" />
/// <exception cref="FileNotFoundException" />
/// <exception cref="HIncorrectFilePathException" />
/// <exception cref="HOperationFailedException" />
internal static FileAttributes AddAttributes(string path,bool directory,FileAttributes attributes)
{
   return ModifyAttributes( path, directory, attributes, 0 );
}

/// <exception cref="ArgumentNullException" />
/// <exception cref="ArgumentException" />
/// <exception cref="FileNotFoundException" />
/// <exception cref="HIncorrectFilePathException" />
/// <exception cref="HOperationFailedException" />
internal static FileAttributes RemoveAttributes
(
   string path, bool directory, FileAttributes attributes
)
{
   return ModifyAttributes( path, directory, 0, attributes );
}

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

/// <exception cref="ArgumentNullException" />
/// <exception cref="ArgumentException" />
/// <exception cref="FileNotFoundException" />
/// <exception cref="HIncorrectFilePathException" />
/// <exception cref="HOperationFailedException" />
internal static FileAttributes ModifyAttributes( string path, bool directory,
                                                 FileAttributes attributesToAdd,
                                                 FileAttributes attributesToRemove )
{
   VerifyPath( path, directory );
   if ( (attributesToRemove & attributesToAdd) !=0 )
      throw new ArgumentException(
         Verbose.FILE_ATTRIBUTES_TO_SET_INTERSECT_WITH_ATTRIBUTES_TO_REMOVE );
   try
   {
      FileAttributes
         initialAttributes = GetAttributes( path, directory ),
         modifiedAttributes = ( initialAttributes | attributesToAdd ) & ~attributesToRemove;

      if ( initialAttributes == modifiedAttributes )
         return initialAttributes;

      File.SetAttributes( path, modifiedAttributes );

      if ( File.GetAttributes( path ) != modifiedAttributes )
         throw CreateOpFailedException_CantSetAttributes( path, directory );

      return modifiedAttributes;
   }
   catch (FileNotFoundException)
   {
      throw CreateFileNotFoundException( path, directory );
   }
}

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

/// <exception cref="ArgumentNullException" />
/// <exception cref="ArgumentException" />
/// <exception cref="FileNotFoundException" />
/// <exception cref="HOperationFailedException" />
/// <exception cref="HIncorrectFilePathException" />
/// <exception cref="HUnsuccessException" />
internal static void Move(string sourcePath,string targetPath,bool directory)
{
   HOpFailedExceptionCreator.Do(delegate{
      VerifyExists( sourcePath, directory );
      VerifyNotExists( targetPath, null );
   });
#if WIN32
   if ( Win32_Core.MoveFile( sourcePath, targetPath ) == 0 )
      throw HOpFailedExceptionCreator.Create( directory ?
         Verbose.CAN_NOT_RENAME_FOLDER__0__SOURCE_FOLDER_1__TARGET_FOLDER_2 :
         Verbose.CAN_NOT_RENAME_FILE__0__SOURCE_FILE_1__TARGET_FILE_2,
         HWin32Error.LastErrorMessage,
         HPath.GetFullPathIfPossible( sourcePath ),
         HPath.GetFullPathIfPossible( targetPath ) );
#else // !WIN32:
   if ( directory )
      Directory.Move( sourcePath, targetPath );
   else
      File.Move( sourcePath, targetPath );
#endif // !WIN32
}

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

/// <exception cref="ArgumentNullException" />
internal static FileNotFoundException CreateFileNotFoundException(string path,bool directory)
{
   return
      new FileNotFoundException(string.Format(
         directory ?
            Verbose.FOLDER_NOT_FOUND_0 :
            Verbose.FILE_NOT_FOUND_0,
         HPath.GetFullPathIfPossible( path ) ));
}

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

/// <exception cref="ArgumentNullException" />
static HOperationFailedException CreateOpFailedException_CantCheckIfExists
(
   Exception error, string path, bool? directory
)
{
   HArgChecking.VerifyNotNulls( error, path );
   string messageFmt_0 = directory.HasValue ?
      ( directory.Value ?
      Verbose.CAN_NOT_CHECK_IF_FOLDER_EXISTS_0 :
      Verbose.CAN_NOT_CHECK_IF_FILE_EXISTS_0 ) :
      Verbose.CAN_NOT_CHECK_IF_FILE_OBJECT_EXISTS_0;
   return HOpFailedExceptionCreator.Create(
      messageFmt_0+"\n"+
      "{1}", HPath.GetFullPathIfPossible( path ), error.Message );
}

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

/// <exception cref="ArgumentNullException" />
static HUnsuccessException CreateUnsuccessException_FileNameIsOccupied
(
   string path, bool byDirectory
)
{
   return
      HUnsuccessExceptionCreator.Create(
         byDirectory ?
            Verbose.FILE_NAME_IS_OCCUPIED_BY_EXISTING_FOLDER_0 :
            Verbose.FILE_NAME_IS_OCCUPIED_BY_EXISTING_FILE_0,
         HPath.GetFullPathIfPossible( path ) );
}

/// <exception cref="ArgumentNullException" />
static HOperationFailedException CreateOpFailedException_CantSetAttributes
(
   string path, bool directory
)
{
   return
      HOpFailedExceptionCreator.Create( directory ?
         Verbose.CAN_NOT_CORRECTLY_SET_SOME_OF_ATTRIBUTES_TO_FOLDER_0 :
         Verbose.CAN_NOT_CORRECTLY_SET_SOME_OF_ATTRIBUTES_TO_FILE_0,
         HPath.GetFullPathIfPossible( path ) );
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // HFile
//**************************************************************************************************

} // CommonHelpers (.WASM)
