////////////////////////////////////////////////////////////////////////
// $Id: CH.h,v 1.1 2005/08/26 23:30:13 gmieg Exp $
//
// CH.h
//
// CH contains the templated interface to CandHandle
// for specialized access to CandBase derived objects.
//
// Author:  P. Eschevarria 5/2004
////////////////////////////////////////////////////////////////////////

#ifndef CH_H
#define CH_H

#include "Candidate/CandHandle.h"

template <class CandType>
class CH : public CandHandle
{

public:
  enum ErrorType {DereferenceNil};

  CH();
  CH(CandBase *cb);
  CH(const CandHandle &ch);

  template<class T>
  CH(const CH<T> &ch);

  template<class T>
  operator CH<T>();

  const CandType* operator->() const;
  const CandType& operator*() const;
//CandHandle* operator&();
//const CandHandle* operator&() const;

  CH<CandType> &operator=(const CandHandle &rhs);

  template<class T>
  CH<CandType> &operator=(const CH<T> &rhs);

  virtual CH<CandType> *DupHandle() const;
  bool IsValid() const;

  const CandType& RCmd() const;
  CandType& WCmd();

ClassDef(CH,1)                  // Templated Read/Write CandHandle class
};

#include <iostream>
using namespace std;

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

#include "MessageService/MsgService.h"

//______________________________________________________________________
template <class CandType>
CH<CandType>::CH() :
  CandHandle(0)
{
}

//______________________________________________________________________
template <class CandType>
CH<CandType>::CH(CandBase *cb) :
  CandHandle(dynamic_cast<CandType*>(cb))
{
}

//______________________________________________________________________
template <class CandType>
CH<CandType>::CH(const CandHandle &ch)
{
  *this = const_cast<CandHandle &>(ch);
}

//______________________________________________________________________
template <class CandType>
CH<CandType> &CH<CandType>::operator=(const CandHandle &rhs)
{
  CandHandle *chlhs = dynamic_cast<CandHandle*>(this);
  const CandHandle *chrhs = dynamic_cast<const CandHandle*>(&rhs);
  const CandType *refCrhs =
                    dynamic_cast<const CandType*>(chrhs->GetCandBase());
  
  if (refCrhs) {
    if (refCrhs == chlhs->GetCandBase()) {
      return *this;
    }  
    else {
      CandHandle chnew(const_cast<CandType*>(refCrhs));
      *chlhs = chnew;                    // Invoke CandHandle::operator=
      return *this;
    }
  }
  else {
    CandHandle chnew((CandBase*)0);
    *chlhs = chnew;                      // Invoke CandHandle::operator=
    return *this;
  }
}

//______________________________________________________________________
template<class CandType>
CH<CandType> *CH<CandType>::DupHandle() const
{
   return (new CH<CandType>(*this));
}

//______________________________________________________________________
template<class CandType>
bool CH<CandType>::IsValid() const
{
  return dynamic_cast<const CandType*>(GetCandBase());
}

//______________________________________________________________________
template <class CandType>
const CandType *CH<CandType>::operator->() const
{
  const CandType* cb = dynamic_cast<const CandType*>(GetCandBase());
  return cb;
}

//______________________________________________________________________
template <class CandType>
const CandType &CH<CandType>::operator*() const
{
  const CandType* cb = dynamic_cast<const CandType*>(GetCandBase());
  return *cb;
}

//______________________________________________________________________
template<class CandType>
const CandType &CH<CandType>::RCmd() const
{
  const CandType *cb = dynamic_cast<const CandType*>(GetCandBase());
  if (cb == 0) {
//gmi MSG("Cand", Msg::kError)
//gmi  << "Wrong type referenced from CandHandle " << GetName() << endl;
    throw CH::DereferenceNil;
  }
  return *cb;
}

//______________________________________________________________________
template<class CandType>
CandType &CH<CandType>::WCmd()
{
  CandType *cb = dynamic_cast<CandType*>(GetOwnedCandBase());
  if (cb == 0) {
//gmi MSG("Cand", Msg::kError)
//gmi  << "Wrong type referenced from CandHandle " << GetName() << endl;
    throw CH::DereferenceNil;
  }
  return *cb;
}

#ifndef __CINT__         // Templated functions don't work with rootcint

//______________________________________________________________________
template <class CandType>
template<class T>
CH<CandType>::CH(const CH<T> &ch)
{
  *this = const_cast<CH<T>&>(ch);
}

//______________________________________________________________________
template <class CandType>
template<class T>
CH<CandType>::operator CH<T>()
{
  return CH<T>(GetCandBase());
}

//______________________________________________________________________
template <class CandType>
template<class T>
CH<CandType> &CH<CandType>::operator=(const CH<T> &rhs)
{
  CandHandle *chlhs = dynamic_cast<CandHandle*>(this);
  const CandHandle *chrhs = dynamic_cast<const CandHandle*>(&rhs);
  const CandType *refCrhs =
                    dynamic_cast<const CandType*>(chrhs->GetCandBase());
  
  if (refCrhs) {
    if (refCrhs == chlhs->GetCandBase()) {
      return *this;
    }  
    else {
      CandHandle chnew(const_cast<CandType*>(refCrhs));
      *chlhs = chnew;                    // Invoke CandHandle::operator=
      return *this;
    }
  }
  else {
    CandHandle chnew((CandBase*)0);
    *chlhs = chnew;                      // Invoke CandHandle::operator=
    return *this;
  }
}

#endif                                                       // __CINT__

#endif                                                           // CH_H
