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

namespace CommonHelpers {

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

/// <exception cref="ArgumentNullException" />
/// <exception cref="ArgumentOutOfRangeException" />
public static unsafe string FromPointer(IntPtr ipString)
{
   HPointerArgChecking.VerifyNotNull( ipString );
   return new string( (char*)ipString );
}

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

public static void VerifyCapacity(int capacity)
{
   if (capacity<1)
      throw HArgumentOutOfRangeExceptionCreator.Create(
         "Incorrect capacity for zero terminated string." );
}

public static unsafe string ToString([HOptional] IntPtr ptrSZ)
{
   return ptrSZ!=null ? new string((char*)ptrSZ) : null;
}

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

public static unsafe int Length([HIn] IntPtr ptrSZ)
{
   HPointerArgChecking.VerifyNotNull( ptrSZ );
   for (char* pch=(char*)ptrSZ;;pch++)
      if (*pch=='\0')
         return (int)((uint)pch-(uint)ptrSZ);
}

public static bool IsEmpty([HIn] IntPtr ptrSZ)
{
   return Length( ptrSZ )==0;
}

public static bool IsNullOrEmpty([HIn] IntPtr ptrSZ)
{
   return ptrSZ==IntPtr.Zero || IsEmpty(ptrSZ);
}

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

/// <exception cref="ArgumentException" />
/// <exception cref="HOperationFailedException" />
public static unsafe IntPtr Copy([HIn] IntPtr ptrSourceSZ,[HOut] IntPtr ptrDestinationSZ)
{
   HPointerArgChecking.VerifyNotNull( ptrSourceSZ );
   HPointerArgChecking.VerifyNotNull( ptrDestinationSZ );
   for ( char* pchSource=(char*)ptrSourceSZ,
               pchDestination=(char*)ptrDestinationSZ;;
         pchSource++, pchDestination++ )
      if ((*pchDestination=*pchSource)=='\0')
         return ptrDestinationSZ;
}

/// <exception cref="ArgumentException" />
/// <exception cref="HOperationFailedException" />
public static IntPtr Copy( [HIn] IntPtr ptrSourceSZ,
                           [HOut] IntPtr ptrDestinationSzBuffer,
                           int destBuffCapacity )
{
   HPointerArgChecking.VerifyNotNull( ptrSourceSZ );
   HPointerArgChecking.VerifyNotNull( ptrDestinationSzBuffer );
   if (destBuffCapacity<=1)
      throw new ArgumentException(
         "Wrong destination capacity for zero-terminated string." );
   int sourceLength = Length(ptrSourceSZ);
   if ( sourceLength >= destBuffCapacity )
      throw new HOperationFailedException(
         "Insufficient buffer for zero-terminated string." );
   return HMemory.Copy<char>(ptrSourceSZ,ptrDestinationSzBuffer,sourceLength+1);
}

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

/// <exception cref="HOperationFailedException" />
public static unsafe IntPtr Allocate(int capacity)
{
   VerifyCapacity( capacity );
   IntPtr result = HMemory.Allocate<char>( capacity );
   ((char*)result)[ 0 ] = '\0';
   return result;
}

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

/// <exception cref="HOperationFailedException" />
public static unsafe IntPtr ReAllocate([HIn] IntPtr ptrAllocatedBuffer,int newCapacity)
{
   VerifyCapacity( newCapacity );
   IntPtr result = HMemory.ReAllocate<char>( ptrAllocatedBuffer, newCapacity );
   ((char*)result)[ newCapacity-1 ] = '\0';
   return result;
}

/// <exception cref="HOperationFailedException" />
public static unsafe IntPtr ReAllocate( [HIn][HVolatileAccess] ref IntPtr ptrAllocatedBuffer,
                                        int newCapacity )
{
   VerifyCapacity( newCapacity );
   return HVolatile.Write( ref ptrAllocatedBuffer,
      ReAllocate( Thread.VolatileRead(ref ptrAllocatedBuffer), newCapacity ) );
}

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

/// <exception cref="HOperationFailedException" />
public static IntPtr ReAllocateByLength([HIn] IntPtr ptrAllocatedSzBuffer)
{
   return ReAllocate( ptrAllocatedSzBuffer, Length( ptrAllocatedSzBuffer ) );
}

/// <exception cref="HOperationFailedException" />
public static IntPtr ReAllocateByLength([HIn] ref IntPtr ptrAllocatedSzBuffer)
{
   return HVolatile.Write( ref ptrAllocatedSzBuffer,
      ReAllocateByLength( Thread.VolatileRead(ref ptrAllocatedSzBuffer) ) );
}

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

/// <exception cref="HOperationFailedException" />
public static IntPtr Duplicate([HIn] IntPtr ptrSZ)
{
   return Copy( ptrSZ, Allocate(Length(ptrSZ)) );
}

/// <exception cref="HOperationFailedException" />
public static unsafe IntPtr Duplicate([HIn] string str)
{
   HArgChecking.VerifyNotNull( str );
   char* buffer = HUnsafeCharBuffer.Allocate( str.Length+1 );
   for (int i=0; i<str.Length; i++)
      buffer[i] = str[i];
   buffer[ str.Length ] = '\0';
   return (IntPtr)buffer;
}

/// <exception cref="HOperationFailedException" />
public static unsafe IntPtr Duplicate([HIn] char* psz)
{
   return Duplicate( (IntPtr)psz );
}

/// <exception cref="HOperationFailedException" />
public static IntPtr DuplicateAllocatedBuffer([HIn] IntPtr ptrAllocatedBuffer)
{
   return HMemory.Duplicate<char>( ptrAllocatedBuffer );
}

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

/// <exception cref="HOperationFailedException" />
public static int GetAllocatedCapacity(IntPtr ptrAllocatedBuffer)
{
   return HMemory.GetAllocatedCapacity<char>( ptrAllocatedBuffer );
}

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

/// <exception cref="Win32Exception" />
public static bool Free([HOptional] IntPtr ptrAllocatedBuffer)
{
   return HMemory.Free<char>( ptrAllocatedBuffer );
}

/// <exception cref="Win32Exception" />
public static bool Free([HOptional][HInterlockedAccess] ref IntPtr ptrAllocatedBuffer)
{
   return HMemory.Free(ref ptrAllocatedBuffer);
}

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

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // HSZ
//**************************************************************************************************

} // CommonHelpers
