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

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

//**************************************************************************************************
partial class HOps {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

public static bool TrueCondition<T>([HOptional] T value) => true;
public static bool FalseCondition<T>([HOptional] T value) => false;

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

public static bool IsDefaultValue<T>(T value) where T: struct
{
   return value.Equals( default(T) );
}

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

public static T Exchange<T>(ref T operand,T value)
{
   T prev=operand; operand=value; return prev;
}

public static T NullExchange<T>(ref T operand) where T: class
{
   return Exchange(ref operand,null);
}

public static T DefaultExchange<T>(ref T operand) where T: struct
{
   return Exchange(ref operand,default(T));
}

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

public static void Swap<T>(ref T operand_1,ref T operand_2)
{
   T temp=operand_1; operand_1=operand_2; operand_2=temp;
}

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

public static T IsNullSubstitution<T>(T value,T subst)
{
   return value!=null ? value : subst;
}

public static T SubstituteIfNull<T>(ref T operand,T subst)
{
   return operand!=null ? operand : operand=subst;
}

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

public static T DefaultValueSubstitution<T>(T value,T subst) where T: struct
{
   return XValueSubstitution(value,default(T),subst);
}

public static T SubstituteDefaultValue<T>(ref T operand,T subst) where T: struct
{
   return SubstituteXValue(ref operand,default(T),subst);
}

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

public static T XValueSubstitution<T>(T value,T xValue,T subst)
{
   return !object.Equals(value,xValue) ? value : subst;
}

public static T SubstituteXValue<T>(ref T operand,T xValue,T subst)
{
   return !object.Equals(operand,xValue) ? operand : operand=subst;
}

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

/// <exception cref="ArgumentNullException" />
public static T Min<T>(T value_1,T value_2) where T: IComparable
{
   HArgChecking.VerifyNotNulls( value_1, value_2 );
   return value_1.CompareTo(value_2)<=0 ? value_1 : value_2;
}

/// <exception cref="ArgumentNullException" />
public static T Max<T>(T value_1,T value_2) where T: IComparable
{
   HArgChecking.VerifyNotNulls( value_1, value_2 );
   return value_1.CompareTo(value_2)>=0 ? value_1 : value_2;
}

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

/// <exception cref="ArgumentNullException" />
public static bool AccountMin<T>(ref T min,T value) where T: IComparable
{
   HArgChecking.VerifyNotNulls( min, value );
   if ( value.CompareTo( min ) < 0 )
      { min = value; return true; }
   return false;
}

/// <exception cref="ArgumentNullException" />
public static bool AccountMax<T>(ref T max,T value) where T: IComparable
{
   HArgChecking.VerifyNotNulls( max, value );
   if ( value.CompareTo( max ) > 0 )
      { max = value; return true; }
   return false;
}

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

public static bool IsBetween<T>(T value,T lowerBound,T upperBound) where T: IComparable<T>
{
   return value.CompareTo(lowerBound)>=0 && value.CompareTo(upperBound)<=0;
}

public static bool IsExBetween<T>(T value,T lowerBound,T upperBound) where T: IComparable<T>
{
   return value.CompareTo(lowerBound)>0 && value.CompareTo(upperBound)<0;
}

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

public static bool IsOneOf<T>([HOptional] T value,params T[] values)
{
   return IsOneOf(null,value,values);
}

public static int IndexOf<T>([HOptional] T value,params T[] values)
{
   return IndexOf(null,value,values);
}

public static int StrictIndexOf<T>([HOptional] T value,params T[] values)
{
   return StrictIndexOf(null,value,values);
}

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

public static bool IsOneOf<T>( [HOptional] HEqualsCallback<T> equalsCallback,
                               [HOptional] T value, params T[] values )
{
   HArgChecking.VerifyNotNull( values );
   return
      IndexOf(equalsCallback,value,values) !=
      HArray.NotFoundElementIndexOf( values );
}

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

public static int StrictIndexOf<T>( [HOptional] HEqualsCallback<T> equalsCallback,
                                    [HOptional] T value, params T[] values )
{
   int idx = IndexOf(equalsCallback,value,values);
   if ( idx == HArray.NotFoundElementIndexOf( values ) )
      throw new HElementNotFoundException();
   return idx;
}

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

/// <exception cref="InvalidOperationException" />
public static T ValueOrInvalidOperation<T>(T value) where T: class
{
   if ( value != null ) return value;
   throw new InvalidOperationException( "Value is null." );
}

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

public static void ForEach<T>(T[] array,HEnumerationCallback<T> procedure)
{
   HArgChecking.VerifyNotNulls( array );
   HArgChecking.VerifyNotNull( procedure );
   for (int idx=array.GetLowerBound(0); idx<=array.GetUpperBound(0); idx++)
      procedure( array[ idx ] );
}

public static bool ForEach<T>(T[] array,HContinueEnumerationCallback<T> procedure)
{
   HArgChecking.VerifyNotNulls( array );
   HArgChecking.VerifyNotNull( procedure );
   for (int idx=array.GetLowerBound(0); idx<=array.GetUpperBound(0); idx++)
      if ( !procedure( array[ idx ] ) )
         return false;
   return true;
}

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

public static void ForEach<T>(T[] array,HEnumerationWithIndexCallback<T> procedure)
{
   HArgChecking.VerifyNotNulls( array );
   HArgChecking.VerifyNotNull( procedure );
   for (int idx=array.GetLowerBound(0); idx<=array.GetUpperBound(0); idx++)
      procedure( array[ idx ], idx );
}

public static bool ForEach<T>(T[] array,HContinueEnumerationWithIndexCallback<T> procedure)
{
   HArgChecking.VerifyNotNulls( array );
   HArgChecking.VerifyNotNull( procedure );
   for (int idx=array.GetLowerBound(0); idx<=array.GetUpperBound(0); idx++)
      if ( !procedure( array[ idx ], idx ) )
         return false;
   return true;
}

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

public static void BackwardForEach<T>(T[] array,HEnumerationCallback<T> procedure)
{
   HArgChecking.VerifyNotNulls( array );
   HArgChecking.VerifyNotNull( procedure );
   for (int idx=array.GetUpperBound(0); idx>=array.GetLowerBound(0); idx--)
      procedure( array[ idx ] );
}

public static bool BackwardForEach<T>(T[] array,HContinueEnumerationCallback<T> procedure)
{
   HArgChecking.VerifyNotNulls( array );
   HArgChecking.VerifyNotNull( procedure );
   for (int idx=array.GetUpperBound(0); idx>=array.GetLowerBound(0); idx--)
      if ( !procedure( array[ idx ] ) )
         return false;
   return true;
}

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

public static void BackwardForEach<T>(T[] array,HEnumerationWithIndexCallback<T> procedure)
{
   HArgChecking.VerifyNotNulls( array );
   HArgChecking.VerifyNotNull( procedure );
   for (int idx=array.GetUpperBound(0); idx>=array.GetLowerBound(0); idx--)
      procedure( array[ idx ], idx );
}

public static bool BackwardForEach<T>(T[] array,HContinueEnumerationWithIndexCallback<T> procedure)
{
   HArgChecking.VerifyNotNulls( array );
   HArgChecking.VerifyNotNull( procedure );
   for (int idx=array.GetUpperBound(0); idx>=array.GetLowerBound(0); idx--)
      if ( !procedure( array[ idx ], idx ) )
         return false;
   return true;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // HOps
//**************************************************************************************************

} // CommonHelpers (.WASM)
