//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
// UserRTX.NET satellite library | Author: Sergei Y.Kitáev
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
using System;
using System.Collections;
using System.Threading.Tasks;

#if !WASM
namespace user_rtx { using u = user_rtx;
#else
namespace user_rtx.wasm { using u = user_rtx.wasm;
#endif

/// <summary>
/// Enumerable helpers
/// </summary>
public static partial class enumerable {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

public static bool HasValues( IEnumerable collection )
{
   var iterator = collection.GetEnumerator();
   try {
      return iterator.MoveNext();
   }
   finally {
      u.disposable.DisposeIfDisposable( iterator );
   }
}

public static bool IsEmpty( IEnumerable collection ) =>
   !HasValues( collection );

public static int Count( IEnumerable collection )
{
   var iterator = collection.GetEnumerator();
   try {
      int count = 0;
      while ( iterator.MoveNext() )
         count++;
      return count;
   }
   finally {
      u.disposable.DisposeIfDisposable( iterator );
   }
}

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

public static object? FirstOrNull_O( IEnumerable collection )
{
   var iterator = collection.GetEnumerator();
   try {
      return iterator.MoveNext() ? iterator.Current : null;
   }
   finally {
      u.disposable.DisposeIfDisposable( iterator );
   }
}
public static object? SecondOrNull_O( IEnumerable collection )
{
   var iterator = collection.GetEnumerator();
   try {
      return iterator.MoveNext() && iterator.MoveNext() ? iterator.Current : null;
   }
   finally {
      u.disposable.DisposeIfDisposable( iterator );
   }
}

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

public static bool Exists_O( IEnumerable collection, object obj ) =>
   Exists_O( collection, o => object.Equals( o, obj ) );

public static bool Exists_O( IEnumerable collection, Func<object,bool> predicate )
{
   var iterator = collection.GetEnumerator();
   try {
      while ( iterator.MoveNext() )
         if ( predicate( iterator.Current ) )
            return true;
      return false;
   }
   finally {
      u.disposable.DisposeIfDisposable( iterator );
   }
}

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

public static void ForEach_O( IEnumerable collection, Action<object> processElementProc )
{
   foreach ( var obj in collection )
      processElementProc( obj );
}

public static async Task ForEach_OA<T>( IEnumerable collection, Func<object,Task> processElementAP )
{
   foreach ( var obj in collection )
      await processElementAP( obj ).ConfigureAwait(false);
}

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

public static bool HasNN( IEnumerable values )
{
   foreach ( var v in values )
      if ( v != null )
         return true;
   return false;
}

public static bool HasNull( IEnumerable values )
{
   foreach ( var v in values )
      if ( v == null )
         return true;
   return false;
}

public static bool NotNulls( IEnumerable values ) =>
   HasValues( values ) && !HasNull( values );
public static bool AllNulls( IEnumerable values ) =>
   HasValues( values ) && !HasNN( values );

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

[u.opt_through_minus_1]
public static int FindIndex<T>( IEnumerable collection, Predicate<object> predicate )
{
   var iterator = collection.GetEnumerator();
   try {
      int idx = -1;
      while ( iterator.MoveNext() )
      {
         idx++;
         if ( predicate( iterator.Current ) )
            return idx;
      }
      return -1;
   }
   finally {
      u.disposable.DisposeIfDisposable( iterator );
   }
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // enumerable

} // user_rtx (.wasm)
