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

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

/// <summary>
/// Async-await helper class
/// </summary>
public static class asynch {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

public const int
   PollInterval = 100, // milliseconds
   EnlargedPollInterval = 250; // milliseconds

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

public static ConfiguredTaskAwaitable NOP_A( bool continueOnCapturedContext = true ) =>
   Task.CompletedTask.ConfigureAwait( continueOnCapturedContext );

public static ConfiguredTaskAwaitable Completed_A( bool continueOnCapturedContext = false ) =>
   Task.CompletedTask.ConfigureAwait( continueOnCapturedContext );

public static ConfiguredTaskAwaitable<T> Result_A<T>( T result,
                                                      bool continueOnCapturedContext = false ) =>
   Task.FromResult<T>( result ).ConfigureAwait( continueOnCapturedContext );

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

public static Task Delay_A( int milliseconds ) =>
   Task.Delay( milliseconds );

public static Task PollDelay_A() =>
   Task.Delay( PollInterval );

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

public static Task WaitFor_A( Func<bool> condition ) =>
   WaitFor_A( PollInterval, condition );

/// <exception cref="ArgumentOutOfRangeException" />
public static async Task WaitFor_A( [u.positive] int pollInterval, Func<bool> condition )
{
   u.arg_check.Positive( pollInterval, nameof(pollInterval) );
   while ( !condition() )
      await Task.Delay( pollInterval ).ConfigureAwait(false);
}

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

public static Task WaitFor_A( Func<Task<bool>> conditionA ) =>
   WaitFor_A( PollInterval, conditionA );

/// <exception cref="ArgumentOutOfRangeException" />
public static async Task WaitFor_A( [u.positive] int pollInterval, Func<Task<bool>> conditionA )
{
   u.arg_check.Positive( pollInterval, nameof(pollInterval) );
   while ( !await conditionA().ConfigureAwait(false) )
      await Task.Delay( pollInterval ).ConfigureAwait(false);
}

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

public static async Task<u.EFake> Hang_A()
{
   await Task.Delay(-1).ConfigureAwait(false);
   return u.assertion_fail.DEAD_BRANCH();
}

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

public static async Task<bool> NotCancelledDo_A( Func<Task> bodyA )
{
   try {
      await bodyA();
      return true;
   } catch ( TaskCanceledException ) {
      return false;
   }
}

[u.failure_as_null]
public static async Task<R?> NotCancelledDo_A<R>( Func<Task<R>> functionA )
where R: notnull
{
   try {
      return await functionA();
   } catch ( TaskCanceledException ) {
      return default;
   }
}

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

public static async Task<bool> NotCancelledDo_A( string actionName, Func<Task> bodyA )
{
   bool success = await NotCancelledDo_A( bodyA );
   if ( !success )
      TraceActionCancelled( actionName );
   return success;
}

[u.failure_as_null]
public static async Task<R?> NotCancelledDo_A<R>( string actionName, Func<Task<R>> functionA )
where R: notnull
{
   R? rslt = await NotCancelledDo_A( functionA );
   if ( rslt == null )
      TraceActionCancelled( actionName );
   return rslt;
}

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

public static void TraceActionCancelled( string actionName ) =>
   u.trace.PrintError( "{0}: CANCELED", actionName );

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

static Task<object?> GetNull_A() =>
   Task.FromResult<object?>( null );

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // asynch

} // user_rtx (.wasm)
