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

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

//**************************************************************************************************
/// <summary>
/// </summary>
public static partial class HPath {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

public const string
   LongNamePrefix = @"\\?\",
   LongNamePrefixWithUNC = @"\\?\UNC\";

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

public static char[] WildcardChars
{
   get { return new char[]{ '*', '?' }; }
}
public static char[] SlashChars
{
   get { return new char[]{ '\\', '/' }; }
}
public static char[] DirectorySeparatorChars
{
   get { return new char[]{ Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }; }
}
public static string DirectorySeparator
{
   get { return Path.DirectorySeparatorChar.ToString(); }
}
public static string NetworkPathPrefix
{
   get { return new string( Path.DirectorySeparatorChar, 2 ); }
}

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

public static bool IsWildcardChar(char ch)
{
   return HOps.IsOneOf( ch, WildcardChars );
}
public static bool IsSlashChar(char ch)
{
   return HOps.IsOneOf( ch, SlashChars );
}
public static bool IsDirectorySeparatorChar(char ch)
{
   return HOps.IsOneOf( ch, DirectorySeparatorChars );
}

/// <exception cref="ArgumentNullException" />
public static bool IsDriveLetterPath(string path)
{
   path = WithoutLongNamePrefix( path );
   return path.Length >= 2 && HChar.IsEnglishLetter( path[ 0 ] ) && path[ 1 ] == ':';
}
/// <exception cref="ArgumentNullException" />
public static bool IsDirSeparatorHeadedPath(string path)
{
   return HString.StartsWith( WithoutLongNamePrefix( path ), DirectorySeparatorChars );
}
/// <exception cref="ArgumentNullException" />
public static bool IsNetworkPath(string path)
{
   path = WithoutLongNamePrefix( path );
   return path.Length >= 2 &&
      IsDirectorySeparatorChar( path[ 0 ] ) &&
      IsDirectorySeparatorChar( path[ 1 ] );
}

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

public static string GetDirectorySeparator(bool useAltSeparatorChar)
{
   return(
      useAltSeparatorChar ?
         Path.AltDirectorySeparatorChar :
         Path.DirectorySeparatorChar
   ).ToString();
}

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

/// <exception cref="ArgumentNullException" />
public static bool ContainsVolumeSeparatorChar(string path)
{
   HArgChecking.VerifyNotNull( path );
   return path.IndexOf( Path.VolumeSeparatorChar )>=0;
}
/// <exception cref="ArgumentNullException" />
public static bool ContainsDirectorySeparatorChar(string path)
{
   HArgChecking.VerifyNotNull( path );
   return
      path.IndexOf( Path.DirectorySeparatorChar    )>=0 ||
      path.IndexOf( Path.AltDirectorySeparatorChar )>=0;
}

/// <exception cref="ArgumentNullException" />
public static bool ContainsPathSeparatorChar(string path)
{
   HArgChecking.VerifyNotNull( path );
   return path.IndexOf( Path.PathSeparator )>=0;
}

/// <exception cref="ArgumentNullException" />
public static bool ContainsWildcardChar(string path)
{
   HArgChecking.VerifyNotNull( path );
   return path.IndexOfAny( WildcardChars )>=0;
}

/// <exception cref="ArgumentNullException" />
public static bool ContainsInvalidFileNameChar(string path)
{
   HArgChecking.VerifyNotNull( path );
   return path.IndexOfAny( Path.GetInvalidFileNameChars() )>=0;
}

/// <exception cref="ArgumentNullException" />
public static bool ContainsInvalidPathChar(string path)
{
   HArgChecking.VerifyNotNull( path );
   return path.IndexOfAny( Path.GetInvalidPathChars() )>=0;
}

/// <exception cref="ArgumentNullException" />
public static bool StartsWithSlash(string path)
{
   HArgChecking.VerifyNotNull( path );
   return path.Length > 0 && HOps.IsOneOf( path[ 0 ], SlashChars );
}
/// <exception cref="ArgumentNullException" />
public static bool EndsWithSlash(string path)
{
   HArgChecking.VerifyNotNull( path );
   return path.Length > 0 && HOps.IsOneOf( HString.LastChar( path ), SlashChars );
}

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

/// <exception cref="ArgumentNullException" />
public static bool HasTrailingDirSeparator(string path)
{
   HArgChecking.VerifyNotNull( path );
   if ( path == "" )
      return false;
   char
      tailChar = path[ path.Length-1 ];
   return
      tailChar ==
         Path.DirectorySeparatorChar ||
         tailChar==Path.AltDirectorySeparatorChar;
}

/// <exception cref="ArgumentNullException" />
public static string AppendTrailingDirSeparator(string path)
{
   return AppendTrailingDirSeparator(path,false);
}
/// <exception cref="ArgumentNullException" />
public static string AppendTrailingDirSeparator(string path,bool useAltSeparatorChar)
{
   HArgChecking.VerifyNotNull( path );
   var dirSeparator =
      GetDirectorySeparator( useAltSeparatorChar );
   if ( path == "" )
      return "."+dirSeparator;
   return HasTrailingDirSeparator( path ) ?
      path : path+dirSeparator;
}

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

/// <exception cref="ArgumentNullException" />
public static string NormalizeDirSeparators(string path)
{
   HArgChecking.VerifyNotNull( path );
   var sb = new StringBuilder();
   foreach (char ch in path)
      sb.Append( ch == Path.AltDirectorySeparatorChar ? Path.DirectorySeparatorChar : ch );
   return sb.ToString();
}

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

/// <exception cref="ArgumentNullException" />
/// <exception cref="HIncorrectFilePathException" />
public static void VerifyNotContainsWildcardChars(string path)
{
   HArgChecking.VerifyNotNull( path );
   if ( ContainsWildcardChar( path ) )
      throw new HIncorrectFilePathException(
         Verbose.PATH_TO_SINGLE_FILE_OBJECT_MUST_NOT_CONTAIN_WILDCARD_CHARACTERS );
}

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

/// <exception cref="ArgumentNullException" />
public static bool HasLongNamePrefix(string path)
{
   HArgChecking.VerifyNotNull( path );
   return path.StartsWith( LongNamePrefix, true, CultureInfo.InvariantCulture );
}
/// <exception cref="ArgumentNullException" />
public static bool HasLongNamePrefixWithUNC(string path)
{
   HArgChecking.VerifyNotNull( path );
   return path.StartsWith( LongNamePrefixWithUNC, true, CultureInfo.InvariantCulture );
}

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

/// <exception cref="ArgumentException" />
/// <exception cref="ArgumentNullException" />
public static string ToLong(string path)
{
   HArgChecking.VerifyNotNull( path );
   if ( HasLongNamePrefix( path ) )
      return path;
   if ( path == "" || IsDriveLetterPath( path ) )
      return LongNamePrefix + path;
   if ( IsNetworkPath( path ) )
      return LongNamePrefixWithUNC + path.Substring( 2 );
   if ( IsDirSeparatorHeadedPath( path ) )
      return LongNamePrefix + path.Substring( 1 );
   string currentFolderPath = Directory.GetCurrentDirectory();
   return IsNetworkPath( currentFolderPath ) ?
      LongNamePrefixWithUNC + currentFolderPath.Substring( 2 ) +
      Path.DirectorySeparatorChar + path :
      IsDirSeparatorHeadedPath( currentFolderPath ) ?
         LongNamePrefix + currentFolderPath.Substring( 1 ) + Path.DirectorySeparatorChar + path :
         LongNamePrefix + currentFolderPath + Path.DirectorySeparatorChar + path;
}

/// <exception cref="ArgumentNullException" />
public static string WithoutLongNamePrefix(string path)
{
   HArgChecking.VerifyNotNull( path );
   return HasLongNamePrefixWithUNC( path ) ?
      NetworkPathPrefix + path.Substring( LongNamePrefixWithUNC.Length ) :
      HasLongNamePrefix( path ) ? path.Substring( LongNamePrefix.Length ) : path;
}

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

/// <exception cref="ArgumentNullException" />
public static string GetFullPathIfPossible(string path)
{
   string fullPath;
   return TryGetFullPath( path, out fullPath ) ? fullPath : path;
}

/// <exception cref="ArgumentNullException" />
public static bool TryGetFullPath(string path,out string fullPath)
{
   HArgChecking.VerifyNotNull( path );
   if ( HasLongNamePrefix( path ) )
   {
      fullPath = path;
      return true;
   }
   fullPath = null;
   try { fullPath = Path.GetFullPath( path ); } catch {}
   return fullPath != null;
}

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

/// <exception cref="ArgumentNullException" />
public static string GetRelativePathIfPossible(string path)
{
   return GetRelativePathIfPossible( path, false );
}
/// <exception cref="ArgumentNullException" />
public static string GetRelativePathIfPossible(string path,bool removeLongPrefixAnyway)
{
   string relativePath;
   return TryGetRelativePath( path, out relativePath ) ? relativePath :
      removeLongPrefixAnyway ? WithoutLongNamePrefix( path ) : path;
}

/// <exception cref="ArgumentNullException" />
public static bool TryGetRelativePath(string path,out string relativePath)
{
   HArgChecking.VerifyNotNull( path );
   relativePath = null;
   string currentFolderPath = Directory.GetCurrentDirectory();
   int cfpl = currentFolderPath.Length;
   if ( cfpl == 0 ) return false;
   path = NormalizeDirSeparators( WithoutLongNamePrefix( path ) );
   if ( path.StartsWith( currentFolderPath, true, CultureInfo.InvariantCulture ) )
   {
      if ( path.Length == cfpl )
      {
         relativePath = "";
         return true;
      }
      if ( path.Length > cfpl && IsDirectorySeparatorChar( path[ cfpl ] ) )
      {
         int pos = cfpl + 1;
         HString.SkipChars( path, DirectorySeparatorChars, ref pos );
         relativePath = path.Substring( pos );
         return true;
      }
   }
   return false;
}

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

static HPath()
{
   CommonHelpers_Core.Access();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // HPath
//**************************************************************************************************

} // CommonHelpers (.WASM)
