//------------------------------------------------------------------------------
// emCrossPtr.h
//
// Copyright (C) 2007-2008 Oliver Hamann.
//
// Homepage: http://eaglemode.sourceforge.net/
//
// This program is free software: you can redistribute it and/or modify it under
// the terms of the GNU General Public License version 3 as published by the
// Free Software Foundation.
//
// 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 General Public License version 3 for
// more details.
//
// You should have received a copy of the GNU General Public License version 3
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//------------------------------------------------------------------------------

#ifndef emCrossPtr_h
#define emCrossPtr_h

#ifndef emStd1_h
#include <emCore/emStd1.h>
#endif

class emCrossPtrPrivate {
protected:
        friend class emCrossPtrList;
        void Unlink();
        void * Obj;
        emCrossPtrPrivate * * ThisPtr;
        emCrossPtrPrivate * Next;
};


//==============================================================================
//================================= emCrossPtr =================================
//==============================================================================

template <class CLS> class emCrossPtr : private emCrossPtrPrivate {

public:

        // Template class for an object pointer which is automatically set to
        // NULL when the object is destructed. It is something like a so-called
        // weak reference (in compare to emRef). The name "cross pointer" comes
        // from the fact that these pointers can be safely used to cross the
        // ownership hierarchy.
        //
        // The template parameter CLS is the class of the object to be pointed.
        // It must be an emCrossPtrList or a class that has the method
        // LinkCrossPtr(emCrossPtrPrivate) which forwards the call to a member
        // emCrossPtrList. Typical candidates are emContext, emModel, emPanel
        // and their derivatives.

        emCrossPtr();
                // Construct a NULL pointer.

        emCrossPtr(const emCrossPtr & crossPtr);
                // Construct a copied pointer.

        emCrossPtr(CLS * obj);
                // Construct from a normal pointer (NULL is allowed).

        ~emCrossPtr();
                // Destructor.

        emCrossPtr & operator = (const emCrossPtr & crossPtr);
        emCrossPtr & operator = (CLS * obj);
                // Copy operators (NULL-pointer is allowed).

        operator CLS * () const;
                // Cast this to a normal pointer (can be NULL).

        CLS * Get() const;
                // Get the normal pointer (can be NULL).

        CLS * operator -> () const;
                // This makes this class a so-called "smart pointer". For
                // example, if p is an emCrossPtr to an object which has a
                // method named Hello(), one could say p->Hello() instead of
                // p.Get()->Hello().
};


//==============================================================================
//=============================== emCrossPtrList ===============================
//==============================================================================

class emCrossPtrList : public emUncopyable {

public:

        // Class for a list of cross pointers pointing to an object.

        emCrossPtrList();
                // Start with an empty list.

        ~emCrossPtrList();
                // Like BreakCrossPtrs().

        void BreakCrossPtrs();
                // Remove all cross pointers and set them to NULL. This could be
                // called at the beginning of a destructor of an object for
                // getting rid of the pointers a little bit earlier than through
                // the destructor of this list.

        void LinkCrossPtr(emCrossPtrPrivate & crossPtr);
                // Insert a cross pointer to this list (the field crossPtr.Obj
                // is not touched by this). This method is only to be called by
                // emCrossPtr or by forwarding from an object class instance to
                // a member instance of this class.

private:
        emCrossPtrPrivate * First;
};


//==============================================================================
//============================== Implementations ===============================
//==============================================================================

template <class CLS> inline emCrossPtr<CLS>::emCrossPtr()
{
        Obj=NULL;
}

template <class CLS> inline emCrossPtr<CLS>::emCrossPtr(
        const emCrossPtr & crossPtr
)
{
        Obj=crossPtr.Obj;
        if (Obj) ((CLS*)Obj)->LinkCrossPtr(*this);
}

template <class CLS> inline emCrossPtr<CLS>::emCrossPtr(CLS * obj)
{
        Obj=obj;
        if (obj) obj->LinkCrossPtr(*this);
}

template <class CLS> inline emCrossPtr<CLS>::~emCrossPtr()
{
        if (Obj) Unlink();
}

template <class CLS> emCrossPtr<CLS> & emCrossPtr<CLS>::operator = (
        const emCrossPtr & crossPtr
)
{
        if (Obj) Unlink();
        Obj=crossPtr.Obj;
        if (Obj) ((CLS*)Obj)->LinkCrossPtr(*this);
        return *this;
}

template <class CLS> emCrossPtr<CLS> & emCrossPtr<CLS>::operator = (CLS * obj)
{
        if (Obj) Unlink();
        Obj=obj;
        if (obj) obj->LinkCrossPtr(*this);
        return *this;
}

template <class CLS> inline emCrossPtr<CLS>::operator CLS * () const
{
        return (CLS*)Obj;
}

template <class CLS> inline CLS * emCrossPtr<CLS>::Get() const
{
        return (CLS*)Obj;
}

template <class CLS> inline CLS * emCrossPtr<CLS>::operator -> () const
{
        return (CLS*)Obj;
}

inline emCrossPtrList::emCrossPtrList()
{
        First=NULL;
}

inline emCrossPtrList::~emCrossPtrList()
{
        BreakCrossPtrs();
}


#endif