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

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

//**************************************************************************************************
partial class HCollection {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

public static T Min<T>(IEnumerable<T> collection) where T: IComparable
{
   int index;
   T value = GetMin(collection,out index);
   return index>=0 ? value : default(T);
}

public static T Max<T>(IEnumerable<T> collection) where T: IComparable
{
   int index;
   T value = GetMax(collection,out index);
   return index>=0 ? value : default(T);
}

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

/// <exception cref="HElementNotFoundException" />
public static T StrictMin<T>(IEnumerable<T> collection) where T: IComparable
{
   int index;
   T value = GetMin(collection,out index);
   if (index<0)
      throw new HEmptySetException();
   return value;
}

/// <exception cref="HElementNotFoundException" />
public static T StrictMax<T>(IEnumerable<T> collection) where T: IComparable
{
   int index;
   T value = GetMax(collection,out index);
   if (index<0)
      throw new HEmptySetException();
   return value;
}

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

public static bool GetMinAndMax<T>( IEnumerable<T> collection,
                                    out T min, out T max ) where T: IComparable
{
   min = max = default(T);
   bool productiveIterated = false;
   foreach (var element in collection)
      if ( element != null )
      {
         if ( !productiveIterated || element.CompareTo( min ) < 0 ) min = element;
         if ( !productiveIterated || element.CompareTo( max ) > 0 ) max = element;
         productiveIterated = true;
      }
   return productiveIterated;
}

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

public static int IndexOfMin<T>(IEnumerable<T> collection) where T: IComparable
{
   int index; GetMin(collection,out index); return index;
}

public static int IndexOfMax<T>(IEnumerable<T> collection) where T: IComparable
{
   int index; GetMax(collection,out index); return index;
}

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

/// <exception cref="HElementNotFoundException" />
public static int StrictIndexOfMin<T>(IEnumerable<T> collection) where T: IComparable
{
   int index = IndexOfMin( collection );
   if (index<0)
      throw new HEmptySetException();
   return index;
}

/// <exception cref="HElementNotFoundException" />
public static int StrictIndexOfMax<T>(IEnumerable<T> collection) where T: IComparable
{
   int index = IndexOfMax( collection );
   if (index<0)
      throw new HEmptySetException();
   return index;
}

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

public static T GetMin<T>(IEnumerable<T> collection,out int index) where T: IComparable
{
   return GetMinOrMax(collection,HMinOrMax.Min,out index);
}

public static T GetMax<T>(IEnumerable<T> collection,out int index) where T: IComparable
{
   return GetMinOrMax(collection,HMinOrMax.Max,out index);
}

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

static T GetMinOrMax<T>(IEnumerable<T> collection,HMinOrMax minmax,out int index)
   where T: IComparable
{
   HArgChecking.VerifyNotNull( collection );

   T result=default(T); index=-1;

   using (IEnumerator<T> enumerator=collection.GetEnumerator())
   {
      if (!enumerator.MoveNext())
         return result;
      int
         idx=0;
      do
      {
         T element=enumerator.Current;

         if ( element!=null && ( index<0 ||
              minmax==HMinOrMax.Min && element.CompareTo(result)<0 ||
              minmax==HMinOrMax.Max && element.CompareTo(result)>0 ) )
         {
            result=element; index=idx;
         }

         idx++;
      }
      while (enumerator.MoveNext());
   }

   return result;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // HCollection
//**************************************************************************************************

} // CommonHelpers (.WASM)
