// @(#)root/meta:$Name:  $:$Id: TFunction.cxx,v 1.12 2003/08/04 20:07:42 brun Exp $
// Author: Fons Rademakers   07/02/97

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// Global functions class (global functions are obtaine from CINT).     //
// This class describes one single global function.                     //
// The TROOT class contains a list of all currently defined global      //
// functions (accessible via TROOT::GetListOfGlobalFunctions()).        //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TFunction.h"
#include "TMethodArg.h"
#include "TROOT.h"
#include "TInterpreter.h"
#include "Strlen.h"
#include "Api.h"


ClassImp(TFunction)

//______________________________________________________________________________
TFunction::TFunction(G__MethodInfo *info) : TDictionary()
{
   // Default TFunction ctor. TFunctions are constructed in TROOT via
   // a call to TCint::UpdateListOfGlobalFunctions().

   fInfo       = info;
   fMethodArgs = 0;
   if (fInfo) {
      SetName(fInfo->Name());
      SetTitle(fInfo->Title());
      fMangledName = fInfo->GetMangledName();
   }
}

//______________________________________________________________________________
TFunction::TFunction(const TFunction &orig) : TDictionary(orig)
{
   // Copy operator.

   if (orig.fInfo) {
      fInfo = new G__MethodInfo(*orig.fInfo);
      fMangledName = fInfo->GetMangledName();
   } else
      fInfo = 0;
   fMethodArgs = 0;
}

//______________________________________________________________________________
TFunction& TFunction::operator=(const TFunction &rhs)
{
   // Assignment operator.

   if (this != &rhs) {
      delete fInfo;
      if (fMethodArgs) fMethodArgs->Delete();
      delete fMethodArgs;
      if (rhs.fInfo) {
         fInfo = new G__MethodInfo(*rhs.fInfo);
         SetName(fInfo->Name());
         SetTitle(fInfo->Title());
         fMangledName = fInfo->GetMangledName();
      } else
         fInfo = 0;
      fMethodArgs = 0;
   }
   return *this;
}

//______________________________________________________________________________
TFunction::~TFunction()
{
   // TFunction dtor deletes adopted G__MethodInfo.

   delete fInfo;

   if (fMethodArgs) fMethodArgs->Delete();
   delete fMethodArgs;
}

//______________________________________________________________________________
TObject *TFunction::Clone(const char *newname) const
{
   // Clone method.

   TNamed *newobj = new TFunction(*this);
   if (newname && strlen(newname)) newobj->SetName(newname);
   return newobj;
}

//______________________________________________________________________________
void TFunction::CreateSignature()
{
   // Using the CINT method arg information to create a complete signature string.

   G__MethodArgInfo arg(*fInfo);

   int ifirst = 0;
   fSignature = "(";
   while (arg.Next()) {
      if (ifirst) fSignature += ", ";
      if (arg.Type() == 0) break;
      //if (arg.Property() & G__BIT_ISCONSTANT)   // is returned as part of the name
      //   fSignature += "const ";
      fSignature += arg.Type()->Name();
      if (arg.Name() && strlen(arg.Name())) {
         fSignature += " ";
         fSignature += arg.Name();
      }
      if (arg.DefaultValue() && strlen(arg.DefaultValue())) {
         fSignature += " = ";
         const char *charstar = strstr(arg.Type()->TrueName(),"char*");
         if (charstar) fSignature += "\"";
         fSignature += arg.DefaultValue();
         if (charstar) fSignature += "\"";
      }
      ifirst++;
   }
   fSignature += ")";
}

//______________________________________________________________________________
const char *TFunction::GetSignature()
{
   // Return signature of function.

   if (fInfo && fSignature.IsNull())
      CreateSignature();

   return fSignature.Data();
}

//______________________________________________________________________________
TList *TFunction::GetListOfMethodArgs()
{
   // Return list containing the TMethodArgs of a TFunction.

   if (!fMethodArgs) {
      if (!gInterpreter)
         Fatal("GetListOfMethodArgs", "gInterpreter not initialized");

      gInterpreter->CreateListOfMethodArgs(this);
   }
   return fMethodArgs;
}

//______________________________________________________________________________
const char *TFunction::GetReturnTypeName() const
{
   // Get full type description of function return type, e,g.: "class TDirectory*".

   if (fInfo->Type() == 0) return "Unknown";
   return fInfo->Type()->Name();
}

//______________________________________________________________________________
Int_t TFunction::GetNargs() const
{
   // Number of function arguments.

   return fInfo->NArg();
}

//______________________________________________________________________________
Int_t TFunction::GetNargsOpt() const
{
   // Number of function optional (default) arguments.

   return fInfo->NDefaultArg();
}

//______________________________________________________________________________
Long_t TFunction::Property() const
{
   // Get property description word. For meaning of bits see EProperty.

   return fInfo->Property();
}

//______________________________________________________________________________
void *TFunction::InterfaceMethod() const
{
   // Return pointer to the interface method. Using this pointer we
   // can find which TFunction belongs to a G__MethodInfo object.
   // Both need to have the same InterfaceMethod pointer.

   G__InterfaceMethod pfunc = fInfo->InterfaceMethod();
   if (!pfunc) {
      struct G__bytecodefunc *bytecode = fInfo->GetBytecode();

      if(bytecode) pfunc = (G__InterfaceMethod)G__exec_bytecode;
      else {
        pfunc = (G__InterfaceMethod)NULL;
      }
   }
   return (void*)pfunc;
}

//______________________________________________________________________________
const char *TFunction::GetMangledName() const
{
   // Returns the mangled name as defined by CINT, or 0 in case of error.

   // This function is being used by TROOT to determine the full identity of 
   // of the function.  It has to work even if the function has been 
   // unloaded by cint (in which case fInfo is actually hold reference to 
   // memory that is (likely) not valid anymore.  So we cache the information.
   // Maybe we should also cache the rest of the informations .. but this might
   // be too much duplication of information.
   if (fInfo)
      return fMangledName; 
   else
      return 0;
}

//______________________________________________________________________________
const char *TFunction::GetPrototype() const
{
   // Returns the prototype of a function as defined by CINT, or 0 in
   // case of error.

   if (fInfo)
      return fInfo->GetPrototype();
   else
      return 0;
}
