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

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

//**************************************************************************************************
partial class HArray2D {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

public static void ForEach<T>( T[,] array, int dimension, int subarrayIdx,
                               HEnumerationCallback<T> procedure )
{
   ForEachEx( array, dimension, subarrayIdx, procedure, null, null, false );
}

public static void ForEach<T>( T[,] array, int dimension, int subarrayIdx,
                               HEnumerationCallback<T> procedure,
                               int? startIdx )
{
   ForEachEx( array, dimension, subarrayIdx, procedure, startIdx, null, false );
}

public static void ForEach<T>( T[,] array, int dimension, int subarrayIdx,
                               HEnumerationCallback<T> procedure,
                               int? startIdx, int? count )
{
   ForEachEx( array, dimension, subarrayIdx, procedure, startIdx, count, false );
}

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

public static void BackwardForEach<T>( T[,] array, int dimension, int subarrayIdx,
                                       HEnumerationCallback<T> procedure )
{
   ForEachEx( array, dimension, subarrayIdx, procedure, null, null, true );
}

public static void BackwardForEach<T>( T[,] array, int dimension, int subarrayIdx,
                                       HEnumerationCallback<T> procedure,
                                       int? startIdx )
{
   ForEachEx( array, dimension, subarrayIdx, procedure, startIdx, null, true );
}

public static void BackwardForEach<T>( T[,] array, int dimension, int subarrayIdx,
                                       HEnumerationCallback<T> procedure,
                                       int? startIdx, int? count )
{
   ForEachEx( array, dimension, subarrayIdx, procedure, startIdx, count, true );
}

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

public static bool ForEach<T>( T[,] array, int dimension, int subarrayIdx,
                               HContinueEnumerationCallback<T> procedure )
{
   return ForEachEx( array, dimension, subarrayIdx, procedure, null, null, false );
}

public static bool ForEach<T>( T[,] array, int dimension, int subarrayIdx,
                               HContinueEnumerationCallback<T> procedure,
                               int? startIdx )
{
   return ForEachEx( array, dimension, subarrayIdx, procedure, startIdx, null, false );
}

public static bool ForEach<T>( T[,] array, int dimension, int subarrayIdx,
                               HContinueEnumerationCallback<T> procedure,
                               int? startIdx, int? count )
{
   return ForEachEx( array, dimension, subarrayIdx, procedure, startIdx, count, false );
}

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

public static bool BackwardForEach<T>( T[,] array, int dimension, int subarrayIdx,
                                       HContinueEnumerationCallback<T> procedure )
{
   return ForEachEx( array, dimension, subarrayIdx, procedure, null, null, true );
}

public static bool BackwardForEach<T>( T[,] array, int dimension, int subarrayIdx,
                                       HContinueEnumerationCallback<T> procedure,
                                       int? startIdx )
{
   return ForEachEx( array, dimension, subarrayIdx, procedure, startIdx, null, true );
}

public static bool BackwardForEach<T>( T[,] array, int dimension, int subarrayIdx,
                                       HContinueEnumerationCallback<T> procedure,
                                       int? startIdx, int? count )
{
   return ForEachEx( array, dimension, subarrayIdx, procedure, startIdx, count, true );
}

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

public static void ForEach<T>( T[,] array, int dimension, int subarrayIdx,
                               HEnumerationWithIndexCallback<T> procedure )
{
   ForEachEx( array, dimension, subarrayIdx, procedure, null, null, false );
}

public static void ForEach<T>( T[,] array, int dimension, int subarrayIdx,
                               HEnumerationWithIndexCallback<T> procedure,
                               int? startIdx )
{
   ForEachEx( array, dimension, subarrayIdx, procedure, startIdx, null, false );
}

public static void ForEach<T>( T[,] array, int dimension, int subarrayIdx,
                               HEnumerationWithIndexCallback<T> procedure,
                               int? startIdx, int? count )
{
   ForEachEx( array, dimension, subarrayIdx, procedure, startIdx, count, false );
}

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

public static void BackwardForEach<T>( T[,] array, int dimension, int subarrayIdx,
                                       HEnumerationWithIndexCallback<T> procedure )
{
   ForEachEx( array, dimension, subarrayIdx, procedure, null, null, true );
}

public static void BackwardForEach<T>( T[,] array, int dimension, int subarrayIdx,
                                       HEnumerationWithIndexCallback<T> procedure,
                                       int? startIdx )
{
   ForEachEx( array, dimension, subarrayIdx, procedure, startIdx, null, true );
}

public static void BackwardForEach<T>( T[,] array, int dimension, int subarrayIdx,
                                       HEnumerationWithIndexCallback<T> procedure,
                                       int? startIdx, int? count )
{
   ForEachEx( array, dimension, subarrayIdx, procedure, startIdx, count, true );
}

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

public static bool ForEach<T>( T[,] array, int dimension, int subarrayIdx,
                               HContinueEnumerationWithIndexCallback<T> procedure )
{
   return ForEachEx( array, dimension, subarrayIdx, procedure, null, null, false );
}

public static bool ForEach<T>( T[,] array, int dimension, int subarrayIdx,
                               HContinueEnumerationWithIndexCallback<T> procedure,
                               int? startIdx )
{
   return ForEachEx( array, dimension, subarrayIdx, procedure, startIdx, null, false );
}

public static bool ForEach<T>( T[,] array, int dimension, int subarrayIdx,
                               HContinueEnumerationWithIndexCallback<T> procedure,
                               int? startIdx, int? count )
{
   return ForEachEx( array, dimension, subarrayIdx, procedure, startIdx, count, false );
}

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

public static bool BackwardForEach<T>( T[,] array, int dimension, int subarrayIdx,
                                       HContinueEnumerationWithIndexCallback<T> procedure )
{
   return ForEachEx( array, dimension, subarrayIdx, procedure, null, null, true );
}

public static bool BackwardForEach<T>( T[,] array, int dimension, int subarrayIdx,
                                       HContinueEnumerationWithIndexCallback<T> procedure,
                                       int? startIdx )
{
   return ForEachEx( array, dimension, subarrayIdx, procedure, startIdx, null, true );
}

public static bool BackwardForEach<T>( T[,] array, int dimension, int subarrayIdx,
                                       HContinueEnumerationWithIndexCallback<T> procedure,
                                       int? startIdx, int? count )
{
   return ForEachEx( array, dimension, subarrayIdx, procedure, startIdx, count, true );
}

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

public static void ForEachEx<T>( T[,] array, int dimension, int subarrayIdx,
                                 HEnumerationCallback<T> procedure,
                                 int? startIdx, int? count, bool backwardScan )
{
   ForEachEx( array, dimension, subarrayIdx,
      delegate (T element,int idx) { procedure( element ); },
      startIdx, count, backwardScan );
}

public static bool ForEachEx<T>( T[,] array, int dimension, int subarrayIdx,
                                 HContinueEnumerationCallback<T> procedure,
                                 int? startIdx, int? count, bool backwardScan )
{
   return ForEachEx( array, dimension, subarrayIdx,
      delegate (T element,int idx) { return procedure( element ); },
      startIdx, count, backwardScan );
}

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

public static void ForEachEx<T>( T[,] array, int dimension, int subarrayIdx,
                                 HEnumerationWithIndexCallback<T> procedure,
                                 int? startIdx, int? count, bool backwardScan )
{
   ForEachEx( array, dimension, subarrayIdx,
      delegate (T element,int idx) { procedure( element, idx ); return true; },
      startIdx, count, backwardScan );
}

public static bool ForEachEx<T>( T[,] array, int dimension, int subarrayIdx,
                                 HContinueEnumerationWithIndexCallback<T> procedure,
                                 int? startIdx, int? count, bool backwardScan )
{
   HArrayArgChecking.VerifyIndex( array, dimension, subarrayIdx );
   HArgChecking.VerifyNotNull( procedure );

   int
      lowerBound = array.GetLowerBound( 1-dimension ),
      upperBound = array.GetUpperBound( 1-dimension ),
      fromIdx = startIdx ?? (backwardScan ? upperBound : lowerBound);

   if ( startIdx.HasValue && !HOps.IsBetween( startIdx.Value, lowerBound, upperBound ) )
      throw HArrayArgChecking.ArgumentOutOfRangeException_IncorrectIndex;

   if ( count != null && ( count < 0 ||
      !HOps.IsBetween( backwardScan ?
         fromIdx-count.Value+1 :
         fromIdx+count.Value-1,
         lowerBound, upperBound ) ) )
      throw new ArgumentOutOfRangeException();

   if ( !backwardScan )
      for ( int idx = fromIdx;
            count == null && idx <= upperBound ||
            count != null && idx-fromIdx < count;
            idx ++ )
         if ( !procedure( GetValue( array, dimension, subarrayIdx, idx ), idx ) )
            return false;

   if ( backwardScan )
      for ( int idx = fromIdx;
            count == null && idx >= lowerBound ||
            count != null && fromIdx-idx < count;
            idx -- )
         if ( !procedure( GetValue( array, dimension, subarrayIdx, idx ), idx ) )
            return false;

   return true;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // HArray2D
//**************************************************************************************************

} // CommonHelpers (.WASM)
