/**
 * @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_REMOTEREFERENCE_H
#define __IWREMOTE_REMOTEREFERENCE_H

#ifndef __IWEAR_UTILITY_H
#include <iwear/utility.h>
#endif

namespace iwear
{

/**
 * This class is to hold references on remote objects. Every RemoteObject should be 
 */
template<class T>    
class RemoteReference /*{{{*/
{
    friend class RemoteObject; ///< humm, I dont like friends... @todo find a better way
public:
   /**
    * 
    */
    mutable T* ptr;

   /**
    * Constructs an emtpy Pointer, pointing to NULL
    */
    RemoteReference();

   /**
    * Constructs a Pointer pointing to _ptr. This also registers at _ptr for
    * lifetime-end notification.
    */
    RemoteReference(T* _ptr);

   /**
    * This destroys the pointer object, and also deregisters it from
    * notification of lifetime end 
    */
    virtual ~RemoteReference();

    /**
     * Dereference the pointer, just if it was a usual T*. This does not do any
     * locking, since if needed, it would be done in the correct class. There
     * could be little race condition with the object pointed to beeing
     * currently destructed and then calling on an object not beeing there. But
     * you can still cast to an ordinary pointer and do the same, so no need
     * for this here...
     * @note Although this operator can check for a few memory boundaries, it
     * will not prevent you from accesing wrong memory and crashing your
     * application.
     */
    T* operator->( void );

    /**
     * Just dereference the pointer to a reference of type T.
     */
    T& operator* ( void );

    /**
     * Assing one RemoteReference to another. The old ptr will be deregistered and the new
     * one registered.  It might happen that during registering the object is
     * currently beeing destructed, so the pointer assigned (and of course
     * assigned from later on too) will be NULL.
     */
    RemoteReference& operator=( RemoteReference& v);

    /**
     * Does the same as the above, but as an assignment from ordinary pointer,
     * e.g. one you got from new.
     */
    RemoteReference& operator=( T* _ptr);

    /**
     * Cast this pointer to a void* one. Usefull to display the virtual
     * address.
     */ 
    operator T * (void);

private:
   /**
    * Please do not call this function yourself, for the end user the
    * assignment of NULL is the proper way. This is only to be called by the
    * RemoteReferenceTracker class tracking this pointer.
    */
    virtual void reset( void ) const;
};/*}}}*/

template<class T>
inline RemoteReference<T>::operator T * ( void )/*{{{*/
{
    return ptr;
}/*}}}*/

template<class T>
inline void RemoteReference<T>::reset( void ) const /*{{{*/
{ 
//    cout << "Resetting Pointer from " << (void*) ptr << endl;
    /// No need to deregister here since this is to be called from the Tracker class only    
    ptr = NULL; 
}/*}}}*/

template<class T>
inline RemoteReference<T>& RemoteReference<T>::operator=( RemoteReference<T>& v) /*{{{*/
{ 
    if ( ptr )
    {
	ptr->deregister_sptr(this);
    }
    ptr = v.ptr; 
    if ( ptr )
    {
	try
	{
	    ptr->register_sptr(this);
	}
	catch(...)
	{
	    ptr = NULL;
	}
    }
    return *this; 
}/*}}}*/

template<class T>
inline RemoteReference<T>& RemoteReference<T>::operator=( T* _ptr) /*{{{*/
{ 
    if ( ptr )
    {
	ptr->deregister_sptr(this);
    }

    ptr = _ptr; 
    if ( ptr )
    {
	try
	{
	    ptr->register_sptr(this);
	}
	catch(...)
	{
	    /// In case of error while registering we do not point to the
	    /// object so we set us to 0 !!
	    ptr = NULL;
	}
    }
    return *this; 
}/*}}}*/

template<class T>
RemoteReference<T>::~RemoteReference()/*{{{*/
{
    if ( ptr )
    {
	ptr->deregister_sptr(this);
    }
}/*}}}*/

template<class T>
RemoteReference<T>::RemoteReference() : ptr(NULL) /*{{{*/
{ 
    T::read_comment_on_this_function_please();

    if (app_base_addr==NULL) 
	get_app_base_addr(); 
}/*}}}*/

template<class T>
RemoteReference<T>::RemoteReference(T* _ptr) : ptr(_ptr) /*{{{*/
{ 
    T::read_comment_on_this_function_please();

    if (app_base_addr==NULL) 
	get_app_base_addr(); 

    ptr->register_sptr(this);
}/*}}}*/

template<class T>
inline T& RemoteReference<T>::operator*( void )/*{{{*/
{
    return (*(operator->()));
}/*}}}*/

template<class T>
inline T* RemoteReference<T>::operator->( void ) /*{{{*/
{ 
/*
    cout << "Pointer points to " << (void*) ptr << endl;
    cout << "Base Address is " << (void*) app_base_addr << endl;
*/
    if ( ptr )
    {
	
	/// @todo Find a way to check the current segment boundaries in a fast way !!

	if( ptr > app_base_addr )
	{
	    return ptr; 
	}
	else
	{
	    throw invptr_error(
		string("Pointer to be dereferenced is pointing to invalid Memory (before main app) while attempting to dereference a ") 
		+ demangle_cpp_name(typeid(T).name()) + " *");
	}
    }
    else
    {
	throw nullptr_error(
		string("NULL Pointer dereference while attempting to dereference a ") 
		+ demangle_cpp_name(typeid(T).name()) + " *");
    }
}/*}}}*/

}
#endif
