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

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

//**************************************************************************************************
/// <summary>
/// </summary>
public static partial class HCollection {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

public static bool HasElements<T>(IEnumerable<T> collection)
{
   HArgChecking.VerifyNotNull( collection );
   var
      enumerator = collection.GetEnumerator();
   try
   {
      return enumerator.MoveNext();
   }
   finally
   {
      if (enumerator is IDisposable)
         ((IDisposable)enumerator).Dispose();
   }
}

public static bool IsEmpty<T>(IEnumerable<T> collection)
{
   return !HasElements( collection );
}

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

public static int Count<T>(IEnumerable<T> collection)
{
   HArgChecking.VerifyNotNull( collection );
   var
      enumerator = collection.GetEnumerator();
   try
   {
      int count=0;
      while (enumerator.MoveNext())
         count++;
      return count;
   }
   finally
   {
      if (enumerator is IDisposable)
         ((IDisposable)enumerator).Dispose();
   }
}

public static int Count<T>(IEnumerable<T> collection,HConditionDelegate<T> condition)
{
   HArgChecking.VerifyNotNulls( collection, condition );
   int count = 0;
   foreach (T value in collection)
      if ( condition( value ) )
         count++;
   return count;
}

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

public static bool Contains<T>(IEnumerable<T> collection,[HOptional] T value)
{
   return Contains(collection,value,null);
}

public static int ZBIndexOf<T>(IEnumerable<T> collection,[HOptional] T value)
{
   return ZBIndexOf(collection,value,null);
}

public static int StrictZBIndexOf<T>(IEnumerable<T> collection,[HOptional] T value)
{
   return StrictZBIndexOf(collection,value,null);
}

public static bool GetZBIndexOf<T>(IEnumerable<T> collection,[HOptional] T value,out int index)
{
   return GetZBIndexOf(collection,value,null,out index);
}

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

public static bool Contains<T>( IEnumerable<T> collection,
                                [HOptional] T value,
                                [HOptional] HEqualsCallback<T> equalsCallback )
{
   return ZBIndexOf(collection,value,equalsCallback) >= 0;
}

public static int ZBIndexOf<T>( IEnumerable<T> collection,
                                [HOptional] T value,
                                [HOptional] HEqualsCallback<T> equalsCallback )
{
   int idx;
   GetZBIndexOf(collection,value,equalsCallback,out idx);
   return idx;
}

public static int StrictZBIndexOf<T>( IEnumerable<T> collection,
                                      [HOptional] T value,
                                      [HOptional] HEqualsCallback<T> equalsCallback )
{
   int idx;
   if (GetZBIndexOf(collection,value,equalsCallback,out idx))
      return idx;
   throw new HElementNotFoundException();
}

public static bool GetZBIndexOf<T>( IEnumerable<T> collection,
                                    [HOptional] T value,
                                    [HOptional] HEqualsCallback<T> equalsCallback,
                                    out int index )
{
   HArgChecking.VerifyNotNull( collection );
   int idx=-1;
   foreach (var v in collection)
   {
      idx++;
      if ( equalsCallback!=null ? equalsCallback(v,value) : object.Equals(v,value) )
      {
         index = idx;
         return true;
      }
   }
   index = -1;
   return false;
}

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

public static bool ConventEquals<T>( [HOptional] IEnumerable<T> collection_1,
                                     [HOptional] IEnumerable<T> collection_2 )
{
   if (collection_1==collection_2)
      return true;
   if ( collection_1==null && collection_2!=null ||
        collection_1!=null && collection_2==null )
      return false;
   var
      enumerator_1 = collection_1.GetEnumerator();
   try
   {
      var
         enumerator_2 = collection_2.GetEnumerator();
      try
      {
         for (;;)
         {
            bool
               end_1 =! enumerator_1.MoveNext(),
               end_2 =! enumerator_2.MoveNext();
            if (end_1 && end_2)
               return true;
            if (end_1!=end_2)
               return false;
            T
               element_1 = enumerator_1.Current,
               element_2 = enumerator_2.Current;
            if (!object.Equals(element_1,element_2))
               return false;
         }
      }
      finally
      {
         if (enumerator_2 is IDisposable)
            ((IDisposable)enumerator_2).Dispose();
      }
   }
   finally
   {
      if (enumerator_1 is IDisposable)
         ((IDisposable)enumerator_1).Dispose();
   }
}

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

public static void Process<T>(IEnumerable<T> collection,HEnumerationCallback<T> procedure)
{
   HArgChecking.VerifyNotNulls( collection, procedure );
   Process( collection, delegate (T element){ procedure( element ); return true; } );
}

public static bool Process<T>(IEnumerable<T> collection,HContinueEnumerationCallback<T> procedure)
{
   HArgChecking.VerifyNotNulls( collection, procedure );
   foreach (T element in collection)
      if ( !procedure( element ) )
         return false;
   return true;
}

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

public static T[] ToArray<T>(IEnumerable<T> collection)
{
   HArgChecking.VerifyNotNull( collection );
   var list = new List<T>();
   foreach (T value in collection)
      list.Add( value );
   return list.ToArray();
}

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

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

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

} // CommonHelpers (.WASM)
