// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //
//  »Project«   Talina Gaming System (TgS) (∂)
//  »File«      TgS Common - Base - Defines.h
//  »Author«    Andrew Aye (EMail: mailto:andrew.aye@gmail.com, Web: http://www.andrewaye.com)
//  »Version«   4.0
// ------------------------------------------------------------------------------------------------------------------------------ //
//  Copyright: © 2002-2010, Andrew Aye.  All Rights Reserved.
//  This software is free for non-commercial use. Redistribution and use in source and binary forms, with or without modification,
//  are permitted provided that the following conditions are met: 
//    Redistributions of source code must retain this copyright notice, this list of conditions and the following disclaimers. 
//    Redistributions in binary form must reproduce this copyright notice, this list of conditions and the following
//      disclaimers in the documentation and other materials provided with the distribution. 
//  Neither the names of the copyright owner nor the names of its contributors may be used to endorse or promote products derived
//  from this software without specific prior written permission. 
//  The intellectual property rights of the algorithms used reside with Andrew Aye.  You may not use this software, in whole or
//  in part, in support of any commercial product without the express written consent of the author.
//  There is no warranty or other guarantee of fitness of this software for any purpose. It is provided solely "as is".
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //
#if !defined(_TGS_COMMON_BASE_DEFINES_H_)
#define _TGS_COMMON_BASE_DEFINES_H_
#pragma once

#include "TgS COMMON/TgS Common - Base - Define - Configuration.h"


// ============================================================================================================================== //
// -- Basic DEFINE routines ----------------------------------------------------------------------------------------------------- //

//#define TgSAFE_DEL_ARRAY(p)                 { if (p) { tgMM_Free_Pool(p); (p)=NULL; } };
#define TgSAFE_RELEASE(p)                   { if ((p)) { (p)->Release(); (p)=NULL; } };
#define TgSAFE_ASSIGN_REF( a, b )           { TgSAFE_RELEASE(a); if ( NULL != (b) ) { (a) = (b); (a)->AddRef(); } };
//#define TgSAFE_FREE(p)                      { if (p) { tgMM_Free_Pool(p); (p) = NULL; } };

#define TgPERM(A,B,C,D)                     ((D<<6) | (C<<4) | (B<<2) | A)

// ============================================================================================================================== //
// -- Base Defines -------------------------------------------------------------------------------------------------------------- //

#if TgS_COMPILE_ASSERT

    #if (_MSC_VER >= 1600 && !defined(__STDC__))
        #define TgCOMPILER_ASSERT_MSG(x,...)        static_assert(x,__VA_ARGS__);
        #define TgCOMPILER_ASSERT(x)                static_assert(x,"");
    #else
        #define TgCOMPILER_ASSERT_MSG(x,...)        typedef int COMPILER_ASSERT_[(x) ? 1 : -1];
        #define TgCOMPILER_ASSERT(x)                typedef int COMPILER_ASSERT_[(x) ? 1 : -1];
        #define nullptr                             NULL
    #endif

    // Critical validation is for things that would put the executable in an unstable and usable state.  These are important
    // enough that they are left in the compilation even during a final build (one used for certification).  This will cause a
    // break in a shipping product.

    #define TgCRITICAL_MSG( A, ... )            MSVC_ATTRIBUTE(__analysis_assume(A));                                           \
                                                if (!(A))                                                                       \
                                                {                                                                               \
                                                    TgLOG( KTgCON_CHANEL_CRITICAL, __VA_ARGS__ );                               \
                                                    tgPM_Abort();                                                               \
                                                };

    #define TgCRITICAL_MSGF( A, ... )           MSVC_ATTRIBUTE(__analysis_assume(A));                                           \
                                                if (!(A))                                                                       \
                                                {                                                                               \
                                                    TgLOGF( KTgCON_CHANEL_CRITICAL, __VA_ARGS__ );                              \
                                                    tgPM_Abort();                                                               \
                                                };

    #define TgCRITICAL( A )                     MSVC_ATTRIBUTE(__analysis_assume(A));                                           \
                                                if (!(A))                                                                       \
                                                {                                                                               \
                                                    TgLOG( KTgCON_CHANEL_CRITICAL, TgT(#A) TgT("\n") );                         \
                                                    tgPM_Abort();                                                               \
                                                };

    // Asserts are used in release and debug executables when continuing execution is undesirable.  Most often this is the case
    // similar to above, where the executable would be in an illegal state.  These are often used for bounds checking.  The
    // difference is that asserts can be used to validate values and quantities during development that are "assumed" to be valid
    // in a final build.

    #define TgERROR_MSG( A, ... )               MSVC_ATTRIBUTE(__analysis_assume(A));                                           \
                                                if (!(A))                                                                       \
                                                {                                                                               \
                                                    TgLOG( KTgCON_CHANEL_ERROR, __VA_ARGS__ );                                  \
                                                };

    #define TgERROR_MSGF( A, ... )              MSVC_ATTRIBUTE(__analysis_assume(A));                                           \
                                                if (!(A))                                                                       \
                                                {                                                                               \
                                                    TgLOGF( KTgCON_CHANEL_ERROR, __VA_ARGS__ );                                 \
                                                };

    #define TgERROR( A )                        MSVC_ATTRIBUTE(__analysis_assume(A));                                           \
                                                if (!(A))                                                                       \
                                                {                                                                               \
                                                    TgLOG( KTgCON_CHANEL_ERROR, TgT(#A) TgT("\n") );                            \
                                                };

    #define TgASSERT_MSG                        TgERROR_MSG
    #define TgASSERT_MSGF                       TgERROR_MSGF
    #define TgASSERT                            TgERROR
    #define TgASSERT_PARAM                      TgERROR

    #define TgDIAG_ASSERT_MSG( A, ... )         MSVC_ATTRIBUTE(__analysis_assume(A));                                           \
                                                {                                                                               \
                                                    static TgBOOL bSkip = TgFALSE;                                              \
                                                    if (!bSkip && !(A))                                                         \
                                                    {                                                                           \
                                                        TgLOG( KTgCON_CHANEL_ERROR, __VA_ARGS__ );                              \
                                                    };                                                                          \
                                                };

    #define TgDIAG_ASSERT_MSGF( A, ... )        MSVC_ATTRIBUTE(__analysis_assume(A));                                           \
                                                {                                                                               \
                                                    static TgBOOL bSkip = TgFALSE;                                              \
                                                    if (!bSkip && !(A))                                                         \
                                                    {                                                                           \
                                                        TgLOGF( KTgCON_CHANEL_ERROR, __VA_ARGS__ );                             \
                                                    };                                                                          \
                                                };

    #define TgDIAG_ASSERT( A )                  MSVC_ATTRIBUTE(__analysis_assume(A));                                           \
                                                {                                                                               \
                                                    static TgBOOL bSkip = TgFALSE;                                              \
                                                    if (!bSkip && !(A))                                                         \
                                                    {                                                                           \
                                                        TgLOG( KTgCON_CHANEL_ERROR, TgT(#A) TgT("\n") );                        \
                                                    };                                                                          \
                                                };

    #define TgVERIFY_MSG( A, ... )              {                                                                               \
                                                    static TgBOOL bSkip = TgFALSE;                                              \
                                                    if (!(A) && !bSkip)                                                         \
                                                    {                                                                           \
                                                        TgLOG( KTgCON_CHANEL_ERROR, __VA_ARGS__ );                              \
                                                    };                                                                          \
                                                };

    #define TgVERIFY_MSGF( A, ... )             {                                                                               \
                                                    static TgBOOL bSkip = TgFALSE;                                              \
                                                    if (!(A) && !bSkip)                                                         \
                                                    {                                                                           \
                                                        TgLOGF( KTgCON_CHANEL_ERROR, __VA_ARGS__ );                             \
                                                    };                                                                          \
                                                };

    #define TgVERIFY( A )                       {                                                                               \
                                                    static TgBOOL bSkip = TgFALSE;                                              \
                                                    if (!(A) && !bSkip)                                                         \
                                                    {                                                                           \
                                                        TgLOG( KTgCON_CHANEL_ERROR, TgT(#A) TgT("\n") );                        \
                                                    };                                                                          \
                                                };

    // Warnings are used to communicate potential development issues to the console.
    #define TgWARNING_MSG( A, ... )             {                                                                               \
                                                    static TgBOOL bSkip = TgFALSE;                                              \
                                                    if (!bSkip && !(A))                                                         \
                                                    {                                                                           \
                                                        TgLOG( KTgCON_CHANEL_WARNING, __VA_ARGS__ );                            \
                                                    };                                                                          \
                                                };

    #define TgWARNING_MSGF( A, ... )            {                                                                               \
                                                    static TgBOOL bSkip = TgFALSE;                                              \
                                                    if (!bSkip && !(A))                                                         \
                                                    {                                                                           \
                                                        TgLOGF( KTgCON_CHANEL_WARNING, __VA_ARGS__ );                           \
                                                    };                                                                          \
                                                };

    #define TgWARNING( A )                      {                                                                               \
                                                    static TgBOOL bSkip = TgFALSE;                                              \
                                                    if (!bSkip && !(A))                                                         \
                                                    {                                                                           \
                                                        TgLOG( KTgCON_CHANEL_WARNING, TgT(#A) TgT("\n") );                      \
                                                    };                                                                          \
                                                };

    // Messages are used to communicate general development information to the console

    #define TgMSG( L, ... )                     {                                                                               \
                                                    static TgBOOL bSkip = TgFALSE;                                              \
                                                    if (!bSkip)                                                                 \
                                                    {                                                                           \
                                                        TgLOG( KTgCON_CHANEL_MESSAGE|L, __VA_ARGS__ );                          \
                                                    };                                                                          \
                                                };

    #define TgMSGF( L, ... )                    {                                                                               \
                                                    static TgBOOL bSkip = TgFALSE;                                              \
                                                    if (!bSkip)                                                                 \
                                                    {                                                                           \
                                                        TgLOGF( KTgCON_CHANEL_MESSAGE|L, __VA_ARGS__ );                         \
                                                    };                                                                          \
                                                };

#else
    #define TgCOMPILER_ASSERT_MSGF(x,...)        
    #define TgCOMPILER_ASSERT_MSG(x,...)        
    #define TgCOMPILER_ASSERT(x)                
    #define TgCRITICAL_MSGF( A, ... )            
    #define TgCRITICAL_MSG( A, ... )            
    #define TgCRITICAL( A )                     
    #define TgERROR_MSGF( A, ... )               
    #define TgERROR_MSG( A, ... )               
    #define TgERROR( A )                        
    #define TgASSERT_MSGF( A, ... )              
    #define TgASSERT_MSG( A, ... )              
    #define TgASSERT( A )                       
    #define TgASSERT_PARAM( A, ... )            
    #define TgDIAG_ASSERT_MSGF( A, ... )         
    #define TgDIAG_ASSERT_MSG( A, ... )         
    #define TgDIAG_ASSERT( A )                  
    #define TgVERIFY_MSGF( A, ... )             (void)(A)
    #define TgVERIFY_MSG( A, ... )              (void)(A)
    #define TgVERIFY( A )                       (void)(A)
    #define TgWARNING_MSGF( A, ... )             
    #define TgWARNING_MSG( A, ... )             
    #define TgWARNING( A )                      
    #define TgMSGF( A, ... )             
    #define TgMSG( A, ... )             
#endif

#if TgS_COMPILE_MEM_TRACK
//    #define TgVSAFE_RELEASE(p)                  { if (p) { TgVERIFY( 0 == (p)->Release() ); (p)=NULL; } };
//    #define TgNEW_INPLACE(A)                    new( A, TgWIDEN(__FILE__), __LINE__, TgS_OPERATOR() )
//    #define TgNEW                               new( TgWIDEN(__FILE__), __LINE__, TgS_OPERATOR() )
//    #define TgDELETE(A)                         (pszSourceFile = TgWIDEN(__FILE__), uiSourceLine = __LINE__), delete A 
//    #define TgDELETE_ARRAY(A)                   (pszSourceFile = TgWIDEN(__FILE__), uiSourceLine = __LINE__), delete[] A
    #define TgMALLOC_EXACT(A)                   tgMM_Malloc_Exact( A, TgWIDEN(__FILE__), __LINE__ )
    #define TgFREE__EXACT(A)                    tgMM_Free_Exact( A, TgWIDEN(__FILE__), __LINE__ )
    #define TgMALLOC_POOL(A)                    tgMM_Malloc_Pool( A, TgWIDEN(__FILE__), __LINE__ )
    #define TgFREE_POOL(A)                      tgMM_Free_Pool( A, TgWIDEN(__FILE__), __LINE__ )
    #define TgREALLOC_POOL(A,B)                 tgMM_Realloc_Pool( A,B, TgWIDEN(__FILE__), __LINE__ )
    #define TgMALLOC_TEMP(A)                    tgMM_Malloc_Temp( A, TgWIDEN(__FILE__), __LINE__ )
    #define TgFREE_TEMP(A)                      tgMM_Free_Temp( A, TgWIDEN(__FILE__), __LINE__ )
    #define TgPUSH_SCRATCH(A)                   tgMM_Push_Scratch( A, TgWIDEN(__FILE__), __LINE__ )
    #define TgPOP_SCRATCH(A)                    tgMM_Pop_Scratch( A, TgWIDEN(__FILE__), __LINE__ )
    #define TgMALLOC_PHYSICAL(A,B,C)            tgMM_Malloc_Physical( A,B,C, TgWIDEN(__FILE__), __LINE__ )
    #define TgFREE_PHYSICAL(A)                  tgMM_Free_Physical( A, TgWIDEN(__FILE__), __LINE__ )
    #define TgMALLOC_VIRTUAL(A)                 tgMM_Malloc_Virtual( A, TgWIDEN(__FILE__), __LINE__ )
    #define TgCOMMIT_VIRTUAL(A,B)               tgMM_Commit_Virtual( A,B, TgWIDEN(__FILE__), __LINE__ )
    #define TgFREE_VIRTUAL(A)                   tgMM_Free_Virtual( A, TgWIDEN(__FILE__), __LINE__ )
#else
//    #define TgVSAFE_RELEASE(p)                  { if (p) { TgVERIFY( 0 == (p)->Release() ); (p)=NULL; } };
//    #define TgNEW_INPLACE(A)                    new( A, 0, 0, TgS_OPERATOR() )
//    #define TgNEW                               new( 0, 0, TgS_OPERATOR() )
//    #define TgDELETE(A)                         delete( A )
//    #define TgDELETE_ARRAY(A)                   delete[]( A )
    #define TgMALLOC_EXACT(A)                   tgMM_Malloc_Exact( A )
    #define TgFREE__EXACT(A)                    tgMM_Free_Exact( A )
    #define TgMALLOC_POOL(A)                    tgMM_Malloc_Pool( A )
    #define TgFREE_POOL(A)                      tgMM_Free_Pool( A )
    #define TgREALLOC_POOL(A,B)                 tgMM_Realloc_Pool( A,B )
    #define TgMALLOC_TEMP(A)                    tgMM_Malloc_Temp( A )
    #define TgFREE_TEMP(A)                      tgMM_Free_Temp( A )
    #define TgPUSH_SCRATCH(A)                   tgMM_Push_Scratch( A )
    #define TgPOP_SCRATCH(A)                    tgMM_Pop_Scratch( A )
    #define TgMALLOC_PHYSICAL(A,B,C)            tgMM_Malloc_Physical( A,B,C )
    #define TgFREE_PHYSICAL(A)                  tgMM_Free_Physical( A )
    #define TgMALLOC_VIRTUAL(A)                 tgMM_Malloc_Virtual( A )
    #define TgCOMMIT_VIRTUAL(A,B)               tgMM_Commit_Virtual( A,B )
    #define TgFREE_VIRTUAL(A)                   tgMM_Free_Virtual( A )
#endif

// ============================================================================================================================== //
// -- Base TgS RESULT Values ---------------------------------------------------------------------------------------------------- //

#define MAKE_TgRESULT(fac,code)             ((TgSINT32) (((TgRESULT)(fac)<<16) | ((TgRESULT)(code))))
#define MAKE_ERROR(A,B)                     CTgERROR( TgWIDEN(__FILE__), __LINE__, A, B )

// 64 Libraries, 256 Classes per Library, 262144 Functions per Class - 32 bits to describe overloads/parameters
#define MAKE_CODE(lib,cls,fcn,pm) \
    ((TgUINT64) (((TgUINT64)(lib)) | ((TgUINT64)(cls) >> 6) | ((TgUINT64)(fcn) >> 14) | ((TgUINT64)(pm) >> 32) ))

#define TM_TIMER                            1L
#define TIME_MAXITERATIONS                  7

// ============================================================================================================================== //
// -- Code Helpers -------------------------------------------------------------------------------------------------------------- //

#define TgSUCCEEDED(Status)                 ((TgSINT32)(Status) >= 0)
#define TgFAILED(Status)                    ((TgSINT32)(Status) <  0)

#define TgTYPE_PREFIX(B)                    typedef const B                             C_##B;                  \
                                            typedef B *                                 P_##B;                  \
                                            typedef B * const                           PC_##B;                 \
                                            typedef B * const __restrict                PCU_##B;                \
                                            typedef B * __restrict                      PU_##B;                 \
                                            typedef const B *                           CP_##B;                 \
                                            typedef const B * __restrict                CPU_##B;                \
                                            typedef const B * const                     CPC_##B;                \
                                            typedef const B * const __restrict          CPCU_##B;               \
                                            typedef B**                                 PP_##B;                 \
                                            typedef B ** __restrict                     PP_U##B;                \
                                            typedef const B *const * __restrict         CPCPU_##B;              \
                                            typedef const B ** __restrict               CPPU_##B;               \
                                            typedef B ** const __restrict               PPCU_##B                \

#define TgTYPE_DECLARE(A,B)                 typedef A                                   B;                      \
                                            TgTYPE_PREFIX( B )

#define TgFOURCC(ch0, ch1, ch2, ch3)        (((TgUINT32)(TgUINT08)(ch0)      ) | ((TgUINT32)(TgUINT08)(ch1) << 8  ) | \
                                             ((TgUINT32)(TgUINT08)(ch2) << 16) | ((TgUINT32)(TgUINT08)(ch3) << 24 ))

#define TgKI_DECLARE(A)                                                                                                         \
                                                                                                                                \
    typedef struct                                                                                                              \
    {                                                                                                                           \
        TgUINT16 uiK;                                                                                                           \
        TgUINT16 uiI;                                                                                                           \
    } Tg##A##_ELEM;                                                                                                             \
    typedef union                                                                                                               \
    {                                                                                                                           \
        TgUINT32 m_uiKI;                                                                                                        \
        Tg##A##_ELEM m;                                                                                                         \
    } Tg##A;                                                                                                                    \
                                                                                                                                \
    TgTYPE_PREFIX( Tg##A );                                                                                                     \
                                                                                                                                \
    extern TgATOMIC_INT32 tgKI_NUI_##A;                                                                                         \
    extern C_Tg##A tgKI_INVALID_##A;                                                                                            \
                                                                                                                                \
    TgINLINE TgVOID tgInit_##A( PCU_Tg##A ptgKI, C_TgUINT16 uiI )                                                          \
    {                                                                                                                           \
        ptgKI->m.uiK = tgAM32_INC(&tgKI_NUI_##A) & 0xFFFF;                                                                      \
        ptgKI->m.uiI = uiI;                                                                                                     \
    }                                                                                                                           \
                                                                                                                                \
    TgINLINE TgBOOL tgEQ_##A( CPCU_Tg##A ptgK0, CPCU_Tg##A ptgK1 )                                                         \
    {                                                                                                                           \
        return (ptgK0->m_uiKI == ptgK1->m_uiKI);                                                                                \
    }                                                                                                                           

#define TgKI_DEFINE(A)                                                                                                          \
    TgATOMIC_INT32 tgKI_NUI_##A;                                                                                                \
    C_Tg##A tgKI_INVALID_##A = { ~0u };

#if TgS_WIDE_CHAR
    #define TgT( A )                            L##A
    #define TgTEXT( A )                         L##A
#else
    #define TgT( A )                            A
    #define TgTEXT( A )                         A
#endif
#define TgWIDEN( A)                         TgT(A)

#define TgTEST_MSG( A, ... )                {                                                                                   \
                                                if (!(A))                                                                       \
                                                {                                                                               \
                                                    TgLOG( KTgCON_CHANEL_ERROR, TgT("FAILED: ") TgT(#A) TgT("\n") );        \
                                                    tgPM_Break();                                                               \
                                                }                                                                               \
                                                else                                                                            \
                                                {                                                                               \
                                                    TgLOG( KTgCON_CHANEL_MESSAGE, TgT("PASSED: ") TgT(#A) TgT("\n") );      \
                                                };                                                                              \
                                            };

// ============================================================================================================================== //
// -- Optimization Macros ------------------------------------------------------------------------------------------------------- //

// Optimizer Hints
#if TgS_COMPILE_ASSERT
    #define TgS_NO_DEFAULT(A)   TgCRITICAL(0); A
#elif defined(_MSC_VER)
    #define TgS_NO_DEFAULT(A)   __assume(0)
#else
    #define TgS_NO_DEFAULT(A)   A
#endif

#endif //  END  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////