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

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

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

public static T Min<T>(T[,] array,int dimension,int subarrayIdx)
   where T: IComparable
{
   return MinOrMax( array, dimension, subarrayIdx, HMinOrMax.Min, null, null );
}

public static T Min<T>(T[,] array,int dimension,int subarrayIdx,int? startIdx)
   where T: IComparable
{
   return MinOrMax( array, dimension, subarrayIdx, HMinOrMax.Min, startIdx, null );
}

public static T Min<T>(T[,] array,int dimension,int subarrayIdx,int? startIdx,int? count)
   where T: IComparable
{
   return MinOrMax( array, dimension, subarrayIdx, HMinOrMax.Min, startIdx, count );
}

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

public static T Max<T>(T[,] array,int dimension,int subarrayIdx)
   where T: IComparable
{
   return MinOrMax( array, dimension, subarrayIdx, HMinOrMax.Max, null, null );
}

public static T Max<T>(T[,] array,int dimension,int subarrayIdx,int? startIdx)
   where T: IComparable
{
   return MinOrMax( array, dimension, subarrayIdx, HMinOrMax.Max, startIdx, null );
}

public static T Max<T>(T[,] array,int dimension,int subarrayIdx,int? startIdx,int? count)
   where T: IComparable
{
   return MinOrMax( array, dimension, subarrayIdx, HMinOrMax.Max, startIdx, count );
}

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

public static int? IndexOfMin<T>(T[,] array,int dimension,int subarrayIdx)
   where T: IComparable
{
   return IndexOfMinOrMax( array, dimension, subarrayIdx, HMinOrMax.Min, null, null );
}

public static int? IndexOfMin<T>(T[,] array,int dimension,int subarrayIdx,int? startIdx)
   where T: IComparable
{
   return IndexOfMinOrMax( array, dimension, subarrayIdx, HMinOrMax.Min, startIdx, null );
}

public static int? IndexOfMin<T>(T[,] array,int dimension,int subarrayIdx,int? startIdx,int? count)
   where T: IComparable
{
   return IndexOfMinOrMax( array, dimension, subarrayIdx, HMinOrMax.Min, startIdx, count );
}

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

public static int? IndexOfMax<T>(T[,] array,int dimension,int subarrayIdx)
   where T: IComparable
{
   return IndexOfMinOrMax( array, dimension, subarrayIdx, HMinOrMax.Max, null, null );
}

public static int? IndexOfMax<T>(T[,] array,int dimension,int subarrayIdx,int? startIdx)
   where T: IComparable
{
   return IndexOfMinOrMax( array, dimension, subarrayIdx, HMinOrMax.Max, startIdx, null );
}

public static int? IndexOfMax<T>(T[,] array,int dimension,int subarrayIdx,int? startIdx,int? count)
   where T: IComparable
{
   return IndexOfMinOrMax( array, dimension, subarrayIdx, HMinOrMax.Max, startIdx, count );
}

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

public static bool GetMinAndMax<T>( T[,] array, int dimension, int subarrayIdx,
                                    out T min, out T max ) where T: IComparable
{
   return GetMinAndMax( array, dimension, subarrayIdx, null, out min, out max );
}

public static bool GetMinAndMax<T>( T[,] array, int dimension, int subarrayIdx,
                                    int? startIdx, out T min, out T max ) where T: IComparable
{
   return GetMinAndMax( array, dimension, subarrayIdx, startIdx, null, out min, out max );
}

public static bool GetMinAndMax<T>( T[,] array, int dimension, int subarrayIdx,
                                    int? startIdx, int? count,
                                    out T min, out T max ) where T: IComparable
{
   bool productivity = false;
   T minimum = default(T), maximum = default(T);
   ForEachEx
   (
      array, dimension, subarrayIdx,
      (HContinueEnumerationWithIndexCallback<T>)delegate (T element,int idx)
      {
         if ( element != null )
         {
            if ( element.CompareTo( minimum ) < 0  )
               minimum = element;
            if ( element.CompareTo( maximum ) > 0 )
               maximum = element;
            productivity = true;
         }
         return true;
      },
      startIdx, count, false
   );
   min = minimum;
   max = maximum;
   return productivity;
}

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

static T MinOrMax<T>( T[,] array, int dimension, int subarrayIdx,
                      HMinOrMax minmax, int? startIdx, int? count )
   where T: IComparable
{
   int? index;
   return GetMinOrMax(array,dimension,subarrayIdx,minmax,startIdx,count,out index);
}

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

static int? IndexOfMinOrMax<T>( T[,] array, int dimension, int subarrayIdx,
                                HMinOrMax minmax, int? startIdx, int? count )
   where T: IComparable
{
   int? index;
   GetMinOrMax(array,dimension,subarrayIdx,minmax,startIdx,count,out index);
   return index;
}

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

static T GetMinOrMax<T>( T[,] array, int dimension, int subarrayIdx,
                         HMinOrMax minmax, int? startIdx, int? count,
                         out int? index )
   where T: IComparable
{
   T resultValue = default(T);
   int? resultIdx = null;
   ForEachEx
   (
      array, dimension, subarrayIdx,
      (HContinueEnumerationWithIndexCallback<T>)delegate (T element,int idx)
      {
         if ( element != null )
         if ( resultIdx == null ||
              minmax==HMinOrMax.Min && element.CompareTo( resultValue )<0 ||
              minmax==HMinOrMax.Max && element.CompareTo( resultValue )>0 )
         {
            resultIdx = idx; resultValue = element;
         }
         return true;
      },
      startIdx, count, false
   );
   index = resultIdx;
   return resultValue;
}

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

} // CommonHelpers (.WASM)
