//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
// AFXUI auxiliary module for Blazor-application (WASM) | Author: Sergei Y.Kitáev
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
using System;
using System.Reflection;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Collections.Generic;

using CommonHelpers.WASM;

namespace AFXUI {

//**************************************************************************************************
/// <summary>
/// User input blocking (usually for small duration)
/// </summary>
[HSyncOnlyDisposable]
public class UInputBlocking: HDisposable {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

public bool WasBlocked { get; }
public bool UseWaitingCursorInCompletion { get; }
public bool IsNeutralized { get; private set; }

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

public static bool IsBlocked { get; private set; }

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

public UInputBlocking()
: this( false, true )
{}
public UInputBlocking(bool useWaitingCursor)
: this( useWaitingCursor, true )
{}
public UInputBlocking(bool useWaitingCursor,bool useWaitingCursorInCompletion)
{
   UseWaitingCursorInCompletion = useWaitingCursorInCompletion;
   WasBlocked = IsBlocked;
   Block( useWaitingCursor );
   ValidateDisposable();
   _Instances_.Add( this );
}

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

public void Neutralize() =>
   IsNeutralized = true;

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

public static bool CheckBlocking(Type type,string methodNameOrSignature)
{
   if ( UFatalBreakdown.IsInFatalError )
      return false;
   if ( IsBlocked )
   {
      UDebugConsole.Print(
         "Blocking rejection (allready blocked) in: [{0}] {1}",
         type.Name, methodNameOrSignature );
      return false;
   }
   return true;
}
/// <exception cref="ArgumentNullException" />
public static bool CheckBlocking([HRequired] MethodBase? method)
{
   method = HArgChecking.NN( method );
   return CheckBlocking( method.DeclaringType.NN(), method.Name );
}

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

public static bool Block() => Block(false);
public static bool Block(bool useWaitingCursor)
{
   bool wasBlocked = IsBlocked;
   UJS.Invoke( "InputBlocking_Block", true, useWaitingCursor );
   IsBlocked = true;
   return !wasBlocked;
}

public static bool Unblock() => Unblock(true);
public static bool Unblock(bool useWaitingCursor)
{
   bool wasBlocked = IsBlocked;
   UJS.Invoke( "InputBlocking_Unblock", useWaitingCursor );
   IsBlocked = false;
   return wasBlocked;
}

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

public static async Task WaitUnblocked_A()
{
   while ( IsBlocked )
      await Task.Delay( UCircuit.PollInterval );
}

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

public static void NeutralizeInstances()
{
   foreach (var inst in _Instances_)
      inst.Neutralize();
   _Instances_.Clear();
}

public static void NeutralizeResetToInitial()
{
   NeutralizeInstances();
   IsBlocked = true;
}

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

/// <exception cref="InvalidOperationException" />
public static void VerifyBlocked()
{
   if ( !IsBlocked )
      throw new ArgumentException( "User input is unexpectedly not in blocked state." );
}
/// <exception cref="InvalidOperationException" />
public static void VerifyNotBlocked()
{
   if ( IsBlocked )
      throw new ArgumentException( "User input is unexpectedly in blocked state." );
}

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

protected override void OnDispose(bool synchronous)
{
   _Instances_.Remove( this );
   if ( !IsNeutralized && !UCircuit.IsEscapeRequested )
      if ( WasBlocked )
         Block( UseWaitingCursorInCompletion );
      else
         Unblock( UseWaitingCursorInCompletion );
}

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

static readonly List<UInputBlocking>
   _Instances_ = new List<UInputBlocking>();

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // UInputBlocking
//**************************************************************************************************

} // AFXUI
