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

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

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

/// <exception cref="ObjectDisposedException" />
/// <exception cref="AbandonedMutexException" />
/// <exception cref="InvalidOperationException" />
public static bool? WaitOneAndCloseIfNotNull([HOptional] WaitHandle waitHandle)
{
   if ( waitHandle == null ) return null;
   waitHandle.WaitOne(); waitHandle.Close(); return true;
}

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

/// <exception cref="ObjectDisposedException" />
/// <exception cref="AbandonedMutexException" />
/// <exception cref="InvalidOperationException" />
/// <exception cref="ArgumentOutOfRangeException" />
public static bool? WaitOneAndCloseIfNotNull( [HOptional] WaitHandle waitHandle,
                                              int millisecondsTimeout )
{
   if ( waitHandle == null ) return null;
   bool wres = waitHandle.WaitOne( millisecondsTimeout );
   if (wres) waitHandle.Close(); return wres;
}

/// <exception cref="ObjectDisposedException" />
/// <exception cref="AbandonedMutexException" />
/// <exception cref="InvalidOperationException" />
/// <exception cref="ArgumentOutOfRangeException" />
public static bool? WaitOneAndCloseIfNotNull([HOptional] WaitHandle waitHandle,TimeSpan timeout)
{
   if ( waitHandle == null ) return null;
   bool wres = waitHandle.WaitOne( timeout );
   if (wres) waitHandle.Close(); return wres;
}

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

/// <exception cref="ObjectDisposedException" />
/// <exception cref="AbandonedMutexException" />
/// <exception cref="InvalidOperationException" />
/// <exception cref="ArgumentOutOfRangeException" />
public static bool? WaitOneAndCloseIfNotNull( [HOptional] WaitHandle waitHandle,
                                              int millisecondsTimeout,
                                              bool exitContext )
{
   if ( waitHandle == null ) return null;
   bool wres = waitHandle.WaitOne( millisecondsTimeout, exitContext );
   if (wres) waitHandle.Close(); return wres;
}

/// <exception cref="ObjectDisposedException" />
/// <exception cref="AbandonedMutexException" />
/// <exception cref="InvalidOperationException" />
/// <exception cref="ArgumentOutOfRangeException" />
public static bool? WaitOneAndCloseIfNotNull( [HOptional] WaitHandle waitHandle,
                                              TimeSpan timeout, bool exitContext )
{
   if ( waitHandle == null ) return null;
   bool wres = waitHandle.WaitOne( timeout, exitContext );
   if (wres) waitHandle.Close(); return wres;
}

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

/// <exception cref="ObjectDisposedException" />
/// <exception cref="AbandonedMutexException" />
/// <exception cref="InvalidOperationException" />
[CLSCompliant(false)]
public static bool? WaitOneAndCloseIfNotNull( [HOptional][HInterlockedAccess]
                                              ref WaitHandle waitHandle )
{
   return WaitOneAndCloseIfNotNull( HInterlocked.NullExchange(ref waitHandle) );
}

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

/// <exception cref="ObjectDisposedException" />
/// <exception cref="AbandonedMutexException" />
/// <exception cref="InvalidOperationException" />
/// <exception cref="ArgumentOutOfRangeException" />
[CLSCompliant(false)]
public static bool? WaitOneAndCloseIfNotNull( [HOptional][HInterlockedAccess]
                                              ref WaitHandle waitHandle,
                                              int millisecondsTimeout )
{
   return WaitOneAndCloseIfNotNull(
      HInterlocked.NullExchange(ref waitHandle), millisecondsTimeout );
}

/// <exception cref="ObjectDisposedException" />
/// <exception cref="AbandonedMutexException" />
/// <exception cref="InvalidOperationException" />
/// <exception cref="ArgumentOutOfRangeException" />
[CLSCompliant(false)]
public static bool? WaitOneAndCloseIfNotNull( [HOptional][HInterlockedAccess]
                                              ref WaitHandle waitHandle,
                                              TimeSpan timeout )
{
   return WaitOneAndCloseIfNotNull( HInterlocked.NullExchange(ref waitHandle), timeout );
}

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

/// <exception cref="ObjectDisposedException" />
/// <exception cref="AbandonedMutexException" />
/// <exception cref="InvalidOperationException" />
/// <exception cref="ArgumentOutOfRangeException" />
[CLSCompliant(false)]
public static bool? WaitOneAndCloseIfNotNull( [HOptional][HInterlockedAccess]
                                              ref WaitHandle waitHandle,
                                              int millisecondsTimeout, bool exitContext )
{
   return WaitOneAndCloseIfNotNull(
      HInterlocked.NullExchange(ref waitHandle), millisecondsTimeout, exitContext );
}

/// <exception cref="ObjectDisposedException" />
/// <exception cref="AbandonedMutexException" />
/// <exception cref="InvalidOperationException" />
/// <exception cref="ArgumentOutOfRangeException" />
[CLSCompliant(false)]
public static bool? WaitOneAndCloseIfNotNull( [HOptional][HInterlockedAccess]
                                              ref WaitHandle waitHandle,
                                              TimeSpan timeout, bool exitContext )
{
   return WaitOneAndCloseIfNotNull(
      HInterlocked.NullExchange(ref waitHandle), timeout, exitContext );
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // HWaitHandle
//**************************************************************************************************

} // CommonHelpers (.WASM)
