//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
// 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 HMonitor {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/// <exception cref="ArgumentNullException" />
public static bool EnterIf(bool condition,[HRelOpt] object obj)
{
   if ( condition ) {
      HArgChecking.VerifyNotNull( obj );
      Monitor.Enter( obj ); }
   return condition;
}

/// <exception cref="ArgumentNullException" />
public static bool ExitIf(bool condition,[HRelOpt] object obj)
{
   if ( condition ) {
      HArgChecking.VerifyNotNull( obj );
      Monitor.Exit( obj ); }
   return condition;
}

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

/// <exception cref="ArgumentNullException" />
public static void Enter(params object[] objects)
{
   HOps.ForEach( objects, delegate (object obj) { Monitor.Enter( obj ); });
}

/// <exception cref="ArgumentNullException" />
public static void Exit(params object[] objects)
{
   HOps.BackwardForEach( objects, delegate (object obj) { Monitor.Exit( obj ); });
}

/// <exception cref="ArgumentNullException" />
public static void Exit_DirectOrder(params object[] objects)
{
   HOps.ForEach( objects, delegate (object obj) { Monitor.Exit( obj ); });
}

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

public static bool EnterIfNotNull([HOptional] object obj)
{
   return EnterIf( obj!=null, obj );
}

public static bool ExitIfNotNull([HOptional] object obj)
{
   return ExitIf( obj!=null, obj );
}

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

/// <exception cref="ArgumentNullException" />
public static bool? EnterNotNulls(params object[] objects)
{
   HArgChecking.VerifyNotNull( objects );
   bool success = true, hasOk = false;
   for (int idx=objects.GetLowerBound(0); idx<=objects.GetUpperBound(0); idx++)
      if (!( hasOk = EnterIfNotNull( objects[ idx ] ) ))
         success = false;
   return success ? true : hasOk ? new Nullable<bool>() : false;
}

/// <exception cref="ArgumentNullException" />
public static bool? ExitNotNulls(params object[] objects)
{
   HArgChecking.VerifyNotNull( objects );
   bool success = true, hasOk = false;
   for (int idx=objects.GetUpperBound(0); idx>=objects.GetLowerBound(0); idx--)
      if (!( hasOk = ExitIfNotNull( objects[ idx ] ) ))
         success = false;
   return success ? true : hasOk ? new Nullable<bool>() : false;
}

/// <exception cref="ArgumentNullException" />
public static bool? ExitNotNulls_DirectOrder(params object[] objects)
{
   HArgChecking.VerifyNotNull( objects );
   bool success = true, hasOk = false;
   for (int idx=objects.GetLowerBound(0); idx<=objects.GetUpperBound(0); idx++)
      if (!( hasOk = ExitIfNotNull( objects[ idx ] ) ))
         success = false;
   return success ? true : hasOk ? new Nullable<bool>() : false;
}

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

/// <exception cref="ArgumentNullException" />
public static bool LockIf(bool condition,[HRelOpt] object obj,Action callback)
{
   HArgChecking.VerifyNotNull( callback );
   if ( condition ) {
      HArgChecking.VerifyNotNull( obj );
      lock ( obj ) callback(); return true; }
   callback(); return false;
}

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

/// <exception cref="ArgumentNullException" />
public static bool LockIfNotNull([HOptional] object obj,Action callback)
{
   return LockIf( obj!=null, obj, callback );
}

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

/// <exception cref="ArgumentNullException" />
public static bool? LockNotNulls(object[] objects,Action callback)
{
   HArgChecking.VerifyNotNull( callback );
   bool? rslt = EnterNotNulls( objects );
   try { callback(); return rslt; }
   finally { ExitNotNulls( objects ); }
}

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

public static void PulseAndWait(object obj)
{
   Monitor.Pulse(obj); Monitor.Wait(obj);
}

public static void WaitAndPulse(object obj)
{
   Monitor.Wait(obj); Monitor.Pulse(obj);
}

public static void PulseWaitAndPulse(object obj)
{
   Monitor.Pulse(obj); Monitor.Wait(obj); Monitor.Pulse(obj);
}

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

public static void LockAndWait(object obj)
{
   lock (obj) { Monitor.Wait(obj); }
}

public static void LockAndPulse(object obj)
{
   lock (obj) { Monitor.Pulse(obj); }
}

public static void LockPulseAndWait(object obj)
{
   lock (obj) { Monitor.Pulse(obj); Monitor.Wait(obj); }
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // HMonitor
//**************************************************************************************************

} // CommonHelpers (.WASM)
