// @(#)root/meta:$Id$
// Author: Rene Brun   09/02/95

/*************************************************************************
 * 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.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
//  Each ROOT class (see TClass) has a linked list of methods.          //
//  This class describes one single method (member function).           //
//  The method info is obtained via the CINT api. See class TCling.      //
//                                                                      //
//  The method information is used a.o. by the THml class and by the    //
//  TTree class.                                                        //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TClass.h"
#include "TMethod.h"
#include "TMethodArg.h"
#include "TMethodCall.h"
#include "TROOT.h"
#include "TApplication.h"
#include "TInterpreter.h"
#include "Strlen.h"
#include "TDataMember.h"


ClassImp(TMethod)

//______________________________________________________________________________
TMethod::TMethod(MethodInfo_t *info, TClass *cl) : TFunction(info)
{
   // Default TMethod ctor. TMethods are constructed in TClass.
   // Comment strings are pre-parsed to find out whether the method is
   // a context-menu item.

   fClass        = cl;
   fGetterMethod = 0;
   fSetterMethod = 0;
   fMenuItem     = kMenuNoMenu;

   if (fInfo) {
      SetMenuItem(gCling->MethodInfo_Title(fInfo));
   }
}

//______________________________________________________________________________
TMethod::TMethod(const TMethod& orig) : TFunction(orig)
{
   // Copy ctor.

   fClass        = orig.fClass;
   fMenuItem     = orig.fMenuItem;
   fGetter       = orig.fGetter;
   fGetterMethod = 0;
   fSetterMethod = 0;
}

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

   if (this != &rhs) {
      TFunction::operator=(rhs);
      fClass        = rhs.fClass;
      fMenuItem     = rhs.fMenuItem;
      fGetter       = rhs.fGetter;
      if (fGetterMethod)
         delete fGetterMethod;
      fGetterMethod = 0;
      if (fSetterMethod)
         delete fSetterMethod;
      fSetterMethod = 0;
   }
   return *this;
}

//______________________________________________________________________________
TMethod::~TMethod()
{
   // Cleanup.

   delete fGetterMethod;
   delete fSetterMethod;
}

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

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

//______________________________________________________________________________
const char *TMethod::GetCommentString()
{
   // Returns a comment string from the class declaration.

   return fInfo ? gCling->MethodInfo_Title(fInfo) : "";
}


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

   TFunction::CreateSignature();

   if (Property() & kIsConstMethod) fSignature += " const";
}

//______________________________________________________________________________
TDataMember *TMethod::FindDataMember()
{
   // Tries to guess DataMember from comment string
   // and Method's name <==(only if 1 Argument!).
   // If more then one argument=> returns pointer to the last argument.
   // It also sets MethodArgs' pointers to point to specified data members.
   //
   // The form of comment string defining arguments is:
   // void XXX(Int_t x1, Float_t y2) //*ARGS={x1=>fX1,y2=>fY2}
   // where fX1, fY2 are data fields in the same class.
   // ("pointers" to data members)

   Char_t *argstring = (char*)strstr(GetCommentString(),"*ARGS={");

   // the following statement has been commented (Rene). Not needed
   // it was making troubles in BuildRealData for classes with protected
   // default constructors.
   // if (!(GetClass()->GetListOfRealData())) GetClass()->BuildRealData();

   if (argstring) {

      // if we found any argument-specifying hints  - parse it

      if (!fMethodArgs) return 0;

      Int_t nchs = strlen(argstring);    // workspace...
      char *argstr = new char[nchs+1];   // workspace...
      char *ptr1 = 0;
      char *tok  = 0;
      char *ptr2 = 0;
      Int_t i;

      strlcpy(argstr,argstring,nchs+1);       //let's move it to "worksapce"  copy
      ptr2 = strtok(argstr,"{}");     //extract the data!
      if (ptr2 == 0) {
         Fatal("FindDataMember","Internal error found '*ARGS=\"' but not \"{}\" in %s",GetCommentString());
         delete [] argstr;
         return 0;
      }
      ptr2 = strtok((char*)0,"{}");

      //extract argument tokens//
      char *tokens[20];
      Int_t cnt       = 0;
      Int_t token_cnt = 0;
      do {
         ptr1 = strtok((char*) (cnt++ ? 0:ptr2),",;"); //extract tokens
                                                        // separated by , or ;
         if (ptr1) {
            Int_t nch = strlen(ptr1);
            tok = new char[nch+1];
            strlcpy(tok,ptr1,nch+1);
            tokens[token_cnt] = tok;            //store this token.
            token_cnt++;
         }
      } while (ptr1);

      //now let's  parse all argument tokens...
      TClass     *cl = 0;
      TMethodArg *a  = 0;
      TMethodArg *ar = 0;
      TDataMember *member = 0;

      for (i=0; i<token_cnt;i++) {
         cnt = 0;
         ptr1 = strtok(tokens[i],"=>");  //LeftHandedSide=methodarg
         ptr2 = strtok((char*)0,"=>"); //RightHandedSide-points to datamember

         //find the MethodArg
         a      = 0;
         ar     = 0;
         member = 0;
         TIter nextarg(fMethodArgs);     // iterate through all arguments.
         while ((ar = (TMethodArg*)nextarg())) {
            if (!strcmp(ptr1,ar->GetName())) {
               a = ar;
               break;
            }
         }

         //now find the data member
         cl = GetClass()->GetBaseDataMember(ptr2);
         if (cl) {
            member = cl->GetDataMember(ptr2);
            if (a) a->fDataMember = member; //SET THE APROPRIATE FIELD !!!
                                     //We can do it - friend decl. in MethodArg
         }
         delete [] tokens[i];
      }
      delete [] argstr;
      return member; // nothing else to do! We return a pointer to the last
                     // found data member

   // if not found in comment string - try to guess it from name!
   } else {
      if (fMethodArgs)
         if (fMethodArgs->GetSize() != 1) return 0;
      
      TMethodArg *a = 0;
      if (fMethodArgs) a = (TMethodArg*)(fMethodArgs->First());

      char dataname[64]    = "";
      char basename[64]    = "";
      const char *funcname = GetName();
      if ( strncmp(funcname,"Get",3) == 0 || strncmp(funcname,"Set",3) == 0 )
         snprintf(basename,64,"%s",funcname+3);
      else if ( strncmp(funcname,"Is",2) == 0 )
         snprintf(basename,64,"%s",funcname+2);
      else if (strncmp(funcname, "Has", 3) == 0)
         snprintf(basename,64,"%s", funcname+3);
      else
         return 0;

      snprintf(dataname,64,"f%s",basename);

      TClass *cl = GetClass()->GetBaseDataMember(dataname);
      if (cl) {
         TDataMember *member   = cl->GetDataMember(dataname);
         if (a) a->fDataMember = member;
         return member;
      } else {
         snprintf(dataname,64,"fIs%s",basename);  //in case of IsEditable()
                                                        //and fIsEditable
         cl = GetClass()->GetBaseDataMember(dataname);
         if (cl) {
            TDataMember *member = cl->GetDataMember(dataname);
            if (a) a->fDataMember = member;
            return member;
         }
      }
   }

   //if nothing found - return null -pointer:
   return 0;
}

//______________________________________________________________________________
TMethodCall *TMethod::GetterMethod()
{
   // Return call environment for the getter method in case this is a
   // *TOGGLE method (for the context menu).

   if (!fGetterMethod && fMenuItem == kMenuToggle && fGetter != "" && fClass) {
      fGetterMethod = new TMethodCall(fClass, Getter(), "");
   }
   return fGetterMethod;
}

//______________________________________________________________________________
Bool_t TMethod::IsValid()
{
   // Return true if this function object is pointing to a currently
   // loaded function.  If a function is unloaded after the TMethod
   // is created, the TMethod will be set to be invalid.

   // Register the transaction when checking the validity of the object.
   if (!fInfo && UpdateInterpreterStateMarker()) {
      DeclId_t newId = gInterpreter->GetFunction(fClass->GetClassInfo(), fName);
      if (newId) {
         MethodInfo_t *info = gInterpreter->MethodInfo_Factory(newId);
         Update(info);
      }
      return newId != 0;
   }
   return fInfo != 0;
}

//______________________________________________________________________________
TMethodCall *TMethod::SetterMethod()
{
   // Return call environment for this method in case this is a
   // *TOGGLE method which takes a single boolean or integer argument.

   if (!fSetterMethod && fMenuItem == kMenuToggle && fClass) {
      fSetterMethod = new TMethodCall(fClass, GetName(), "1");
   }
   return fSetterMethod;
}

//______________________________________________________________________________
TList *TMethod::GetListOfMethodArgs()
{
   // Returns methodarg list and additionally updates fDataMember in TMethod by
   // calling FindDataMember();

   if (!fMethodArgs){
      TFunction::GetListOfMethodArgs();
      FindDataMember();
   }
   return fMethodArgs;
}

//______________________________________________________________________________
void TMethod::SetMenuItem(const char *docstring)
{
   // Set the menu item as prescribed in the doctstring.

   if (docstring && strstr(docstring, "*TOGGLE")) {
      fMenuItem = kMenuToggle;
      const char *s;
      if ((s = strstr(docstring, "*GETTER="))) {
         fGetter = s+8;
         fGetter = fGetter.Strip(TString::kBoth);
      }
   } else
      if (docstring && strstr(docstring, "*MENU"))
         fMenuItem = kMenuDialog;
      else
         if (docstring && strstr(docstring, "*SUBMENU"))
            fMenuItem = kMenuSubMenu;
         else
            fMenuItem = kMenuNoMenu;
}

//______________________________________________________________________________
Bool_t TMethod::Update(MethodInfo_t *info)
{
   // Update the TMethod to reflect the new info.
   //
   // This can be used to implement unloading (info == 0) and then reloading
   // (info being the 'new' decl address).

   if (TFunction::Update(info)) {
      delete fGetterMethod; fGetterMethod = 0;
      delete fSetterMethod; fSetterMethod = 0;
      if (fInfo) {
         SetMenuItem(gCling->MethodInfo_Title(fInfo));
      }  
      return kTRUE;
   } else {
      return kFALSE;
   }
}
 TMethod.cxx:1
 TMethod.cxx:2
 TMethod.cxx:3
 TMethod.cxx:4
 TMethod.cxx:5
 TMethod.cxx:6
 TMethod.cxx:7
 TMethod.cxx:8
 TMethod.cxx:9
 TMethod.cxx:10
 TMethod.cxx:11
 TMethod.cxx:12
 TMethod.cxx:13
 TMethod.cxx:14
 TMethod.cxx:15
 TMethod.cxx:16
 TMethod.cxx:17
 TMethod.cxx:18
 TMethod.cxx:19
 TMethod.cxx:20
 TMethod.cxx:21
 TMethod.cxx:22
 TMethod.cxx:23
 TMethod.cxx:24
 TMethod.cxx:25
 TMethod.cxx:26
 TMethod.cxx:27
 TMethod.cxx:28
 TMethod.cxx:29
 TMethod.cxx:30
 TMethod.cxx:31
 TMethod.cxx:32
 TMethod.cxx:33
 TMethod.cxx:34
 TMethod.cxx:35
 TMethod.cxx:36
 TMethod.cxx:37
 TMethod.cxx:38
 TMethod.cxx:39
 TMethod.cxx:40
 TMethod.cxx:41
 TMethod.cxx:42
 TMethod.cxx:43
 TMethod.cxx:44
 TMethod.cxx:45
 TMethod.cxx:46
 TMethod.cxx:47
 TMethod.cxx:48
 TMethod.cxx:49
 TMethod.cxx:50
 TMethod.cxx:51
 TMethod.cxx:52
 TMethod.cxx:53
 TMethod.cxx:54
 TMethod.cxx:55
 TMethod.cxx:56
 TMethod.cxx:57
 TMethod.cxx:58
 TMethod.cxx:59
 TMethod.cxx:60
 TMethod.cxx:61
 TMethod.cxx:62
 TMethod.cxx:63
 TMethod.cxx:64
 TMethod.cxx:65
 TMethod.cxx:66
 TMethod.cxx:67
 TMethod.cxx:68
 TMethod.cxx:69
 TMethod.cxx:70
 TMethod.cxx:71
 TMethod.cxx:72
 TMethod.cxx:73
 TMethod.cxx:74
 TMethod.cxx:75
 TMethod.cxx:76
 TMethod.cxx:77
 TMethod.cxx:78
 TMethod.cxx:79
 TMethod.cxx:80
 TMethod.cxx:81
 TMethod.cxx:82
 TMethod.cxx:83
 TMethod.cxx:84
 TMethod.cxx:85
 TMethod.cxx:86
 TMethod.cxx:87
 TMethod.cxx:88
 TMethod.cxx:89
 TMethod.cxx:90
 TMethod.cxx:91
 TMethod.cxx:92
 TMethod.cxx:93
 TMethod.cxx:94
 TMethod.cxx:95
 TMethod.cxx:96
 TMethod.cxx:97
 TMethod.cxx:98
 TMethod.cxx:99
 TMethod.cxx:100
 TMethod.cxx:101
 TMethod.cxx:102
 TMethod.cxx:103
 TMethod.cxx:104
 TMethod.cxx:105
 TMethod.cxx:106
 TMethod.cxx:107
 TMethod.cxx:108
 TMethod.cxx:109
 TMethod.cxx:110
 TMethod.cxx:111
 TMethod.cxx:112
 TMethod.cxx:113
 TMethod.cxx:114
 TMethod.cxx:115
 TMethod.cxx:116
 TMethod.cxx:117
 TMethod.cxx:118
 TMethod.cxx:119
 TMethod.cxx:120
 TMethod.cxx:121
 TMethod.cxx:122
 TMethod.cxx:123
 TMethod.cxx:124
 TMethod.cxx:125
 TMethod.cxx:126
 TMethod.cxx:127
 TMethod.cxx:128
 TMethod.cxx:129
 TMethod.cxx:130
 TMethod.cxx:131
 TMethod.cxx:132
 TMethod.cxx:133
 TMethod.cxx:134
 TMethod.cxx:135
 TMethod.cxx:136
 TMethod.cxx:137
 TMethod.cxx:138
 TMethod.cxx:139
 TMethod.cxx:140
 TMethod.cxx:141
 TMethod.cxx:142
 TMethod.cxx:143
 TMethod.cxx:144
 TMethod.cxx:145
 TMethod.cxx:146
 TMethod.cxx:147
 TMethod.cxx:148
 TMethod.cxx:149
 TMethod.cxx:150
 TMethod.cxx:151
 TMethod.cxx:152
 TMethod.cxx:153
 TMethod.cxx:154
 TMethod.cxx:155
 TMethod.cxx:156
 TMethod.cxx:157
 TMethod.cxx:158
 TMethod.cxx:159
 TMethod.cxx:160
 TMethod.cxx:161
 TMethod.cxx:162
 TMethod.cxx:163
 TMethod.cxx:164
 TMethod.cxx:165
 TMethod.cxx:166
 TMethod.cxx:167
 TMethod.cxx:168
 TMethod.cxx:169
 TMethod.cxx:170
 TMethod.cxx:171
 TMethod.cxx:172
 TMethod.cxx:173
 TMethod.cxx:174
 TMethod.cxx:175
 TMethod.cxx:176
 TMethod.cxx:177
 TMethod.cxx:178
 TMethod.cxx:179
 TMethod.cxx:180
 TMethod.cxx:181
 TMethod.cxx:182
 TMethod.cxx:183
 TMethod.cxx:184
 TMethod.cxx:185
 TMethod.cxx:186
 TMethod.cxx:187
 TMethod.cxx:188
 TMethod.cxx:189
 TMethod.cxx:190
 TMethod.cxx:191
 TMethod.cxx:192
 TMethod.cxx:193
 TMethod.cxx:194
 TMethod.cxx:195
 TMethod.cxx:196
 TMethod.cxx:197
 TMethod.cxx:198
 TMethod.cxx:199
 TMethod.cxx:200
 TMethod.cxx:201
 TMethod.cxx:202
 TMethod.cxx:203
 TMethod.cxx:204
 TMethod.cxx:205
 TMethod.cxx:206
 TMethod.cxx:207
 TMethod.cxx:208
 TMethod.cxx:209
 TMethod.cxx:210
 TMethod.cxx:211
 TMethod.cxx:212
 TMethod.cxx:213
 TMethod.cxx:214
 TMethod.cxx:215
 TMethod.cxx:216
 TMethod.cxx:217
 TMethod.cxx:218
 TMethod.cxx:219
 TMethod.cxx:220
 TMethod.cxx:221
 TMethod.cxx:222
 TMethod.cxx:223
 TMethod.cxx:224
 TMethod.cxx:225
 TMethod.cxx:226
 TMethod.cxx:227
 TMethod.cxx:228
 TMethod.cxx:229
 TMethod.cxx:230
 TMethod.cxx:231
 TMethod.cxx:232
 TMethod.cxx:233
 TMethod.cxx:234
 TMethod.cxx:235
 TMethod.cxx:236
 TMethod.cxx:237
 TMethod.cxx:238
 TMethod.cxx:239
 TMethod.cxx:240
 TMethod.cxx:241
 TMethod.cxx:242
 TMethod.cxx:243
 TMethod.cxx:244
 TMethod.cxx:245
 TMethod.cxx:246
 TMethod.cxx:247
 TMethod.cxx:248
 TMethod.cxx:249
 TMethod.cxx:250
 TMethod.cxx:251
 TMethod.cxx:252
 TMethod.cxx:253
 TMethod.cxx:254
 TMethod.cxx:255
 TMethod.cxx:256
 TMethod.cxx:257
 TMethod.cxx:258
 TMethod.cxx:259
 TMethod.cxx:260
 TMethod.cxx:261
 TMethod.cxx:262
 TMethod.cxx:263
 TMethod.cxx:264
 TMethod.cxx:265
 TMethod.cxx:266
 TMethod.cxx:267
 TMethod.cxx:268
 TMethod.cxx:269
 TMethod.cxx:270
 TMethod.cxx:271
 TMethod.cxx:272
 TMethod.cxx:273
 TMethod.cxx:274
 TMethod.cxx:275
 TMethod.cxx:276
 TMethod.cxx:277
 TMethod.cxx:278
 TMethod.cxx:279
 TMethod.cxx:280
 TMethod.cxx:281
 TMethod.cxx:282
 TMethod.cxx:283
 TMethod.cxx:284
 TMethod.cxx:285
 TMethod.cxx:286
 TMethod.cxx:287
 TMethod.cxx:288
 TMethod.cxx:289
 TMethod.cxx:290
 TMethod.cxx:291
 TMethod.cxx:292
 TMethod.cxx:293
 TMethod.cxx:294
 TMethod.cxx:295
 TMethod.cxx:296
 TMethod.cxx:297
 TMethod.cxx:298
 TMethod.cxx:299
 TMethod.cxx:300
 TMethod.cxx:301
 TMethod.cxx:302
 TMethod.cxx:303
 TMethod.cxx:304
 TMethod.cxx:305
 TMethod.cxx:306
 TMethod.cxx:307
 TMethod.cxx:308
 TMethod.cxx:309
 TMethod.cxx:310
 TMethod.cxx:311
 TMethod.cxx:312
 TMethod.cxx:313
 TMethod.cxx:314
 TMethod.cxx:315
 TMethod.cxx:316
 TMethod.cxx:317
 TMethod.cxx:318
 TMethod.cxx:319
 TMethod.cxx:320
 TMethod.cxx:321
 TMethod.cxx:322
 TMethod.cxx:323
 TMethod.cxx:324
 TMethod.cxx:325
 TMethod.cxx:326
 TMethod.cxx:327
 TMethod.cxx:328
 TMethod.cxx:329
 TMethod.cxx:330
 TMethod.cxx:331
 TMethod.cxx:332
 TMethod.cxx:333
 TMethod.cxx:334
 TMethod.cxx:335
 TMethod.cxx:336
 TMethod.cxx:337
 TMethod.cxx:338
 TMethod.cxx:339
 TMethod.cxx:340
 TMethod.cxx:341
 TMethod.cxx:342
 TMethod.cxx:343
 TMethod.cxx:344
 TMethod.cxx:345
 TMethod.cxx:346
 TMethod.cxx:347
 TMethod.cxx:348
 TMethod.cxx:349
 TMethod.cxx:350
 TMethod.cxx:351
 TMethod.cxx:352
 TMethod.cxx:353
 TMethod.cxx:354
 TMethod.cxx:355
 TMethod.cxx:356