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

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

//**************************************************************************************************
/// <summary>
/// </summary>
public static partial class HString {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/*
public static bool IsNullOrWhiteSpace([HOptional] string str)
{
   if ( str == null )
      return true;
   foreach (char ch in str)
      if ( !char.IsWhiteSpace( ch ) )
         return false;
   return true;
}
*/
//--------------------------------------------------------------------------------------------------

public static bool Equals([HOptional] string str_1,[HOptional] string str_2)
{
   return Equals( str_1, str_2, false );
}
public static bool Equals([HOptional] string str_1,[HOptional] string str_2,bool ignoreCase)
{
   return CompareOrdinal( str_1, str_2, ignoreCase ) == 0;
}

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

public static int CompareOrdinal([HOptional] string str_1,[HOptional] string str_2)
{
   return CompareOrdinal( str_1, str_2, false );
}
public static int CompareOrdinal( [HOptional] string str_1,
                                  [HOptional] string str_2,
                                  bool ignoreCase )
{
   return
      string.Compare( str_1, str_2,
         ignoreCase ?
            StringComparison.OrdinalIgnoreCase :
            StringComparison.Ordinal );
}

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

public static int CompareInvariant([HOptional] string str_1,[HOptional] string str_2)
{
   return CompareInvariant(str_1,str_2,false);
}
public static int CompareInvariant( [HOptional] string str_1,
                                    [HOptional] string str_2,
                                    bool ignoreCase )
{
   return
      string.Compare( str_1, str_2,
         ignoreCase ?
            StringComparison.InvariantCultureIgnoreCase :
            StringComparison.InvariantCulture );
}

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

public static bool IsOneOf([HOptional] string str,params string[] strings)
{
   return IsOneOf(false,str,strings);
}
public static bool IsOneOf(bool ignoreCase,[HOptional] string str,params string[] strings)
{
   return IsOneOf(
      delegate (string s1,string s2)
         { return Equals(s1,s2,ignoreCase); },
      str, strings );
}

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

public static int ListIndexOf([HOptional] string str,params string[] strings)
{
   return ListIndexOf(false,str,strings);
}
public static int ListIndexOf(bool ignoreCase,[HOptional] string str,params string[] strings)
{
   return ListIndexOf(
      delegate (string s1,string s2)
         { return Equals(s1,s2,ignoreCase); },
      str, strings );
}

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

public static int StrictListIndexOf([HOptional] string str,params string[] strings)
{
   return StrictListIndexOf(false,str,strings);
}
public static int StrictListIndexOf(bool ignoreCase,[HOptional] string str,params string[] strings)
{
   return StrictListIndexOf(
      delegate (string s1,string s2)
         { return Equals(s1,s2,ignoreCase); },
      str, strings );
}

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

public static string NormilizeCaseByList([HOptional] string str,params string[] strings)
{
   return NormilizeByList(
      delegate (string s1,string s2)
         { return Equals(s1,s2,true); },
      str, strings );
}
public static string StrictNormilizeCaseByList([HOptional] string str,params string[] strings)
{
   return StrictNormilizeByList(
      delegate (string s1,string s2)
         { return Equals(s1,s2,true); },
      str, strings );
}

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

public static bool IsOneOf( [HOptional] HEqualsCallback<string> equalsCallback,
                            [HOptional] string str, params string[] strings )
{
   int idx = ListIndexOf(equalsCallback,str,strings);
   return idx != HArray.NotFoundElementIndexOf( strings );
}

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

public static int ListIndexOf( [HOptional] HEqualsCallback<string> equalsCallback,
                               [HOptional] string str, params string[] strings )
{
   HArgChecking.VerifyNotNull( strings );
   for ( int i=strings.GetLowerBound(0); i<=strings.GetUpperBound(0); i++ )
      if ( equalsCallback!=null ? equalsCallback(str,strings[i]) : Equals(str,strings[i]) )
         return i;
   return HArray.NotFoundElementIndexOf( strings );
}

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

[HStrictResult]
public static int StrictListIndexOf( [HOptional] HEqualsCallback<string> equalsCallback,
                                     [HOptional] string str, params string[] strings )
{
   int idx = ListIndexOf(equalsCallback,str,strings);
   if ( idx == HArray.NotFoundElementIndexOf( strings ) )
      throw new HElementNotFoundException();
   return idx;
}

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

public static string NormilizeByList( [HOptional] HEqualsCallback<string> equalsCallback,
                                      [HOptional] string str, params string[] strings )
{
   int idx = ListIndexOf(equalsCallback,str,strings);
   return idx != HArray.NotFoundElementIndexOf( strings ) ?
      strings[ idx ] : null;
}

[HStrictResult]
public static string StrictNormilizeByList( [HOptional] HEqualsCallback<string> equalsCallback,
                                            [HOptional] string str, params string[] strings )
{
   string result = NormilizeByList(equalsCallback,str,strings);
   if ( result == null )
      throw new HElementNotFoundException();
   return result;
}

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

public static bool IsBlank([HOptional] string str)
{
   if ( str == null )
      return false;
   foreach (char ch in str)
      if ( !char.IsWhiteSpace( ch ) )
         return false;
   return true;
}

public static bool IsSpaceNormalizedName([HOptional] string str)
{
   return str != null && !(
      IsBlank( str ) || StartsWithWhiteSpace( str ) ||
      EndsWithWhiteSpace( str ) || ContainsDoubleWhiteSpace( str ) );
}

//--------------------------------------------------------------------------------------------------
/*
public static bool IsNullOrBlank([HOptional] string str)
{
   return str==null || IsBlank( str );
}
*/
//--------------------------------------------------------------------------------------------------

public static bool StartsWithWhiteSpace([HOptional] string str)
{
   return !string.IsNullOrEmpty( str ) && char.IsWhiteSpace( str[0] );
}
public static bool EndsWithWhiteSpace([HOptional] string str)
{
   return !string.IsNullOrEmpty( str ) && char.IsWhiteSpace( LastChar( str ) );
}
public static bool HasBoundaryWhiteSpace([HOptional] string str)
{
   return StartsWithWhiteSpace( str ) || EndsWithWhiteSpace( str );
}

public static bool ContainsWhiteSpace([HOptional] string str)
{
   if ( str != null )
      foreach (char ch in str)
         if ( char.IsWhiteSpace( ch ) )
            return true;
   return false;
}
public static bool ContainsDoubleWhiteSpace([HOptional] string str)
{
   if ( str != null && str.Length > 1 )
   {
      bool isPrevCharWhiteSpace = char.IsWhiteSpace( str[ 0 ] );
      for (int i=1; i<str.Length; i++)
      {
         bool isWhiteSpace = char.IsWhiteSpace( str[i] );
         if ( isWhiteSpace && isPrevCharWhiteSpace )
            return true;
         isPrevCharWhiteSpace = isWhiteSpace;
      }
   }
   return false;
}

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

/// <exception cref="ArgumentNullException" />
/// <exception cref="ArgumentException "/>
[HStrictResult]
public static char FirstChar(string str)
{
   HArgChecking.VerifyNotNull( str );
   if ( str == "" )
      throw new ArgumentException( "Can not extract first character from empty string." );
   return str[ 0 ];
}
public static char? FirstCharOrNull([HOptional] string str)
{
   return string.IsNullOrEmpty( str ) ? null : (char?)str[ 0 ];
}

/// <exception cref="ArgumentNullException" />
/// <exception cref="ArgumentException" />
[HStrictResult]
public static char LastChar(string str)
{
   HArgChecking.VerifyNotNull( str );
   if ( str == "" )
      throw new ArgumentException( "Can not extract last character from empty string." );
   return str[ str.Length-1 ];
}
public static char? LastCharOrNull([HOptional] string str)
{
   return string.IsNullOrEmpty( str ) ? null : (char?)str[ str.Length-1 ];
}

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

public static bool StartsWith([HOptional] string str,char ch)
{
   return !string.IsNullOrEmpty( str ) && FirstChar( str ) == ch;
}
public static bool StartsWith([HOptional] string str,params char[] chars)
{
   return !string.IsNullOrEmpty( str ) && HArray.Contains( chars, str[ 0 ] );
}

public static bool EndsWith([HOptional] string str,char ch)
{
   return !string.IsNullOrEmpty( str ) && LastChar( str ) == ch;
}
public static bool EndsWith([HOptional] string str,params char[] chars)
{
   return !string.IsNullOrEmpty( str ) && HArray.Contains( chars, LastChar( str ) );
}

public static bool IsEmbracedWith([HOptional] string str,char ch)
{
   return str!=null && str.Length>1 && StartsWith( str, ch ) && EndsWith( str, ch );
}
public static bool IsEmbracedWith([HOptional] string str,params char[] chars)
{
   if ( str == null || str.Length < 2 )
      return false;
   char firstChar = str[ 0 ];
   return LastChar( str )==firstChar && HArray.Contains( chars, firstChar );
}

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

public static string SubstNullOrEmpty([HOptional] string str,string replacement)
{
   HStringArgChecking.VerifyNotNullOrEmpty( replacement );
   return string.IsNullOrEmpty( str ) ? replacement : str;
}
public static string SubstNullOrWhiteSpace([HOptional] string str,string replacement)
{
   HStringArgChecking.VerifyNotNullOrWhiteSpace( replacement );
   return string.IsNullOrWhiteSpace( str ) ? replacement : str;
}

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

[CLSCompliant(false)]
public static string SubstNullOrEmpty([HOptional] ref string str,string replacement)
{
   return str = SubstNullOrEmpty( str, replacement );
}
[CLSCompliant(false)]
public static string SubstNullOrWhiteSpace([HOptional] ref string str,string replacement)
{
   return str = SubstNullOrWhiteSpace( str, replacement );
}

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

public static int SkipChar(string str,char ch,ref int pos)
{
   HArgChecking.VerifyNotNull( str );
   int cnt = 0;
   while ( pos < str.Length && str[ pos ] == ch )
      { pos++; cnt++; }
   return cnt;
}

public static int SkipChars(string str,char[] chars,ref int pos)
{
   HArgChecking.VerifyNotNull( str );
   int cnt = 0;
   while ( pos < str.Length && HOps.IsOneOf( str[ pos ], chars ) )
      { pos++; cnt++; }
   return cnt;
}

public static int SkipWhiteSpaces(string str,ref int pos)
{
   HArgChecking.VerifyNotNull( str );
   int cnt = 0;
   while ( pos < str.Length && char.IsWhiteSpace( str[ pos ] ) )
      { pos++; cnt++; }
   return cnt;
}

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

public static string UndecorateEmbracement([HOptional] string str,char ch)
{
   return UndecorateEmbracement( str, new char[]{ ch } );
}
public static string UndecorateEmbracement([HOptional] string str,params char[] chars)
{
   return IsEmbracedWith( str, chars ) ? str.Substring( 1, str.Length-2 ): str;
}

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

public static char[] ToCharArray([HOptional] string str)
{
   return ToCharArray(str,false);
}

public static char[] ToCharArray([HOptional] string str,bool nullToEmpty)
{
   return str!=null ?
      str.ToCharArray() :
      (nullToEmpty ? new char[0] : null);
}

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

public static string FromCharArray([HOptional] char[] chars)
{
   return FromCharArray(chars,false);
}

public static string FromCharArray([HOptional] char[] chars,bool nullToEmpty)
{
   return chars!=null ?
      new string(chars) :
      (nullToEmpty ? "" : null);
}

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

public static string MakeSeparation<T>([HOptional] params T[] parameters)
{
   return MakeSeparationWith( null, parameters );
}

public static string MakeSeparationWith<T>(char separator,[HOptional] params T[] parameters)
{
   return MakeSeparationWith( separator.ToString(), parameters );
}

public static string MakeSeparationWith<T>( [HOptional] string separator,
                                            [HOptional] params T[] parameters )
{
   if ( parameters == null )
      return "";
   separator = separator ?? _SeparatedStringSeparator_;
   var sb = new StringBuilder();
   bool wasAppended = false;
   foreach (T value in parameters)
      if ( value != null )
      {
         if (wasAppended)
            sb.Append( separator );
         sb.Append( value.ToString() );
         wasAppended = true;
      }
   return sb.ToString();
}

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

/// <exception cref="ArgumentNullException" />
public static string AppendSeparator(string str)
{
   return AppendSeparator( str, null );
}
/// <exception cref="ArgumentNullException" />
public static string AppendSeparator(string str,char separator)
{
   return AppendSeparator( str, separator.ToString() );
}
/// <exception cref="ArgumentNullException" />
public static string AppendSeparator(string str,[HOptional] string separator)
{
   HArgChecking.VerifyNotNull( str );
   return str!="" ? str+HOps.IsNullSubstitution(separator,_SeparatedStringSeparator_) : str;
}

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

/// <exception cref="ArgumentNullException" />
public static void AppendSeparator(StringBuilder sb)
{
   AppendSeparator( sb, null );
}
/// <exception cref="ArgumentNullException" />
public static void AppendSeparator(StringBuilder sb,[HOptional] char separator)
{
   AppendSeparator( sb, separator.ToString() );
}
/// <exception cref="ArgumentNullException" />
public static void AppendSeparator(StringBuilder sb,[HOptional] string separator)
{
   HArgChecking.VerifyNotNull( sb );
   if ( sb.Length > 0 )
      sb.Append( HOps.IsNullSubstitution(separator,_SeparatedStringSeparator_) );
}

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

/// <exception cref="ArgumentNullException" />
public static string AppendLine(ref string str,string line)
{
   return str = HTextBuilder.CombineLines( str, line );
}

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

public static string NullAsEmpty([HOptional] string str)
{
   return str ?? "";
}
public static string BlankAsEmpty([HOptional] string str)
{
   return IsBlank( str ) ? "" : str;
}
public static string NullOrBlankAsEmpty([HOptional] string str)
{
   return str==null || IsBlank( str ) ? "" : str;
}

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

[CLSCompliant(false)]
public static string NullAsEmpty([HOptional] ref string str)
{
   return str = NullAsEmpty( str );
}
[CLSCompliant(false)]
public static string BlankAsEmpty([HOptional] ref string str)
{
   return str = BlankAsEmpty( str );
}
[CLSCompliant(false)]
public static string NullOrBlankAsEmpty([HOptional] ref string str)
{
   return str = NullOrBlankAsEmpty( str );
}

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

public static string ConvertAsText(string multilineStr)
{
   return HTextBuilder.ConvertAsText(multilineStr).ToString();
}
[CLSCompliant(false)]
public static string ConvertAsText(ref string multilineStr)
{
   return multilineStr = ConvertAsText( multilineStr );
}

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

public static string FormatAsText(string multilineStrFmt,params object[] parameters)
{
   return ConvertAsText(string.Format(multilineStrFmt,parameters));
}

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

public static string[] ToLines(string multilineStr)
{
   return HTextBuilder.ToLines(multilineStr).ToArray();
}

public static string[] ToLines(string multilineStrFmt,params object[] parameters)
{
   return ToLines(string.Format(multilineStrFmt,parameters));
}

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

/// <exception cref="ArgumentNullException" />
public static void Trim(ref string str)
{
   HArgChecking.VerifyNotNull( str ); str = str.Trim();
}
/// <exception cref="ArgumentNullException" />
public static void TrimStart(ref string str)
{
   HArgChecking.VerifyNotNull( str ); str = str.TrimStart();
}
/// <exception cref="ArgumentNullException" />
public static void TrimEnd(ref string str)
{
   HArgChecking.VerifyNotNull( str ); str = str.TrimEnd();
}

//==================================================================================================
/*
public static void ForEach(string str,HEnumerationCallback<char> procedure)
{
   HArgChecking.VerifyNotNulls( str, procedure );
   for (int i=0; i<str.Length; i++)
      procedure( str[ i ] );
}

public static bool ForEach(string str,HContinueEnumerationCallback<char> procedure)
{
   HArgChecking.VerifyNotNulls( str, procedure );
   for (int i=0; i<str.Length; i++)
      if ( !procedure( str[ i ] ) )
         return false;
   return true;
}
*/
//--------------------------------------------------------------------------------------------------

public static void ForEach(string str,HEnumerationWithIndexCallback<char> procedure)
{
   HArgChecking.VerifyNotNulls( str, procedure );
   for (int i=0; i<str.Length; i++)
      procedure( str[ i ], i );
}

public static bool ForEach(string str,HContinueEnumerationWithIndexCallback<char> procedure)
{
   HArgChecking.VerifyNotNulls( str, procedure );
   for (int i=0; i<str.Length; i++)
      if ( !procedure( str[ i ], i ) )
         return false;
   return true;
}

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

public static void BackwardForEach(string str,HEnumerationCallback<char> procedure)
{
   HArgChecking.VerifyNotNulls( str, procedure );
   for (int i=str.Length-1; i>=0; i--)
      procedure( str[ i ] );
}

public static bool BackwardForEach(string str,HContinueEnumerationCallback<char> procedure)
{
   HArgChecking.VerifyNotNulls( str, procedure );
   for (int i=str.Length-1; i>=0; i--)
      if ( !procedure( str[ i ] ) )
         return false;
   return true;
}

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

public static void BackwardForEach(string str,HEnumerationWithIndexCallback<char> procedure)
{
   HArgChecking.VerifyNotNulls( str, procedure );
   for (int i=str.Length-1; i>=0; i--)
      procedure( str[ i ], i );
}

public static bool BackwardForEach( string str,
                                    HContinueEnumerationWithIndexCallback<char> procedure )
{
   HArgChecking.VerifyNotNulls( str, procedure );
   for (int i=str.Length-1; i>=0; i--)
      if ( !procedure( str[ i ], i ) )
         return false;
   return true;
}

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

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

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

const string
   _SeparatedStringSeparator_ = ", ";

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // HString
//**************************************************************************************************

} // CommonHelpers (.WASM)
