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

template<typename T>$tstatic<T>::$tstatic($A, int slotIdx )
{
   $TLS::VerifyIndexValue($ci, L"slotIdx", slotIdx );
   ResetSuperstructure();
   _SlotIdx_ = slotIdx;
   ValidateDisposable($$);
}

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

template<typename T>$tstatic<T>& $tstatic<T>::operator = ($tstatic<T>& predecessor)
{
   $memory::Copy($, &predecessor, this );
   if ( predecessor.IsValidDisposable )
   {
      predecessor.DetachReference();
      predecessor.Dispose();
   }
   return *this;
}

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

template<typename T>T& $tstatic<T>::D($O) const $alias("Data")
{
   return *P($ci);
}
template<typename T>T* $tstatic<T>::P($O) const $alias("Pointer") $strict_result
{
   $$VERIFY_VALID_DISPOSABLE();
   T* pointer = GetPointer();
   if ( !pointer )
      $INVALID_OPERATION_WITH_MESSAGE( $TEXT(
         L"TLS-refefence was not attached.\r\n"
         L"(Slot pointer has null value.)",
         L"Ссылка “TLS” не была подключена.\r\n"
         L"(Указатель слота не содержит действительного значения.)" ));
   return pointer;
}
template<typename T>DWORD $tstatic<T>::SlotIdx($O) const
{
   $$VERIFY_VALID_DISPOSABLE(); return _SlotIdx_;
}

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

template<typename T>bool $tstatic<T>::GetHasReference() const
{
   return $BOOL( GetPointer() );
}
template<typename T>bool $tstatic<T>::GetAutoFree() const
{
   return IsValidDisposable && _AutoFree_;
}
template<typename T>bool $tstatic<T>::GetIsDeletable() const
{
   return IsValidDisposable && _IsDeletable_;
}
template<typename T>bool $tstatic<T>::GetIsDeletableArray() const
{
   return IsValidDisposable && _IsDeletableArray_;
}

template<typename T>void $tstatic<T>::VerifyHasReference($O) const
{
   $$VERIFY_VALID_DISPOSABLE();
   if ( !HasReference )
      $INVALID_OPERATION_WITH_MESSAGE( $TEXT(
         L"T-static reference has not been attached.",
         L"Ссылка “T-static” не была подключена." ));
}
template<typename T>void $tstatic<T>::VerifyReferenceNotAttached($O) const
{
   if ( HasReference )
      $INVALID_OPERATION_WITH_MESSAGE( $TEXT(
         L"T-static reference must not be attached.",
         L"Ссылка “T-static” не должна быть подключена." ));
}

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

template<typename T>void $tstatic<T>::AttachMemory($OA, T* pointer )
                                                        $imaginary_param("autoFree",true)
{
   AttachMemory( pointer, true );
}
template<typename T>void $tstatic<T>::AttachMemory($OA,T* pointer,bool autoFree)
{
   $$VERIFY_VALID_DISPOSABLE();
   VerifyDoesNotHaveReference($ci);
   SetPointer( pointer );
   _AutoFree_ = autoFree;
}

template<typename T>void $tstatic<T>::AttachDeletable($OA,T* pointer)
{
   AttachDeletable($ci, pointer, false );
}
template<typename T>void $tstatic<T>::AttachDeletable($OA,T* pointer,bool isArray)
{
   $$VERIFY_VALID_DISPOSABLE();
   VerifyDoesNotHaveReference($ci);
   $$VERIFY_POINTER_ARG( pointer );
   SetPointer( pointer );
   _IsDeletable_ = true;
   _IsDeletableArray_ = isArray;
}

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

template<typename T>void $tstatic<T>::DetachReference()
{
   ResetSuperstructure();
}

template<typename T>void $tstatic<T>::ReleaseAutoRC()
{
   T* pointer = _Pointer_;
   if ( pointer )
   {
      ResetSuperstructure();
      if ( releaseRC )
         if ( AutoFree )
            $Memory::Free( pointer );
         else
         if ( IsDeletable )
            if ( IsDeletableArray )
               delete[] pointer;
            else
               delete pointer;
         else
            $DEAD_CODE_BRANCH();
   }
}

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

template<typename T>void $tstatic<T>::DoDispose($CI_REF)
{
   ReleaseAutoRC();
}

template<typename T>void $tstatic<T>::ResetSuperstructure()
{
   _AutoFree_ = _IsDeletable_ = _IsDeletableArray_ = false;
   if ( _SlotIdx_ != TLS_OUT_OF_INDEXES )
      ResetPointer();
}

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

template<typename T>$tstatic<T> $tstatic<T>::CreateAttachMemory($A,
   int slotIdx, T* pointer )
   $imaginary_param("autoFree",true)
{
   return CreateAttachMemory($ci, slotIdx, pointer, true );
}
template<typename T>$tstatic<T> $tstatic<T>::CreateAttachMemory($A, int slotIdx,
                                                                    T* pointer,
                                                                    bool autoFree )
{
   $tstatic<T>&& instance = $tstatic($ci, slotIdx );
   instance.AttachMemory($ci, pointer, autoFree );
   return instance;
}

template<typename T>$tstatic<T> $tstatic<T>::CreateAttachDeletable($A,int slotIdx,T* pointer)
{
   return CreateAttachDeletable($ci, slotIdx, pointer, false );
}
template<typename T>$tstatic<T> $tstatic<T>::CreateAttachDeletable($A, int slotIdx,
                                                                       T* pointer,
                                                                       bool isArray )
{
   $tstatic<T>&& instance = $tstatic($ci, slotIdx );
   instance.AttachDeletable($ci, pointer, isArray );
   return instance;
}

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

template<typename T>T* $tstatic<T>::GetPointer() const
{
   PVOID pointer = ::TlsGetValue( _SlotIdx_ );
   if ( !pointer && ::GetLastError() )
      $FATAL_ERROR_LAST_SYSTEM();
   return (T*)pointer;
}
template<typename T>void $tstatic<T>::SetPointer(T* pointer)
{
   if ( !::TlsSetValue( _SlotIdx_, pointer ) )
      $FATAL_ERROR_LAST_SYSTEM();
}
template<typename T>void $tstatic<T>::ResetPointer()
{
   SetPointer( nullptr );
}

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