// RuntimeForStatic base library | C+- (SysRoutine) | Author: Sergei Y.Kitáev
#include "Precompiled.h"
#include "SharedIncludes.h"
namespace RuntimeForStatic {
//==================================================================================================

$DynText::$DynText()
: $DynText($, L"", false )
{}

$DynText::$DynText($DynText& predecessor) $owner_transfer
{
   TakeOwnership( predecessor );
}
$DynText::$DynText($A, PCWSTR text ) $duplicate $fatal_error_on_failure
{
   ResetSuperstructure();
   DoAssign($ci, text );
   ValidateDisposable($$);
}
$DynText::$DynText($A, const $DynText& dt ) $duplicate $fatal_error_on_failure
{
   ResetSuperstructure();
   DoAssign($ci, dt.T($ci) );
   ValidateDisposable($$);
}
$DynText::$DynText($A, PWSTR textPointer, bool needsFree )
{
   ResetSuperstructure();
   DoSetPointer($ci, textPointer, needsFree );
   ValidateDisposable($$);
}
$DynText::$DynText($A, PWSTR textPointer,
                       $MemFreeRoutine specialFreeRoutine $optional )
{
   ResetSuperstructure();
   DoSetPointer($ci, textPointer, specialFreeRoutine );
   ValidateDisposable($$);
}

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

$DynText& $DynText::operator = ($DynText& predecessor) $owner_transfer
{
   if ( this == &predecessor )
      return *this;
   TakeOwnership( predecessor );
   return *this;
}

void $DynText::TakeOwnership($DynText& predecessor) $owner_transfer
{
   $memory::Copy($, &predecessor, this );
   auto predPtr = ($PDynText)&predecessor;
   if ( predPtr->IsValidDisposable )
   {
      predPtr->ResetSuperstructure();
      predPtr->InvalidateDisposable();
   }
}

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

void $DynText::DoDispose($CI_REF)
{
   Reset($ci);
}

void $DynText::ResetSuperstructure()
{
   _TextPointer_ = L"";
   _Length_ = 0;
   _NeedsFree_ = false;
   _SpecialFreeRoutine_ = nullptr;
}

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

PCWSTR $DynText::T($O) const $alias("Text")
{
   VerifyHasPointer($ci); return _TextPointer_;
}
int $DynText::Length($O) const
{
   VerifyHasPointer($ci); return _Length_;
}
bool $DynText::NeedsFree($O) const
{
   $$VERIFY_VALID_DISPOSABLE(); return _NeedsFree_;
}

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

PCWSTR $DynText::Assign($OA,PCWSTR text) $duplicate $fatal_error_on_failure
{
   $$VERIFY_VALID_DISPOSABLE();
   return DoAssign($ci, text );
}
PCWSTR $DynText::AssignNS($OA,PCWSTR text) $duplicate $null_on_failure $last_error
{
   $$VERIFY_VALID_DISPOSABLE();
   return DoAssignNS($ci, text );
}

PCWSTR $DynText::DoAssign($A,PCWSTR text) $duplicate $fatal_error_on_failure
{
   $$VERIFY_POINTER_ARG( text );
   DoReset();
   int len = $SZ::Length($, text ), capacity = len+1;
   _TextPointer_ = (PWSTR)SetPointer($, $memory::Copy<WCHAR>($, text,
      $memory::Allocate<WCHAR>($, capacity ),
      capacity ));
   _Length_ = len;
   return _TextPointer_;
}
PCWSTR $DynText::DoAssignNS($A,PCWSTR text) $duplicate $null_on_failure $last_error
{
   $$VERIFY_POINTER_ARG( text );
   DoReset();
   int len = $SZ::Length($, text ), capacity = len+1;
   PWSTR textPointer = $memory::AllocateNS<WCHAR>($, capacity );
   if ( !textPointer ) return nullptr;
   _TextPointer_ = (PWSTR)SetPointer($, $memory::Copy<WCHAR>($, text, textPointer, capacity ) );
   _Length_ = len;
   return $RESET_LE( textPointer );
}

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

PCWSTR $DynText::SetPointer($OA,PWSTR textPointer) $imaginary_param("needsFree",true)
{
   return SetPointer($ci, textPointer, true );
}
PCWSTR $DynText::SetPointer($OA,PWSTR textPointer,bool needsFree)
{
   $$VERIFY_VALID_DISPOSABLE();
   return DoSetPointer($ci, textPointer, needsFree );
}
PCWSTR $DynText::SetPointer($OA,PWSTR textPointer,$MemFreeRoutine specialFreeRoutine $optional)
{
   $$VERIFY_VALID_DISPOSABLE();
   return DoSetPointer($ci, textPointer, specialFreeRoutine );
}
PCWSTR $DynText::SetStaticText($OA,PCWSTR textPointer $static_pointer)
{
   return SetPointer($ci, (PWSTR)textPointer, false );
}

PCWSTR $DynText::DoSetPointer($OA,PWSTR textPointer,bool needsFree)
{
   $$VERIFY_POINTER_ARG( textPointer );
   DoReset();
   _TextPointer_ = textPointer;
   _Length_ = $SZ::Length($, textPointer );
   _NeedsFree_ = needsFree;
   return textPointer;
}
PCWSTR $DynText::DoSetPointer($A,PWSTR textPointer,$MemFreeRoutine specialFreeRoutine $optional)
{
   $$VERIFY_POINTER_ARG( textPointer );
   DoReset();
   _TextPointer_ = textPointer;
   _Length_ = $SZ::Length($, textPointer );
   _NeedsFree_ = true;
   _SpecialFreeRoutine_ = specialFreeRoutine;
   return textPointer;
}

PWSTR $DynText::TakePointerOwnership($OM) $not_null $fatal_error_on_failure $needs_free
{
   VerifyHasPointer($$CI);
   PWSTR rslt = _NeedsFree_ ? _TextPointer_ : $SZ::Duplicate($,$ci, _TextPointer_ );
   ResetSuperstructure();
   _TextPointer_ = nullptr;
   return rslt;
}
PWSTR $DynText::TakePointerOwnershipNS($OM) $null_on_failure $last_error $needs_free
{
   VerifyHasPointer($$CI);
   PWSTR rslt = _NeedsFree_ ? _TextPointer_ : $SZ::DuplicateNS($,$ci, _TextPointer_ );
   if ( rslt )
   {
      ResetSuperstructure();
      _TextPointer_ = nullptr;
   }
   return rslt;
}

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

void $DynText::Reset($O)
{
   $$VERIFY_VALID_DISPOSABLE();
   DoReset();
}
void $DynText::ResetToNull($O)
{
   Reset($ci); _TextPointer_ = nullptr;
}

void $DynText::DoReset()
{
   PWSTR pointer = _NeedsFree_ ? _TextPointer_ : nullptr;
   auto specialFreeRoutine = _SpecialFreeRoutine_;
   ResetSuperstructure();
   if ( pointer )
      if ( specialFreeRoutine )
         specialFreeRoutine( pointer );
      else
         $Memory::Free( pointer );
}

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

bool $DynText::GetIsNull() const
{
   return !_TextPointer_;
}
bool $DynText::GetHasPointer() const
{
   return $BOOL( _TextPointer_ );
}
void $DynText::VerifyHasPointer($O) const
{
   $$VERIFY_VALID_DISPOSABLE();
   if ( !_TextPointer_ )
      $INVALID_OPERATION_WITH_MESSAGE( $TEXT(
         L"String pointer is null ($DynText).",
         L"Нулевой указатель строки ($DynText)." ));
}

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

$DynText $DynText::CreateStatic($A,PCWSTR textPointer $static_pointer)
{
   $DynText dt($ci, (PWSTR)textPointer, false );
   return dt;
}
$DynText $DynText::CreateNull()
{
   $DynText dt; dt._TextPointer_ = nullptr; return dt;
}

$DynText $DynText::FromAllocation(PWSTR textPointerOrNull $optional)
{
   $DynText dt;
   if ( textPointerOrNull )
      dt.SetPointer($, textPointerOrNull );
   else
      dt._TextPointer_ = nullptr;
   return dt;
}

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

$DynText $DynText::Format($A,PCWSTR messageFmt, ... ) $fatal_error_on_failure
{
   $$VERIFY_POINTER_ARG( messageFmt );
   va_list argList;
   auto rslt = FormatVA($ci, $VA_COMPLEMENT( messageFmt, argList ) );
   va_end( argList );
   return rslt;
}
$DynText $DynText::FormatVA($A,PCWSTR messageFmt,va_list argList) $fatal_error_on_failure
{
   return $DynText($, $SZ::FormatAllocVA($ci, messageFmt, argList ), true );
}

$DynText $DynText::FormatNS($A,PCWSTR messageFmt, ... ) $null_on_failure $last_error
{
   $$VERIFY_POINTER_ARG( messageFmt );
   va_list argList;
   auto rslt = FormatVANS($ci, $VA_COMPLEMENT( messageFmt, argList ) );
   va_end( argList );
   return rslt;
}
$DynText $DynText::FormatVANS($A,PCWSTR messageFmt,va_list argList) $null_on_failure $last_error
{
   PWSTR pString = $SZ::FormatAllocVANS($ci, messageFmt, argList );
   return pString ? $DynText($, pString, true ) : CreateNull();
}

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

$DynText $DynText::NoError_Message()
{
   return $DynText::CreateStatic($, $StaticMessages::NoError() );
}
$DynText $DynText::UnknownError_Message()
{
   return $DynText::CreateStatic($, $StaticMessages::UnknownError() );
}
$DynText $DynText::MemoryAllocationFailure_Message()
{
   return $DynText::CreateStatic($, $StaticMessages::MemoryAllocationFailure() );
}

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

bool $DynText::SetMessage_NoError($O) $ret_true
{
   SetStaticText($, $StaticMessages::NoError() );
   return true;
}
bool $DynText::SetMessage_UnknownError($O) $ret_false
{
   SetStaticText($, $StaticMessages::UnknownError() );
   return false;
}
bool $DynText::SetMessage_MemoryAllocationFailure($O) $ret_false
{
   SetStaticText($, $StaticMessages::MemoryAllocationFailure() );
   return false;
}

//==================================================================================================
} // RuntimeForStatic
