////////////////////////////////////////////////////////////////////////
// $Id: CandRefer.cxx,v 1.4 2003/12/07 06:09:49 gmieg Exp $
//
// CandRefer.cxx
//
// Class for controlling access to the CandBase class.
//
// The CandBase class inherits from CandRefCounted for ref-counting.
//
// Each concrete CandBase must define a Dup function.
// Each concrete CandBase must grant friendship to class CandRefer.
//
// Adapted from Babar's BbrReferencer (written by Gautier Hamel de
// Monchenault and Bob Jacobsen).
//
// Author:  G. Irwin 1/2000
////////////////////////////////////////////////////////////////////////

#include <cassert>

#include "TBuffer.h"
#include "TClass.h"

#include "Candidate/CandBase.h"
#include "Candidate/CandRefer.h"
#include "MessageService/MsgService.h"

ClassImp(CandRefer)

//______________________________________________________________________
CVSID("$Id: CandRefer.cxx,v 1.4 2003/12/07 06:09:49 gmieg Exp $");

//______________________________________________________________________
CandRefer::CandRefer() :
  fRef(0) 
{
}

//______________________________________________________________________
CandRefer::CandRefer(CandBase *ref) :
  fRef(ref) 
{
   IncNRefer();
}

//______________________________________________________________________
CandRefer::CandRefer(const CandRefer &cr)
{
   fRef = cr.fRef;
   IncNRefer();
}

//______________________________________________________________________
CandRefer::~CandRefer()
{ 
   DropRefer();
}

//______________________________________________________________________
Bool_t CandRefer::operator==(const CandRefer &cr) const
{ 
   return (fRef == cr.fRef);
}

//______________________________________________________________________
Bool_t CandRefer::operator!=(const CandRefer &cr) const
{ 
   return (fRef != cr.fRef);
}

//______________________________________________________________________
CandRefer &CandRefer::operator=(const CandRefer &cr)
{
   if ((this != &cr) && (fRef != cr.fRef)) {
     DropRefer();
     fRef = cr.fRef;
     IncNRefer();
   }
   return *this;
} 

//______________________________________________________________________
Int_t CandRefer::DecNRefer()
{
   if (fRef) return fRef->DropLink() - 1;   // Subtract LocalHandle link
   return 0;
}

//______________________________________________________________________
void CandRefer::DropRefer()
{
   if (fRef && DecNRefer()==0) delete fRef;
   fRef = (CandBase *) 0;
}

//______________________________________________________________________
Int_t CandRefer::IncNRefer()
{
   if (fRef) return fRef->AddLink() - 1;    // Subtract LocalHandle link
   return 0;
}

//______________________________________________________________________
Int_t CandRefer::GetNRefers() const
{
   if (fRef) return fRef->GetNLinks() - 1;  // Subtract LocalHandle link
   return 0;
}

//______________________________________________________________________
CandBase *CandRefer::OwnRef()
{

// Make sure the reference exists
   assert(fRef!=0);
    
// Make sure the referenced object has links (at least this one)
   assert(GetNRefers() > 0);

   if (GetNRefers() != 1) {  // No exclusive access to referenced object

     MSG("Cand", Msg::kSynopsis) << "Candidate object of class "
         << fRef->ClassName() << " cloned before modification." << endl;

// Decrement the referenced object counter
     DecNRefer();
     assert(GetNRefers() > 0);

// Clone the referenced object
     fRef = fRef->Dup();

// Increment the new referenced object counter
     IncNRefer();
     assert(GetNRefers()==1);
   }

// Return the reference
   return fRef;
}

//______________________________________________________________________
void CandRefer::SetRef(CandBase *ref)
{
   if (ref != fRef) {
     DropRefer();
     fRef = ref;
     IncNRefer();
   }
}

//______________________________________________________________________
void CandRefer::Streamer(TBuffer &R__b)
{

// Stream an object of class CandRefer.
   if (R__b.IsReading()) {
      CandRefer::Class()->ReadBuffer(R__b, this);
      IncNRefer(); // Ref count incremented from CandRefer Streamer:2/03
   } else {
      CandRefer::Class()->WriteBuffer(R__b, this);
   }
}
