// @(#)root/tree:$Name:  $:$Id: TFriendElement.cxx,v 1.10 2003/08/23 14:53:41 brun Exp $
// Author: Rene Brun   07/04/2001

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

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TFriendElement                                                       //
//                                                                      //
// A TFriendElement TF describes a TTree object TF in a file.           //
// When a TFriendElement TF is added to the the list of friends of an   //
// existing TTree T, any variable from TF can be referenced in a query  //
// to T.                                                                //
//                                                                      //
// To add a TFriendElement to an existing TTree T, do:                  //
//       T.AddFriend("friendTreename","friendTreeFile");                //
//                                                                      //
//  See TTree::AddFriend for more information.                          //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TTree.h"
#include "TFriendElement.h"
#include "TFile.h"
#include "TROOT.h"

R__EXTERN TTree *gTree;

ClassImp(TFriendElement)

//______________________________________________________________________________
TFriendElement::TFriendElement() : TNamed()
{
//*-*-*-*-*-*Default constructor for a friend element*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*        =======================================

   fFile       = 0;
   fTree       = 0;
   fOwnFile    = kFALSE;
   fOwnTree    = kTRUE;
   fParentTree = gTree;
}

//______________________________________________________________________________
TFriendElement::TFriendElement(TTree *tree, const char *treename, const char *filename)
    :TNamed(treename,filename)
{
//*-*-*-*-*-*-*-*-*-*-*-*-*Create a friend element*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*                      ======================
//
// If treename is of the form "a=b", an alias called "a" is created for
// treename = "b" by default the alias name is the name of the tree.

   fFile       = 0;
   fTree       = 0;
   fOwnFile    = kTRUE;
   fOwnTree    = kTRUE;
   fParentTree = tree;
   fTreeName   = treename;
   if (strchr(treename,'=')) {
      char *temp = Compress(treename);
      char *equal = strchr(temp,'=');
      *equal=0;
      fTreeName = equal+1;
      SetName(temp);
      delete [] temp;
   }

   Connect();
}

//______________________________________________________________________________
TFriendElement::TFriendElement(TTree *tree, const char *treename, TFile *file)
    :TNamed(treename,file?file->GetName():"")
{
//*-*-*-*-*-*-*-*-*-*-*-*-*Create a friend element*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*                      ======================
//
// If treename is of the form "a=b", an alias called "a" is created for
// treename = "b" by default the alias name is the name of the tree.
// The passed TFile is managed by the user (i.e. user must delete the TFile).

   fFile       = file;
   fTree       = 0;
   fOwnFile    = kFALSE;
   fOwnTree    = kTRUE;
   fParentTree = tree;
   fTreeName   = treename;
   if (strchr(treename,'=')) {
      char *temp = Compress(treename);
      char *equal = strchr(temp,'=');
      *equal=0;
      fTreeName = equal+1;
      SetName(temp);
      delete [] temp;
   }

   Connect();
}

//______________________________________________________________________________
TFriendElement::TFriendElement(TTree *tree, TTree* friendtree, const char *alias)
:TNamed(friendtree?friendtree->GetName():"",
          friendtree
        ? (   friendtree->GetDirectory()
            ? (    friendtree->GetDirectory()->GetFile()
                 ? friendtree->GetDirectory()->GetFile()->GetName()
                 :  ""
              )
            : ""
          )
        :  "")
{
//*-*-*-*-*-*-*-*-*-*-*-*-*Create a friend element*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*                      ======================
//

   fTree       = friendtree;
   fTreeName   = "";
   fFile       = 0;
   if (fTree) {
      fTreeName   = fTree->GetName();
      if (fTree->GetDirectory()) fFile = fTree->GetDirectory()->GetFile();
   }
   fOwnFile    = kFALSE;
   fOwnTree    = kFALSE;
   fParentTree = tree;
   if (alias && strlen(alias)) {
      char *temp = Compress(alias);
      SetName(temp);
      delete [] temp;
   }

   // No need to Connect.
}

//______________________________________________________________________________
TFriendElement::~TFriendElement()
{

   DisConnect();
}

//_______________________________________________________________________
TTree *TFriendElement::Connect()
{
// Connect file and return TTree.

   GetFile();
   return GetTree();
}

//_______________________________________________________________________
TTree *TFriendElement::DisConnect()
{
// DisConnect file and TTree.

   if (fOwnTree) delete fTree;
   if (fOwnFile) delete fFile;
   fFile = 0;
   fTree = 0;
   return 0;
}

//_______________________________________________________________________
TFile *TFriendElement::GetFile()
{
// Return pointer to TFile containing this friend TTree.

   if (fFile || IsZombie()) return fFile;
   if (strlen(GetTitle()))
      fFile = new TFile(GetTitle());
   else {
      TDirectory *dir = fParentTree->GetDirectory();
      if (dir) {
         fFile = dir->GetFile();
         fOwnFile = kFALSE;
      }
   }
   if (fFile && fFile->IsZombie()) {
      MakeZombie();
      delete fFile;
      fFile = 0;
   }
   return fFile;
}

//_______________________________________________________________________
TTree *TFriendElement::GetTree()
{
// Return pointer to friend TTree.

   if (fTree) return fTree;
   if (!GetFile()) {
      // This could be a memory tree or chain
      fTree = (TTree*)gROOT->FindObject(GetTreeName());
      if (fTree) {
         if (!fTree->InheritsFrom(TTree::Class()) ) {
            fTree = 0;
         } else {
            // Since we did NOT create it ourself, let's not
            // take ownership of it.
            fOwnTree = kFALSE;
         }
      }
      return fTree;
   }
   fTree = (TTree*)fFile->Get(GetTreeName());
   TDirectory *dir = fParentTree->GetDirectory();
   if (dir && dir != gDirectory) dir->cd();
   return fTree;
}

//_______________________________________________________________________
void TFriendElement::ls(Option_t *) const
{
// List this friend element.

   printf(" Friend Tree: %s in file: %s\n",GetName(),GetTitle());
}
