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

namespace CommonHelpers {

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

public static readonly IntPtr
   NullValue = IntPtr.Zero,
   InvalidValue = (IntPtr)(-1);

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

public static bool IsNull(IntPtr handle)
{
   return handle == NullValue;
}

public static bool IsInvalidValue(IntPtr handle)
{
   return handle == InvalidValue;
}

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

public static bool IsInvalid(IntPtr handle,bool isOfInvalidHandleValueCategory)
{
   return handle == GetNullOrInvalidValue( isOfInvalidHandleValueCategory );
}

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

public static IntPtr GetNullOrInvalidValue(bool isOfInvalidHandleValueCategory)
{
   return isOfInvalidHandleValueCategory ? InvalidValue : NullValue;
}

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

public static bool SimpleValidationCheck( [HOptional] IntPtr handle,
                                          bool isOfInvalidHandleValueCategory )
{
   return isOfInvalidHandleValueCategory ?
      handle!=InvalidValue : handle!=NullValue;
}

public static void SimpleVerification( [HOptional] IntPtr handle,
                                       bool isOfInvalidHandleValueCategory )
{
   if (!SimpleValidationCheck(handle,isOfInvalidHandleValueCategory))
      throw new ArgumentException(
         isOfInvalidHandleValueCategory ?
            "Handle value is invalid." :
            "Handle value is null." );
}

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

public static IntPtr Exchange([HVolatileAccess] ref IntPtr handle,IntPtr subst)
{
   return HPointer.Exchange(ref handle,subst);
}

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

public static IntPtr NullValueExchange([HVolatileAccess] ref IntPtr handle)
{
   return Exchange(ref handle,NullValue);
}

public static IntPtr InvalidValueExchange([HVolatileAccess] ref IntPtr handle)
{
   return Exchange(ref handle,InvalidValue);
}

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

public static IntPtr InterlockedExchange([HInterlockedAccess] ref IntPtr handle,IntPtr subst)
{
   return Interlocked.Exchange(ref handle,subst);
}

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

public static IntPtr InterlockedNullValueExchange([HInterlockedAccess] ref IntPtr handle)
{
   return InterlockedExchange(ref handle,NullValue);
}

public static IntPtr InterlockedInvalidValueExchange([HInterlockedAccess] ref IntPtr handle)
{
   return InterlockedExchange(ref handle,InvalidValue);
}

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

public static IntPtr Reset([HOptional][HInterlockedAccess] ref IntPtr handle)
{
   return Reset( ref handle, false );
}

public static IntPtr Reset( [HOptional][HInterlockedAccess] ref IntPtr handle,
                            bool isOfInvalidHandleValueCategory )
{
   return Interlocked.Exchange( ref handle,
      isOfInvalidHandleValueCategory ? InvalidValue : NullValue );
}

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

/// <exception cref="Win32Exception" />
public static bool Close([HOptional] IntPtr handle)
{
   return Close( handle, false );
}

/// <exception cref="Win32Exception" />
public static bool Close([HOptional] IntPtr handle,bool isOfInvalidHandleValueCategory)
{
   return Close( handle, isOfInvalidHandleValueCategory, null );
}

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

/// <exception cref="Win32Exception" />
public static bool Close( [HOptional] IntPtr handle,
                          [HOptional] HCloseHandleCallback closeHandleCallback )
{
   return Close( handle, false, closeHandleCallback );
}

/// <exception cref="Win32Exception" />
public static bool Close( [HOptional] IntPtr handle,
                          bool isOfInvalidHandleValueCategory,
                          [HOptional] HCloseHandleCallback closeHandleCallback )
{
   if (!SimpleValidationCheck(handle,isOfInvalidHandleValueCategory))
      return false;
   if (closeHandleCallback!=null)
      closeHandleCallback( handle );
   else
      if (!Win32_PAccess.CloseHandle( handle ))
         throw HWin32Error.CreateExceptionFromLastError();
   return true;
}

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

/// <exception cref="Win32Exception" />
public static bool SetNullAndClose([HOptional][HInterlockedAccess] ref IntPtr handle)
{
   return SetNullAndClose(ref handle,null);
}

/// <exception cref="Win32Exception" />
public static bool SetNullAndClose( [HOptional][HInterlockedAccess] ref IntPtr handle,
                                    [HOptional] HCloseHandleCallback closeHandleCallback )
{
   return ResetAndClose(ref handle,false,closeHandleCallback);
}

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

/// <exception cref="Win32Exception" />
public static bool InvalidateAndClose([HOptional][HInterlockedAccess] ref IntPtr handle)
{
   return InvalidateAndClose(ref handle,null);
}

/// <exception cref="Win32Exception" />
public static bool InvalidateAndClose( [HOptional][HInterlockedAccess] ref IntPtr handle,
                                       [HOptional] HCloseHandleCallback closeHandleCallback )
{
   return ResetAndClose(ref handle,true,closeHandleCallback);
}

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

/// <exception cref="Win32Exception" />
public static bool ResetAndClose( [HOptional][HInterlockedAccess] ref IntPtr handle,
                                  bool isOfInvalidHandleValueCategory )
{
   return ResetAndClose(ref handle,isOfInvalidHandleValueCategory,null);
}

/// <exception cref="Win32Exception" />
public static bool ResetAndClose( [HOptional][HInterlockedAccess] ref IntPtr handle,
                                  bool isOfInvalidHandleValueCategory,
                                  [HOptional] HCloseHandleCallback closeHandleCallback )
{
   return Close(
      Reset( ref handle, isOfInvalidHandleValueCategory ),
      isOfInvalidHandleValueCategory,
      closeHandleCallback );
}

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

static HHandle()
{
   CommonHelpers_PAccess.Access();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // HHandle
//**************************************************************************************************

} // CommonHelpers
