/*
 * This source file is part of KEOS (Free 3D Engine)
 * For the latest info, see http://www.keosengine.org/
 * E-mails : thierry.vouriot@keosengine.org, yeri@keosengine.org
 * 
 * This program 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 of the License, or (at your option) any later
 * version.
 *
 * This program 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 program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place - Suite 330, Boston, MA 02111-1307, USA, or go to
 * http://www.gnu.org/copyleft/lesser.txt.
 *
 */

#ifndef KEOS_SMARTPTR_H
#define KEOS_SMARTPTR_H

#include "KeosSmartPtrPolicies.h"
#include "KeosException.h"

namespace Keos
{
    //-----------------------------------------------------------------------
	 /** Smart pointers using policies.
     *
     */
    template <class T, template <class> class Ownership = CRefCount>
    class CSmartPtr : public Ownership<T>
    {
    public :

        /** Default constructor.
         *
         */
        CSmartPtr();

        /** Copy constructor.
         *  @param Copy Object to be copied.
         */
        CSmartPtr(const CSmartPtr& Copy);

        /** Constructor from a pointer.
         *  @param pPointer Pointer to store.
         */
        CSmartPtr(T* pPointer);

        /** Destructor.
         *
         */
        ~CSmartPtr();

        /** Star operator.
         *  @return Reference on the datum.
         */
        T& operator * () const;

        /** Access operator.
         *  @return Pointer on the datum.
         */
        T* operator ->() const;

        /** Affectation operator.
         *  @param Pointer Pointer to affect
         *  @return Constant reference on the current object.
         */
        const CSmartPtr& operator =(const CSmartPtr& Pointer);

        /** Operator of cast in T*.
         *  @return Constant pointer on the datum.
         */
        operator T*() const;

    private :

        /** Swap two CSmartPtr.
         *  @param Ptr Pointer to swap.
         */
        void Swap(CSmartPtr& Ptr);

        //! Pointer on the datum.
        T* m_pData;
    };


    //=======================================================================
    // CSmartPtr inline functions
    //=======================================================================
    
    //-----------------------------------------------------------------------
    template <class T, template <class> class Ownership>
    inline CSmartPtr<T, Ownership>::CSmartPtr() :
    m_pData(NULL)
    {

    }

    //-----------------------------------------------------------------------
    template <class T, template <class> class Ownership>
    inline CSmartPtr<T, Ownership>::CSmartPtr(const CSmartPtr<T, Ownership>& Copy) :
    Ownership<T>(Copy),
    m_pData      (Clone(Copy.m_pData))
    {

    }

    //-----------------------------------------------------------------------
    template <class T, template <class> class Ownership>
    inline CSmartPtr<T, Ownership>::CSmartPtr(T* pPointer) :
    m_pData(pPointer)
    {

    }

    //-----------------------------------------------------------------------
    template <class T, template <class> class Ownership>
    inline CSmartPtr<T, Ownership>::~CSmartPtr()
    {
        Release(m_pData);
    }

    //-----------------------------------------------------------------------
    template <class T, template <class> class Ownership>
    inline void CSmartPtr<T, Ownership>::Swap(CSmartPtr<T, Ownership>& Ptr)
    {
        Ownership<T>::Swap(Ptr);
        std::swap(m_pData, Ptr.m_pData);
    }

    //-----------------------------------------------------------------------
    template <class T, template <class> class Ownership>
    inline T& CSmartPtr<T, Ownership>::operator *() const
    {
        Assert(m_pData != NULL);

        return *m_pData;
    }

    //-----------------------------------------------------------------------
    template <class T, template <class> class Ownership>
    inline T* CSmartPtr<T, Ownership>::operator ->() const
    {
        Assert(m_pData != NULL);

        return m_pData;
    }

    //-----------------------------------------------------------------------
    template <class T, template <class> class Ownership>
    inline const CSmartPtr<T, Ownership>& CSmartPtr<T, Ownership>::operator =(const CSmartPtr<T, Ownership>& Pointer)
    {
        CSmartPtr<T, Ownership>(Pointer).Swap(*this);

        return *this;
    }

    //-----------------------------------------------------------------------
    template <class T, template <class> class Ownership>
    inline CSmartPtr<T, Ownership>::operator T*() const
    {
        return m_pData;
    }

} // namespace Keos

#endif // KEOS_SMARTPTR_H
