//  Copyright (C) 2007-2010  CEA/DEN, EDF R&D, OPEN CASCADE
//
//  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
//  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
//
//  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
//

//  File   : SALOME_GenericObjPtr.hh
//  Author : Oleg UVAROV
//  Module : SALOME
//
#ifndef SALOME_GenericObjPointer_HH
#define SALOME_GenericObjPointer_HH

#include "SALOMEconfig.h"
#include CORBA_SERVER_HEADER(SALOME_GenericObj)

#include <iosfwd>  // for std::basic_ostream

namespace SALOME
{
  //----------------------------------------------------------------------------
  template <class TGenericObj>
  class GenericObjPtr
  {
    //! Pointer to the actual object.
    TGenericObj* myPointer;

    void
    swap(GenericObjPtr& thePointer)
    {
      TGenericObj* aPointer = thePointer.myPointer;
      thePointer.myPointer = this->myPointer;
      this->myPointer = aPointer;
    }

    void
    Register()
    {
      if(this->myPointer)
	this->myPointer->Register();
    }

    void
    Destroy()
    {
      if(this->myPointer){
	this->myPointer->Destroy();
	this->myPointer = NULL;
      }
    }

  public:
    //! Initialize smart pointer to NULL.
    GenericObjPtr():
      myPointer(NULL)
    {}

    //! Initialize smart pointer to given object (TSGenericObj must be complete).
    template<class TGenObj>
    explicit
    GenericObjPtr(TGenObj* thePointer): 
      myPointer(thePointer) 
    {
      this->Register();
    }

    /*! 
      Initialize smart pointer with a new reference to the same object
      referenced by given smart pointer.
     */
    GenericObjPtr(const GenericObjPtr& thePointer):
      myPointer(thePointer.myPointer) 
    {
      this->Register();
    }

    /*! 
      Initialize smart pointer with a new reference to the same object
      referenced by given smart pointer.
     */
    template<class TGenObj>
    GenericObjPtr(const GenericObjPtr<TGenObj>& thePointer):
      myPointer(thePointer.get()) 
    {
      this->Register();
    }

    //! Destroy smart pointer and remove the reference to its object.
    ~GenericObjPtr()
    {
      this->Destroy();
    }

    /*! 
      Assign object to reference.  This removes any reference to an old
      object.
    */
    template<class TGenObj>
    GenericObjPtr&
    operator=(TGenObj* thePointer)
    {
      GenericObjPtr aTmp(thePointer);
      aTmp.swap(*this);
      return *this;
    }

    /*! 
      Assign object to reference.  This removes any reference to an old
      object.
    */
    GenericObjPtr& 
    operator=(const GenericObjPtr& thePointer)
    {
      GenericObjPtr aTmp(thePointer);
      aTmp.swap(*this);
      return *this;
    }

    /*! 
      Assign object to reference.  This removes any reference to an old
      object.
    */
    template<class TGenObj>
    GenericObjPtr& 
    operator=(const GenericObjPtr<TGenObj>& thePointer)
    {
      GenericObjPtr aTmp(thePointer);
      aTmp.swap(*this);
      return *this;
    }

    //! Get the contained pointer.
    virtual
    TGenericObj* 
    get() const
    {
      return this->myPointer;
    }

    //! Get the contained pointer.
    operator TGenericObj* () const
    {
      return this->get();
    }

    /*! 
      Dereference the pointer and return a reference to the contained
      object.
    */
    TGenericObj& 
    operator*() const
    {
      return *this->get();
    }

    //! Provides normal pointer target member access using operator ->.
    TGenericObj* operator->() const
    {
      return this->get();
    }

    operator bool () const
    {
      return this->get() != 0;
    }
  };
}

template<class T, class U> 
inline 
bool 
operator<(SALOME::GenericObjPtr<T> const & a, SALOME::GenericObjPtr<U> const & b)
{
  return a.get() < b.get();
}

template<class T, class U> 
inline
bool 
operator==(SALOME::GenericObjPtr<T> const & a, SALOME::GenericObjPtr<U> const & b)
{
  return a.get() == b.get();
}

template<class T, class U> 
inline 
bool 
operator!=(SALOME::GenericObjPtr<T> const & a, SALOME::GenericObjPtr<U> const & b)
{
  return a.get() != b.get();
}

template<class Y> 
std::ostream& 
operator<< (std::ostream & os, SALOME::GenericObjPtr<Y> const & p)
{
  os << p.get();
  return os;
}


#endif
