// @(#)root/meta:$
// Author: Axel Naumann 2014-05-02

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

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// Persistent version of a TClass.                                      //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TProtoClass.h"

#include "TBaseClass.h"
#include "TClass.h"
#include "TDataMember.h"
#include "TList.h"
#include "TListOfDataMembers.h"
#include "TRealData.h"

//______________________________________________________________________________
TProtoClass::TProtoClass(TClass* cl):
   TNamed(*cl), fBase(cl->GetListOfBases()), fData(cl->GetListOfDataMembers()),
   fSizeof(cl->Size()), fCanSplit(cl->fCanSplit), fStreamerType(cl->fStreamerType),
   fProperty(cl->fProperty),fClassProperty(cl->fClassProperty)
{
   // Initialize a TProtoClass from a TClass.
   fPRealData = new TList();

   if (!cl->GetCollectionProxy()) {
      // Build the list of RealData before we access it:
      cl->BuildRealData(0, true /*isTransient*/);
      // The data members are ordered as follows:
      // - this class's data members,
      // - foreach base: base class's data members.
      // fPRealData encodes all TProtoRealData objects with a
      // TObjString to signal a new class.
      TClass* clCurrent = cl;
      TRealData* precRd = nullptr;
      for (auto realDataObj: *cl->GetListOfRealData()) {
         TRealData *rd = (TRealData*)realDataObj;
         if (!precRd) precRd = rd;
         TClass* clRD = rd->GetDataMember()->GetClass();
         if (clRD != clCurrent) {
            clCurrent = clRD;
            TObjString *clstr = new TObjString(clRD->GetName());
            if (precRd->TestBit(TRealData::kTransient)) {
               clstr->SetBit(TRealData::kTransient);
            }
            fPRealData->AddLast(clstr);
            precRd = rd;
         }
         fPRealData->AddLast(new TProtoRealData(rd));
      }

      if (gDebug > 2) {
         for (auto dataPtr : *fPRealData) {
            const auto classType = dataPtr->IsA();
            const auto dataPtrName = dataPtr->GetName();
            if (classType == TProtoRealData::Class())
               Info("TProtoClass","Data is a protorealdata: %s", dataPtrName);
            if (classType == TObjString::Class())
               Info("TProtoClass","Data is a objectstring: %s", dataPtrName);
            if (dataPtr->TestBit(TRealData::kTransient))
               Info("TProtoClass","And is transient");
         }
      }
   }

   cl->CalculateStreamerOffset();
   fOffsetStreamer = cl->fOffsetStreamer;
}

//______________________________________________________________________________
TProtoClass::~TProtoClass()
{
   // Destructor.
   Delete();
}

//______________________________________________________________________________
void TProtoClass::Delete(Option_t* opt /*= ""*/) {
   // Delete the containers that are usually owned by their TClass.
   if (fPRealData) fPRealData->Delete(opt);
   delete fPRealData; fPRealData = 0;
   if (fBase) fBase->Delete(opt);
   delete fBase; fBase = 0;
   if (fData) fData->Delete(opt);
   delete fData; fData = 0;
}

//______________________________________________________________________________
Bool_t TProtoClass::FillTClass(TClass* cl) {
   // Move data from this TProtoClass into cl.
   if (cl->fRealData || cl->fBase || cl->fData || cl->fSizeof != -1 || cl->fCanSplit >= 0
       || cl->fProperty != (-1) ) {
      Error("FillTClass", "TClass %s already initialized!", cl->GetName());
      return kFALSE;
   }
   if (gDebug > 1) Info("FillTClass","Loading TProtoClass for %s - %s",cl->GetName(),GetName());

   // Copy only the TClass bits.
   // not bit 13 and below and not bit 24 and above, just Bits 14 - 23
   UInt_t newbits = TestBits(0x00ffc000);
   cl->ResetBit(0x00ffc000);
   cl->SetBit(newbits);

   cl->fName  = this->fName;
   cl->fTitle = this->fTitle;
   cl->fBase = fBase;
   cl->fData = (TListOfDataMembers*)fData;
   cl->fRealData = new TList(); // FIXME: this should really become a THashList!

   cl->fSizeof = fSizeof;
   cl->fCanSplit = fCanSplit;
   cl->fProperty = fProperty;
   cl->fClassProperty = fClassProperty;
   cl->fStreamerType = fStreamerType;

   // Update pointers to TClass
   if (cl->fBase) {
      for (auto base: *cl->fBase) {
         ((TBaseClass*)base)->SetClass(cl);
      }
   }
   if (cl->fData) {
      for (auto dm: *cl->fData) {
         ((TDataMember*)dm)->SetClass(cl);
      }
      ((TListOfDataMembers*)cl->fData)->SetClass(cl);
   }

   TClass* currentRDClass = cl;
   if (fPRealData) {
      for (TObject* element: *fPRealData) {
         if (element->IsA() == TObjString::Class()) {
            currentRDClass = TClass::GetClass(element->GetName());
            if (!currentRDClass && !element->TestBit(TRealData::kTransient)) {
               Error("TProtoClass::FillTClass()", "Cannot find TClass for %s; skipping its members.",
                     element->GetName());
            }
         } else {
            if (!currentRDClass) continue;
            TProtoRealData* prd = (TProtoRealData*)element;
            if (TRealData* rd = prd->CreateRealData(currentRDClass)) {
               cl->fRealData->AddLast(rd);
            }
         }
      }
   }

   cl->SetStreamerImpl();

   fBase = 0;
   fData = 0;
   if (fPRealData) fPRealData->Delete();
   delete fPRealData;
   fPRealData = 0;

   return kTRUE;
}

//______________________________________________________________________________
TProtoClass::TProtoRealData::TProtoRealData(const TRealData* rd):
   TNamed(rd->GetDataMember()->GetName(), rd->GetName()),
   fOffset(rd->GetThisOffset())
{
   // Initialize this from a TRealData object.
   SetBit(kIsObject, rd->IsObject());
   SetBit(TRealData::kTransient, rd->TestBit(TRealData::kTransient));
}

//______________________________________________________________________________
TProtoClass::TProtoRealData::~TProtoRealData()
{
   // Destructor to pin vtable.
}

//______________________________________________________________________________
TRealData* TProtoClass::TProtoRealData::CreateRealData(TClass* dmClass) const
{
   // Create a TRealData from this, with its data member coming from dmClass.
   TDataMember* dm = (TDataMember*)dmClass->GetListOfDataMembers()->FindObject(GetName());
   if (!dm) {
      Error("TProtoClass::TProtoRealData::CreateRealData()",
            "Cannot find data member %s::%s!", dmClass->GetName(), GetName());
      return 0;
   }
   TRealData* rd = new TRealData(GetTitle(), fOffset, dm);
   rd->SetIsObject(TestBit(kIsObject));
   return rd;
}
 TProtoClass.cxx:1
 TProtoClass.cxx:2
 TProtoClass.cxx:3
 TProtoClass.cxx:4
 TProtoClass.cxx:5
 TProtoClass.cxx:6
 TProtoClass.cxx:7
 TProtoClass.cxx:8
 TProtoClass.cxx:9
 TProtoClass.cxx:10
 TProtoClass.cxx:11
 TProtoClass.cxx:12
 TProtoClass.cxx:13
 TProtoClass.cxx:14
 TProtoClass.cxx:15
 TProtoClass.cxx:16
 TProtoClass.cxx:17
 TProtoClass.cxx:18
 TProtoClass.cxx:19
 TProtoClass.cxx:20
 TProtoClass.cxx:21
 TProtoClass.cxx:22
 TProtoClass.cxx:23
 TProtoClass.cxx:24
 TProtoClass.cxx:25
 TProtoClass.cxx:26
 TProtoClass.cxx:27
 TProtoClass.cxx:28
 TProtoClass.cxx:29
 TProtoClass.cxx:30
 TProtoClass.cxx:31
 TProtoClass.cxx:32
 TProtoClass.cxx:33
 TProtoClass.cxx:34
 TProtoClass.cxx:35
 TProtoClass.cxx:36
 TProtoClass.cxx:37
 TProtoClass.cxx:38
 TProtoClass.cxx:39
 TProtoClass.cxx:40
 TProtoClass.cxx:41
 TProtoClass.cxx:42
 TProtoClass.cxx:43
 TProtoClass.cxx:44
 TProtoClass.cxx:45
 TProtoClass.cxx:46
 TProtoClass.cxx:47
 TProtoClass.cxx:48
 TProtoClass.cxx:49
 TProtoClass.cxx:50
 TProtoClass.cxx:51
 TProtoClass.cxx:52
 TProtoClass.cxx:53
 TProtoClass.cxx:54
 TProtoClass.cxx:55
 TProtoClass.cxx:56
 TProtoClass.cxx:57
 TProtoClass.cxx:58
 TProtoClass.cxx:59
 TProtoClass.cxx:60
 TProtoClass.cxx:61
 TProtoClass.cxx:62
 TProtoClass.cxx:63
 TProtoClass.cxx:64
 TProtoClass.cxx:65
 TProtoClass.cxx:66
 TProtoClass.cxx:67
 TProtoClass.cxx:68
 TProtoClass.cxx:69
 TProtoClass.cxx:70
 TProtoClass.cxx:71
 TProtoClass.cxx:72
 TProtoClass.cxx:73
 TProtoClass.cxx:74
 TProtoClass.cxx:75
 TProtoClass.cxx:76
 TProtoClass.cxx:77
 TProtoClass.cxx:78
 TProtoClass.cxx:79
 TProtoClass.cxx:80
 TProtoClass.cxx:81
 TProtoClass.cxx:82
 TProtoClass.cxx:83
 TProtoClass.cxx:84
 TProtoClass.cxx:85
 TProtoClass.cxx:86
 TProtoClass.cxx:87
 TProtoClass.cxx:88
 TProtoClass.cxx:89
 TProtoClass.cxx:90
 TProtoClass.cxx:91
 TProtoClass.cxx:92
 TProtoClass.cxx:93
 TProtoClass.cxx:94
 TProtoClass.cxx:95
 TProtoClass.cxx:96
 TProtoClass.cxx:97
 TProtoClass.cxx:98
 TProtoClass.cxx:99
 TProtoClass.cxx:100
 TProtoClass.cxx:101
 TProtoClass.cxx:102
 TProtoClass.cxx:103
 TProtoClass.cxx:104
 TProtoClass.cxx:105
 TProtoClass.cxx:106
 TProtoClass.cxx:107
 TProtoClass.cxx:108
 TProtoClass.cxx:109
 TProtoClass.cxx:110
 TProtoClass.cxx:111
 TProtoClass.cxx:112
 TProtoClass.cxx:113
 TProtoClass.cxx:114
 TProtoClass.cxx:115
 TProtoClass.cxx:116
 TProtoClass.cxx:117
 TProtoClass.cxx:118
 TProtoClass.cxx:119
 TProtoClass.cxx:120
 TProtoClass.cxx:121
 TProtoClass.cxx:122
 TProtoClass.cxx:123
 TProtoClass.cxx:124
 TProtoClass.cxx:125
 TProtoClass.cxx:126
 TProtoClass.cxx:127
 TProtoClass.cxx:128
 TProtoClass.cxx:129
 TProtoClass.cxx:130
 TProtoClass.cxx:131
 TProtoClass.cxx:132
 TProtoClass.cxx:133
 TProtoClass.cxx:134
 TProtoClass.cxx:135
 TProtoClass.cxx:136
 TProtoClass.cxx:137
 TProtoClass.cxx:138
 TProtoClass.cxx:139
 TProtoClass.cxx:140
 TProtoClass.cxx:141
 TProtoClass.cxx:142
 TProtoClass.cxx:143
 TProtoClass.cxx:144
 TProtoClass.cxx:145
 TProtoClass.cxx:146
 TProtoClass.cxx:147
 TProtoClass.cxx:148
 TProtoClass.cxx:149
 TProtoClass.cxx:150
 TProtoClass.cxx:151
 TProtoClass.cxx:152
 TProtoClass.cxx:153
 TProtoClass.cxx:154
 TProtoClass.cxx:155
 TProtoClass.cxx:156
 TProtoClass.cxx:157
 TProtoClass.cxx:158
 TProtoClass.cxx:159
 TProtoClass.cxx:160
 TProtoClass.cxx:161
 TProtoClass.cxx:162
 TProtoClass.cxx:163
 TProtoClass.cxx:164
 TProtoClass.cxx:165
 TProtoClass.cxx:166
 TProtoClass.cxx:167
 TProtoClass.cxx:168
 TProtoClass.cxx:169
 TProtoClass.cxx:170
 TProtoClass.cxx:171
 TProtoClass.cxx:172
 TProtoClass.cxx:173
 TProtoClass.cxx:174
 TProtoClass.cxx:175
 TProtoClass.cxx:176
 TProtoClass.cxx:177
 TProtoClass.cxx:178
 TProtoClass.cxx:179
 TProtoClass.cxx:180
 TProtoClass.cxx:181
 TProtoClass.cxx:182
 TProtoClass.cxx:183
 TProtoClass.cxx:184
 TProtoClass.cxx:185
 TProtoClass.cxx:186
 TProtoClass.cxx:187
 TProtoClass.cxx:188
 TProtoClass.cxx:189
 TProtoClass.cxx:190
 TProtoClass.cxx:191
 TProtoClass.cxx:192
 TProtoClass.cxx:193
 TProtoClass.cxx:194
 TProtoClass.cxx:195
 TProtoClass.cxx:196
 TProtoClass.cxx:197
 TProtoClass.cxx:198