// @(#)root/tree:$Id$
// Author: Axel Naumann, 2010-08-02

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

#ifndef ROOT_TTreeReaderValue
#define ROOT_TTreeReaderValue


////////////////////////////////////////////////////////////////////////////
//                                                                        //
// TTreeReaderValue                                                    //
//                                                                        //
// A simple interface for reading data from trees or chains.              //
//                                                                        //
//                                                                        //
////////////////////////////////////////////////////////////////////////////

#ifndef ROOT_TString
#include "TString.h"
#endif
#ifndef ROOT_TDictionary
#include "TDictionary.h"
#endif
#ifndef ROOT_TBranchProxy
#include "TBranchProxy.h"
#endif

#include <type_traits>

class TBranch;
class TBranchElement;
class TLeaf;
class TTreeReader;

namespace ROOT {
namespace Internal {

   class TTreeReaderValueBase {
   public:

      // Status flags, 0 is good
      enum ESetupStatus {
         kSetupNotSetup = -7, /// No initialization has happened yet.
         kSetupTreeDestructed = -8, /// The TTreeReader has been destructed / not set.
         kSetupMakeClassModeMismatch = -7, // readers disagree on whether TTree::SetMakeBranch() should be on
         kSetupMissingCounterBranch = -6, /// The array cannot find its counter branch: Array[CounterBranch]
         kSetupMissingBranch = -5, /// The specified branch cannot be found.
         kSetupInternalError = -4, /// Some other error - hopefully the error message helps.
         kSetupMissingDictionary = -3, /// To read this branch, we need a dictionary.
         kSetupMismatch = -2, /// Mismatch of branch type and reader template type.
         kSetupNotACollection = -1, /// The branch class type is not a collection.
         kSetupMatch = 0, /// This branch has been set up, branch data type and reader template type match, reading should succeed.
         kSetupMatchBranch = 0, /// This branch has been set up, branch data type and reader template type match, reading should succeed.
         //kSetupMatchConversion = 1, /// This branch has been set up, the branch data type can be converted to the reader template type, reading should succeed.
         //kSetupMatchConversionCollection = 2, /// This branch has been set up, the data type of the branch's collection elements can be converted to the reader template type, reading should succeed.
         //kSetupMakeClass = 3, /// This branch has been set up, enabling MakeClass mode for it, reading should succeed.
         // kSetupVoidPtr = 4,
         kSetupNoCheck = 5,
         kSetupMatchLeaf = 6 /// This branch (or TLeaf, really) has been set up, reading should succeed.
      };
      enum EReadStatus {
         kReadSuccess = 0, // data read okay
         kReadNothingYet, // data now yet accessed
         kReadError // problem reading data
      };

      EReadStatus ProxyRead();

      Bool_t IsValid() const { return fProxy && 0 == (int)fSetupStatus && 0 == (int)fReadStatus; }
      ESetupStatus GetSetupStatus() const { return fSetupStatus; }
      virtual EReadStatus GetReadStatus() const { return fReadStatus; }

      /// If we are reading a leaf, return the corresponding TLeaf.
      TLeaf* GetLeaf() { return fLeaf; }

      void* GetAddress();

      const char* GetBranchName() const { return fBranchName; }

      virtual ~TTreeReaderValueBase();

   protected:
      TTreeReaderValueBase(TTreeReader* reader = 0, const char* branchname = 0, TDictionary* dict = 0);
      TTreeReaderValueBase(const TTreeReaderValueBase&);
      TTreeReaderValueBase& operator=(const TTreeReaderValueBase&);

      void RegisterWithTreeReader();
      void NotifyNewTree(TTree* newTree);

      virtual void CreateProxy();
      const char* GetBranchDataType(TBranch* branch,
                                    TDictionary* &dict) const;

      virtual const char* GetDerivedTypeName() const = 0;

      Detail::TBranchProxy* GetProxy() const { return fProxy; }

      void MarkTreeReaderUnavailable() { fTreeReader = 0; fSetupStatus = kSetupTreeDestructed; }

      /// Stringify the template argument.
      static std::string GetElementTypeName(const std::type_info& ti);

      TString      fBranchName; // name of the branch to read data from.
      TString      fLeafName;
      TTreeReader* fTreeReader; // tree reader we belong to
      TDictionary* fDict; // type that the branch should contain
      Detail::TBranchProxy* fProxy; // proxy for this branch, owned by TTreeReader
      TLeaf*       fLeaf;
      ESetupStatus fSetupStatus; // setup status of this data access
      EReadStatus  fReadStatus; // read status of this data access
      std::vector<Long64_t> fStaticClassOffsets;

      // FIXME: re-introduce once we have ClassDefInline!
      //ClassDef(TTreeReaderValueBase, 0);//Base class for accessors to data via TTreeReader

      friend class ::TTreeReader;
   };

} // namespace Internal
} // namespace ROOT


template <typename T>
class TTreeReaderValue: public ROOT::Internal::TTreeReaderValueBase {
public:
   using NonConstT_t = typename std::remove_const<T>::type;
   TTreeReaderValue() {}
   TTreeReaderValue(TTreeReader& tr, const char* branchname):
      TTreeReaderValueBase(&tr, branchname,
                           TDictionary::GetDictionary(typeid(NonConstT_t))) {}

   T* Get() {
      if (!fProxy){
         Error("Get()", "Value reader not properly initialized, did you remember to call TTreeReader.Set(Next)Entry()?");
         return 0;
      }
      void *address = GetAddress(); // Needed to figure out if it's a pointer
      return fProxy->IsaPointer() ? *(T**)address : (T*)address; }
   T* operator->() { return Get(); }
   T& operator*() { return *Get(); }

protected:
   // FIXME: use IsA() instead once we have ClassDefTInline
   /// Get the template argument as a string.
   virtual const char* GetDerivedTypeName() const {
      static const std::string sElementTypeName = GetElementTypeName(typeid(T));
      return sElementTypeName.data();
   }

   // FIXME: re-introduce once we have ClassDefTInline!
   //ClassDefT(TTreeReaderValue, 0);//Accessor to data via TTreeReader
};

#endif // ROOT_TTreeReaderValue
 TTreeReaderValue.h:1
 TTreeReaderValue.h:2
 TTreeReaderValue.h:3
 TTreeReaderValue.h:4
 TTreeReaderValue.h:5
 TTreeReaderValue.h:6
 TTreeReaderValue.h:7
 TTreeReaderValue.h:8
 TTreeReaderValue.h:9
 TTreeReaderValue.h:10
 TTreeReaderValue.h:11
 TTreeReaderValue.h:12
 TTreeReaderValue.h:13
 TTreeReaderValue.h:14
 TTreeReaderValue.h:15
 TTreeReaderValue.h:16
 TTreeReaderValue.h:17
 TTreeReaderValue.h:18
 TTreeReaderValue.h:19
 TTreeReaderValue.h:20
 TTreeReaderValue.h:21
 TTreeReaderValue.h:22
 TTreeReaderValue.h:23
 TTreeReaderValue.h:24
 TTreeReaderValue.h:25
 TTreeReaderValue.h:26
 TTreeReaderValue.h:27
 TTreeReaderValue.h:28
 TTreeReaderValue.h:29
 TTreeReaderValue.h:30
 TTreeReaderValue.h:31
 TTreeReaderValue.h:32
 TTreeReaderValue.h:33
 TTreeReaderValue.h:34
 TTreeReaderValue.h:35
 TTreeReaderValue.h:36
 TTreeReaderValue.h:37
 TTreeReaderValue.h:38
 TTreeReaderValue.h:39
 TTreeReaderValue.h:40
 TTreeReaderValue.h:41
 TTreeReaderValue.h:42
 TTreeReaderValue.h:43
 TTreeReaderValue.h:44
 TTreeReaderValue.h:45
 TTreeReaderValue.h:46
 TTreeReaderValue.h:47
 TTreeReaderValue.h:48
 TTreeReaderValue.h:49
 TTreeReaderValue.h:50
 TTreeReaderValue.h:51
 TTreeReaderValue.h:52
 TTreeReaderValue.h:53
 TTreeReaderValue.h:54
 TTreeReaderValue.h:55
 TTreeReaderValue.h:56
 TTreeReaderValue.h:57
 TTreeReaderValue.h:58
 TTreeReaderValue.h:59
 TTreeReaderValue.h:60
 TTreeReaderValue.h:61
 TTreeReaderValue.h:62
 TTreeReaderValue.h:63
 TTreeReaderValue.h:64
 TTreeReaderValue.h:65
 TTreeReaderValue.h:66
 TTreeReaderValue.h:67
 TTreeReaderValue.h:68
 TTreeReaderValue.h:69
 TTreeReaderValue.h:70
 TTreeReaderValue.h:71
 TTreeReaderValue.h:72
 TTreeReaderValue.h:73
 TTreeReaderValue.h:74
 TTreeReaderValue.h:75
 TTreeReaderValue.h:76
 TTreeReaderValue.h:77
 TTreeReaderValue.h:78
 TTreeReaderValue.h:79
 TTreeReaderValue.h:80
 TTreeReaderValue.h:81
 TTreeReaderValue.h:82
 TTreeReaderValue.h:83
 TTreeReaderValue.h:84
 TTreeReaderValue.h:85
 TTreeReaderValue.h:86
 TTreeReaderValue.h:87
 TTreeReaderValue.h:88
 TTreeReaderValue.h:89
 TTreeReaderValue.h:90
 TTreeReaderValue.h:91
 TTreeReaderValue.h:92
 TTreeReaderValue.h:93
 TTreeReaderValue.h:94
 TTreeReaderValue.h:95
 TTreeReaderValue.h:96
 TTreeReaderValue.h:97
 TTreeReaderValue.h:98
 TTreeReaderValue.h:99
 TTreeReaderValue.h:100
 TTreeReaderValue.h:101
 TTreeReaderValue.h:102
 TTreeReaderValue.h:103
 TTreeReaderValue.h:104
 TTreeReaderValue.h:105
 TTreeReaderValue.h:106
 TTreeReaderValue.h:107
 TTreeReaderValue.h:108
 TTreeReaderValue.h:109
 TTreeReaderValue.h:110
 TTreeReaderValue.h:111
 TTreeReaderValue.h:112
 TTreeReaderValue.h:113
 TTreeReaderValue.h:114
 TTreeReaderValue.h:115
 TTreeReaderValue.h:116
 TTreeReaderValue.h:117
 TTreeReaderValue.h:118
 TTreeReaderValue.h:119
 TTreeReaderValue.h:120
 TTreeReaderValue.h:121
 TTreeReaderValue.h:122
 TTreeReaderValue.h:123
 TTreeReaderValue.h:124
 TTreeReaderValue.h:125
 TTreeReaderValue.h:126
 TTreeReaderValue.h:127
 TTreeReaderValue.h:128
 TTreeReaderValue.h:129
 TTreeReaderValue.h:130
 TTreeReaderValue.h:131
 TTreeReaderValue.h:132
 TTreeReaderValue.h:133
 TTreeReaderValue.h:134
 TTreeReaderValue.h:135
 TTreeReaderValue.h:136
 TTreeReaderValue.h:137
 TTreeReaderValue.h:138
 TTreeReaderValue.h:139
 TTreeReaderValue.h:140
 TTreeReaderValue.h:141
 TTreeReaderValue.h:142
 TTreeReaderValue.h:143
 TTreeReaderValue.h:144
 TTreeReaderValue.h:145
 TTreeReaderValue.h:146
 TTreeReaderValue.h:147
 TTreeReaderValue.h:148
 TTreeReaderValue.h:149
 TTreeReaderValue.h:150
 TTreeReaderValue.h:151
 TTreeReaderValue.h:152
 TTreeReaderValue.h:153
 TTreeReaderValue.h:154
 TTreeReaderValue.h:155
 TTreeReaderValue.h:156
 TTreeReaderValue.h:157
 TTreeReaderValue.h:158
 TTreeReaderValue.h:159
 TTreeReaderValue.h:160
 TTreeReaderValue.h:161