/**
 * @file
 * $Id$
 * $Revision$
 * $Author$
 * $Date$
 *
 * This file is part of The iWear Framework.
 *
 * The iWear Framework is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by the
 * Free Software Foundation as in version 2 of the License.

 * 
 * The iWear Framework 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 for
 * more details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * The iWear Framework; if not, write to the Free Software Foundation, Inc., 59
 * Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifndef __IWREMOTE_SPTRTRACKER_H
#define __IWREMOTE_SPTRTRACKER_H

#ifndef __IWEAR_SPECIALPOINTER_H
#include <iwear/specialpointer.h>
#endif

#ifndef __IWEAR_THREADLOCKED_H
#include <iwear/threadlocked.h>
#endif

#ifndef __IWEAR_THREADLOCKER_H
#include <iwear/threadlocker.h>
#endif

#ifndef __IWEAR_EXCEPTIONS_H
#include <iwear/exceptions.h>
#endif

#include <set>


namespace iwear
{
/**
 * Every class that wants to benefit from the SPtr construct must be derived
 * from SPtrTracker. Then it also includes the ThreadLocked capabilities so it
 * does not need to inherit from them. Every inheritance from SPtrTracker
 * should be virtual, in case some class has double SPtrTracker inheritance
 * along its path.
 * @todo Check what this construct does to multiple inheritance path classes !!
 * @bug There is a little chance of a race condition here. Although never seen
 * in production application code it might be possible that this leads to a
 * crash on SMP machines.
 */
class SPtrTracker : public virtual ThreadLocked/*{{{*/
{
protected:
    set<SpecialPointer*> SPtrMap;
    /**
     * Flag indicating that the destructor runs/has run. This is to reduce the
     * possible impact of a race condition when deleting the corresponding
     * object. However this does not fully prevent the race condition, which
     * means that you will sometimes access already deleted memory, which might
     * even result in an application crash.
     */
    bool dying : 1;
public:
    
    SPtrTracker();
    virtual ~SPtrTracker() = 0;

    /**
     * Deregisters a pointer that now does not point to this any more.
     */
    void deregister_sptr( SpecialPointer* );
    /**
     * Registeres a new Pointer, which points to this.
     */
    void register_sptr  ( SpecialPointer* );

    /**
     * This function does exactly nothing. Its just here to point you to the
     * documentation of this class. You will probably made some error...
     */
    inline static void read_comment_on_this_function_please( void ) { }
};/*}}}*/

inline SPtrTracker::SPtrTracker()/*{{{*/
    : dying(false)
{
}/*}}}*/

inline void SPtrTracker::register_sptr( SpecialPointer* ptr)/*{{{*/
{
    ThreadLocker LockMe(&Mutex);

    if ( ! dying )
    {
	SPtrMap.insert(ptr);
    }
    else
    {
	throw race_error("While Registering Pointer");
    }

}/*}}}*/

inline void SPtrTracker::deregister_sptr( SpecialPointer* ptr)/*{{{*/
{
    ThreadLocker LockMe(&Mutex);

    if ( ! dying )
    {
	SPtrMap.erase(ptr);
    }
    else
    {
	// No need to throw here since we wanted to deregister anyways...
    }

}/*}}}*/

} // namespace iwear

#endif
