// @(#)root/reflex:$Name:  $:$Id: Type.cxx,v 1.24 2006/11/30 11:37:15 roiser Exp $
// Author: Stefan Roiser 2004

// Copyright CERN, CH-1211 Geneva 23, 2004-2006, All rights reserved.
//
// Permission to use, copy, modify, and distribute this software for any
// purpose is hereby granted without fee, provided that this copyright and
// permissions notice appear in all copies and derivatives.
//
// This software is provided "as is" without express or implied warranty.

#ifndef REFLEX_BUILD
#define REFLEX_BUILD
#endif

#include "Reflex/Type.h"

#include "Reflex/Object.h"
#include "Reflex/Scope.h"
#include "Reflex/Base.h"
#include "Reflex/MemberTemplate.h"
#include "Reflex/TypeTemplate.h"
#include "Reflex/DictionaryGenerator.h"

#include "Enum.h"
#include "Union.h"
#include "Class.h"
#include "Reflex/Tools.h"


//-------------------------------------------------------------------------------
ROOT::Reflex::Type::operator ROOT::Reflex::Scope () const {
//-------------------------------------------------------------------------------
// Conversion operator to Scope.
   if ( * this ) return *(fTypeName->fTypeBase);
   return Dummy::Scope();
}


//-------------------------------------------------------------------------------
ROOT::Reflex::Base ROOT::Reflex::Type::BaseAt( size_t nth ) const {
//-------------------------------------------------------------------------------
// Return nth base info.
   if ( * this ) return fTypeName->fTypeBase->BaseAt( nth );
   return Dummy::Base();
}


//-------------------------------------------------------------------------------
ROOT::Reflex::Type
ROOT::Reflex::Type::ByName( const std::string & key ) {
//-------------------------------------------------------------------------------
// Lookup a type by its fully qualified name.
   return TypeName::ByName( key );
}


//-------------------------------------------------------------------------------
ROOT::Reflex::Type
ROOT::Reflex::Type::ByTypeInfo( const std::type_info & tid ) {
//-------------------------------------------------------------------------------
// Lookup a type by its type_info.
   return TypeName::ByTypeInfo( tid );
}


//-------------------------------------------------------------------------------
ROOT::Reflex::Object
ROOT::Reflex::Type::CastObject( const Type & to,
                                const Object & obj ) const {
//-------------------------------------------------------------------------------
// Cast the current type to "to" using the object obj.
   if ( * this ) return fTypeName->fTypeBase->CastObject( to, obj );
   return Dummy::Object();
}


/*/-------------------------------------------------------------------------------
  ROOT::Reflex::Object 
  ROOT::Reflex::Type::Construct( const Type & signature,
  const std::vector < Object > & values, 
  void * mem ) const {
  //-------------------------------------------------------------------------------
  if ( * this ) return fTypeName->fTypeBase->Construct( signature, 
  values, 
  mem ); 
  return Object();
  }
*/


//-------------------------------------------------------------------------------
ROOT::Reflex::Object
ROOT::Reflex::Type::Construct( const Type & signature,
                               const std::vector < void * > & values, 
                               void * mem ) const {
//-------------------------------------------------------------------------------
// Construct this type and return it as an object. Signature can be used for overloaded
// constructors. Values is a collection of memory addresses of paramters. Mem the memory
// address for in place construction.
   if ( * this ) return fTypeName->fTypeBase->Construct( signature, 
                                                         values, 
                                                         mem ); 
   return Dummy::Object();
}


//-------------------------------------------------------------------------------
ROOT::Reflex::Member ROOT::Reflex::Type::DataMemberAt( size_t nth ) const {
//-------------------------------------------------------------------------------
// Return the nth data member.
   if ( * this ) return fTypeName->fTypeBase->DataMemberAt( nth );
   return Dummy::Member();
}


//-------------------------------------------------------------------------------
ROOT::Reflex::Member ROOT::Reflex::Type::DataMemberByName( const std::string & nam ) const {
//-------------------------------------------------------------------------------
// Return a data member by name.
   if ( * this ) return fTypeName->fTypeBase->DataMemberByName( nam );
   return Dummy::Member();
}


//-------------------------------------------------------------------------------
ROOT::Reflex::Type ROOT::Reflex::Type::DynamicType( const Object & obj ) const {
//-------------------------------------------------------------------------------
// Return the dynamic type of this type.
   if ( * this ) return fTypeName->fTypeBase->DynamicType( obj );
   return Dummy::Type();
}


//-------------------------------------------------------------------------------
ROOT::Reflex::Member ROOT::Reflex::Type::FunctionMemberAt( size_t nth ) const {
//-------------------------------------------------------------------------------
// Return the nth function member.
   if ( * this ) return fTypeName->fTypeBase->FunctionMemberAt( nth );
   return Dummy::Member();
}


//-------------------------------------------------------------------------------
ROOT::Reflex::Member ROOT::Reflex::Type::FunctionMemberByName( const std::string & nam,
                                                                       const Type & signature ) const {
//-------------------------------------------------------------------------------
// Return a function member by name. Signature can be used for overloaded functions.
   if ( * this ) return fTypeName->fTypeBase->FunctionMemberByName( nam, signature );
   return Dummy::Member();
}


//-------------------------------------------------------------------------------
bool ROOT::Reflex::Type::HasBase( const Type & cl ) const {
//-------------------------------------------------------------------------------
   // Return base info if type has base cl.
   if ( * this ) return fTypeName->fTypeBase->HasBase( cl );
   return false;
}


//-------------------------------------------------------------------------------
bool ROOT::Reflex::Type::IsEquivalentTo( const Type & typ ) const {
//-------------------------------------------------------------------------------
// Check if two types are equivalent. It will compare the information of the type
// depending on the TypeType.
   if ( *this == typ ) return true;

   Type t1 = *this;
   Type t2 = typ;

   unsigned int mod1 = t1.fModifiers;
   unsigned int mod2 = t2.fModifiers;

   while (t1.IsTypedef()) { 
      t1 = t1.ToType();
      mod1 |= t1.fModifiers;
   }
   while ( t2.IsTypedef()) {
      t2 = t2.ToType();
      mod2 |= t2.fModifiers;
   }

   if (mod1 == mod2) {

      switch ( t1.TypeType() ) {
      case CLASS:
      case STRUCT:
      case TYPETEMPLATEINSTANCE:
         if ( t2.IsClass() )           return ( t1.fTypeName == t2.fTypeName ); 
      case FUNDAMENTAL:
         if ( t2.IsFundamental() )     return ( t1.fTypeName == t2.fTypeName );
      case UNION:
         if ( t2.IsUnion() )           return ( t1.fTypeName == t2.fTypeName ); 
      case ENUM:
         if ( t2.IsEnum() )            return ( t1.fTypeName == t2.fTypeName ); 
      case POINTER:
         if ( t2.IsPointer() )         return ( t1.ToType().IsEquivalentTo(t2.ToType()) );
      case POINTERTOMEMBER:
         if ( t2.IsPointerToMember() ) return ( t1.ToType().IsEquivalentTo(t2.ToType()) );
      case ARRAY:
         if ( t2.IsArray() )           return ( t1.ToType().IsEquivalentTo(t2.ToType()) && t1.ArrayLength() == t2.ArrayLength() );
      case FUNCTION:
         if ( t2.IsFunction() ) {

            if ( t1.ReturnType().IsEquivalentTo(t2.ReturnType())) {

               if ( t1.FunctionParameterSize() == t2.FunctionParameterSize() ) {

                  Type_Iterator pi1;
                  Type_Iterator pi2;
                  for ( pi1 = t1.FunctionParameter_Begin(), pi2 = t2.FunctionParameter_Begin(); 
                        pi1 != t1.FunctionParameter_End(),  pi2 != t2.FunctionParameter_End(); 
                        ++pi1, ++pi2 ) {

                     if ( ! pi1->IsEquivalentTo(*pi2)) return false;

                  }
                  return true;
               }
            }
            return false;
         }
      default:
         return false;
      }
   }
   else {
      return false;
   }
}


//-------------------------------------------------------------------------------
ROOT::Reflex::Member ROOT::Reflex::Type::MemberByName( const std::string & nam,
                                                       const Type & signature ) const {
//-------------------------------------------------------------------------------
// Return a member by name. Signature is optional for overloaded function members.
   if ( * this ) return fTypeName->fTypeBase->MemberByName( nam, signature );
   return Dummy::Member();
}


//-------------------------------------------------------------------------------
ROOT::Reflex::Member ROOT::Reflex::Type::MemberAt( size_t nth ) const {
//-------------------------------------------------------------------------------
// Return the nth member.
   if ( * this ) return fTypeName->fTypeBase->MemberAt( nth );
   return Dummy::Member();
}


//-------------------------------------------------------------------------------
ROOT::Reflex::MemberTemplate ROOT::Reflex::Type::MemberTemplateAt( size_t nth ) const {
//-------------------------------------------------------------------------------
// Return the nth member template.
   if ( * this ) return fTypeName->fTypeBase->MemberTemplateAt( nth );
   return Dummy::MemberTemplate();
}


//-------------------------------------------------------------------------------
std::string ROOT::Reflex::Type::Name( unsigned int mod ) const {
//-------------------------------------------------------------------------------
// Return the name of the type (qualified and scoped if requested)

   if (( mod & ( QUALIFIED | Q ))==0 && (* this) ) { 
      // most common case
      return fTypeName->fTypeBase->Name( mod );
   }

   std::string s = "";
   std::string cv = "";

   /** apply qualifications if wanted */
   if ( 0 != ( mod & ( QUALIFIED | Q ))) {
      if ( IsConst() && IsVolatile()) cv = "const volatile";
      else if ( IsConst())            cv = "const";
      else if ( IsVolatile())         cv = "volatile";
   }

   /** if At is not a pointer qualifiers can be put before */
   if ( cv.length() && TypeType() != POINTER && TypeType() != FUNCTION ) s += cv + " ";
  
   /** use implemented names if available */
   if ( * this ) s += fTypeName->fTypeBase->Name( mod );
   /** otherwise use the TypeName */
   else {
      if ( fTypeName ) {
         /** unscoped At Name */
         if ( 0 != ( mod & ( SCOPED | S ))) s += fTypeName->Name();
         else  s += Tools::GetBaseName(fTypeName->Name());
      } 
      else { 
         return ""; 
      }
   }

   /** if At is a pointer qualifiers have to be after At */
   if ( cv.length() && ( TypeType() == POINTER || TypeType() == FUNCTION) ) s += " " + cv;

   /** apply reference if qualifications wanted */
   if ( ( 0 != ( mod & ( QUALIFIED | Q ))) && IsReference()) s += "&";

   return s;
}


//-------------------------------------------------------------------------------
ROOT::Reflex::Scope ROOT::Reflex::Type::PointerToMemberScope() const {
//-------------------------------------------------------------------------------
   // Return the scope of the pointer to member type
   if ( * this ) return fTypeName->fTypeBase->PointerToMemberScope();
   return Dummy::Scope();
}


//-------------------------------------------------------------------------------
ROOT::Reflex::Scope ROOT::Reflex::Type::SubScopeAt( size_t nth ) const {
//-------------------------------------------------------------------------------
// Return the nth sub scope.
   if ( * this ) return fTypeName->fTypeBase->SubScopeAt( nth );
   return Dummy::Scope();
}


//-------------------------------------------------------------------------------
ROOT::Reflex::Type ROOT::Reflex::Type::SubTypeAt( size_t nth ) const {
//-------------------------------------------------------------------------------
// Return the nth sub type.
   if ( * this ) return fTypeName->fTypeBase->SubTypeAt( nth );
   return Dummy::Type();
}


//-------------------------------------------------------------------------------
ROOT::Reflex::Type ROOT::Reflex::Type::TypeAt( size_t nth ) {
//-------------------------------------------------------------------------------
// Return the nth type defined in Reflex.
   return TypeName::TypeAt( nth );
}


//-------------------------------------------------------------------------------
size_t ROOT::Reflex::Type::TypeSize() {
//-------------------------------------------------------------------------------
// Return the number of types defined in Reflex.
   return TypeName::TypeSize();
}


//-------------------------------------------------------------------------------
ROOT::Reflex::TypeTemplate ROOT::Reflex::Type::SubTypeTemplateAt( size_t nth ) const {
//-------------------------------------------------------------------------------
// Return the nth sub type template.
   if ( * this ) return fTypeName->fTypeBase->SubTypeTemplateAt( nth );
   return Dummy::TypeTemplate();
}


//------------------------------------------------------------------------------
void ROOT::Reflex::Type::GenerateDict( DictionaryGenerator & generator) const {
//------------------------------------------------------------------------------
// Generate Dictionary information about itself.
   if ( * this ) fTypeName->fTypeBase->GenerateDict( generator );
}

#ifdef REFLEX_CINT_MERGE
bool ROOT::Reflex::Type::operator&&(const Scope &right) const
{ return operator bool() && (bool)right; }
bool ROOT::Reflex::Type::operator&&(const Type &right) const 
{ return operator bool() && (bool)right; }
bool ROOT::Reflex::Type::operator&&(const Member &right) const 
{ return operator bool() && (bool)right; }
bool ROOT::Reflex::Type::operator||(const Scope &right) const 
{ return operator bool() && (bool)right; }
bool ROOT::Reflex::Type::operator||(const Type &right) const 
{ return operator bool() && (bool)right; }
bool ROOT::Reflex::Type::operator||(const Member &right) const 
{ return operator bool() || (bool)right; }
#endif
