/*---------------------------------------------------------------------------*
  Project:  Manual 2D Library - m2d
  File:     RuntimeTypeInfo.h

  Copyright (C)2007-2009 Nintendo  All Rights Reserved.

  These coded instructions, statements, and computer programs contain
  proprietary information of Nintendo of America Inc. and/or Nintendo
  Company Ltd., and are protected by Federal copyright law. They may
  not be disclosed to third parties or copied or duplicated in any form,
  in whole or in part, without the prior written consent of Nintendo.

  $Revision: 1.8 $
 *---------------------------------------------------------------------------*/

#ifndef NTMV_RNT_RUNTIME_TYPEINFO_H_
#define NTMV_RNT_RUNTIME_TYPEINFO_H_

#include <stddef.h>
#include <nitro/types.h>

namespace ntmv
{
namespace m2d
{

//--------------------------------------------------------------------
// This macro embeds run-time type information, required to enable dynamic casting, in members.
// 
// It is indicated in the class declaration.
//--------------------------------------------------------------------
#define NTMV_RNT_RUNTIME_TYPEINFO \
    virtual const ntmv::m2d::detail::RuntimeTypeInfo*    GetRuntimeTypeInfo() const { return &typeInfo; } \
    static  const ntmv::m2d::detail::RuntimeTypeInfo     typeInfo


//--------------------------------------------------------------------
// This macro defines run-time type information for an instance of a class.
// 
// This is written using the format NTMV_RNT_RUNTIME_TYPEINFO_ROOT_DEFINITION(class name) for the base class and NTMV_RNT_RUNTIME_TYPEINFO_DEFINITION(class name, base class name) for derived classes.
//    
// 
// 
// 
//--------------------------------------------------------------------
#define NTMV_RNT_RUNTIME_TYPEINFO_DEFINITION(derived,base) \
    const ntmv::m2d::detail::RuntimeTypeInfo derived::typeInfo( &base::typeInfo )

#define NTMV_RNT_RUNTIME_TYPEINFO_ROOT_DEFINITION(root) \
    const ntmv::m2d::detail::RuntimeTypeInfo root::typeInfo( NULL )


namespace detail
{

//--------------------------------------------------------------------
// 
// Run-time type information structure
// 
//--------------------------------------------------------------------
struct RuntimeTypeInfo
{
    const RuntimeTypeInfo*  mParentTypeInfo;
    
    /* ctor */ explicit  RuntimeTypeInfo( const RuntimeTypeInfo* parent ) : mParentTypeInfo( parent ) {}
    
    bool                 IsDerivedFrom( const RuntimeTypeInfo* typeInfo ) const
    {
        const RuntimeTypeInfo *self = this;
        
        while ( self )
        {
            if ( self == typeInfo )
            {
                return true;
            }
            self = self->mParentTypeInfo;
        }
        return false;
    }
};

//
// Get static members from pointers
// Derived* pDerived = DynamicCast<Derived*>( pBase );
// template function for writing it this way
//
template<class T>
inline const RuntimeTypeInfo*
GetTypeInfoFromPtr_(T* /* _dummy */)
{
    return &T::typeInfo;
}


}   // namespace detail


// 
// template function for downcasting
// 
template<class UP, class T>
inline UP DynamicCast(T* obj)
{
    const detail::RuntimeTypeInfo* typeInfoU = detail::GetTypeInfoFromPtr_( UP(0) );
    if ( obj && obj->GetRuntimeTypeInfo()->IsDerivedFrom( typeInfoU ) )
    {
        return static_cast<UP>(obj);
    }
    return NULL;
}


}   // namespace m2d
}   // namespace ntmv

/* NTMV_RNT_RUNTIME_TYPEINFO_H_ */
#endif
