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

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

//**************************************************************************************************
/// <summary>
/// </summary>
public abstract partial class HDisposable: IDisposable {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

[HLockFree]
public bool IsValidDisposable
{
   get { return _IsValid_; }
}

[HLockFree]
public bool IsDisposing
{
   get { return _IsDisposing_; }
}

[HLockFree]
public bool WasDisposed
{
   get { return _WasDisposed_; }
}

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

/// <exception cref="InvalidOperationException" />
public void ValidateDisposable()
{
   if ( _WasDisposed_ )
      throw new InvalidOperationException(
         "Can not validate object, that is allready disposed." );
   Thread.MemoryBarrier();
   _IsValid_ = true;
}

public void Dispose()
{
   DoDispose( true );
}

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

[MethodImpl(MethodImplOptions.NoInlining)]
protected HDisposable()
{
// _CreationStackTrace_ = new StackTrace( 1, CommonHelpers_Info.IsDebugConfiguration );
   if ( CommonHelpers_Info.IsDebugConfiguration )
      _CreationStackTrace_ = new StackTrace( 1 );
}

protected abstract void OnDispose(bool synchronous);

/// <exception cref="InvalidOperationException" />
/// <exception cref="ObjectDisposedException" />
protected void VerifyValidDisposable()
{
   if ( WasDisposed )
      throw new ObjectDisposedException(string.Format(
         "Object of type \"{0}\" has been disposed.",
         this.GetType() ));
   if ( !IsValidDisposable )
      throw HInvOpExceptionCreator.Create(
         "Object of type \"{0}\" was not initialized.",
         this.GetType() );
}

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

static HDisposable()
{
   CommonHelpers_Core.Access();
}

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

/// <exception cref="InvalidOperationException" />
~HDisposable()
{
   if (HType.IsMarkedWithAttribute( GetType(), typeof(HSyncOnlyDisposableAttribute) ))
   {
      if ( _IsValid_ )
      {
         Exception err = HInvOpExceptionCreator.ObjectMustBeDisposedSynchronously( this );
         var stackTrace = _CreationStackTrace_;
         throw stackTrace != null ?
            HInvOpExceptionCreator.Create( "{0}\n\n"+
               "___ Object creation stack: ___\n"+
               "{1}", err.Message, stackTrace ) :
            err;
      }
   }
   else
   {
      Thread.MemoryBarrier();
      DoDispose( false );
   }
}

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

public void DoDispose(bool synchronous)
{
   if ( !_IsValid_ ) return;
   _IsDisposing_ = true;
   try
   {
      OnDispose( synchronous );
   }
   finally
   {
      _IsValid_ = _IsDisposing_ = false;
      _WasDisposed_ = true;
      if ( synchronous )
         GC.SuppressFinalize( this );
   }
}

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

volatile bool
   _IsValid_, _IsDisposing_, _WasDisposed_;
volatile StackTrace
   _CreationStackTrace_;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // HDisposable
//**************************************************************************************************

} // CommonHelpers (.WASM)
