/*****************************************************************************
 * $LastChangedDate: 2011-04-09 21:58:06 -0400 (Sat, 09 Apr 2011) $
 * @file
 * @author  Jim E. Brooks  http://www.palomino3d.org
 * @brief   Events.
 *//*
 * LEGAL:   COPYRIGHT (C) 2008 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE VERSION 2 (GPL 2).
 *****************************************************************************/

#ifndef OBJECT_EVENTS_HH
#define OBJECT_EVENTS_HH 1

#include "base/singleton.hh"
#include "base/event.hh"
using namespace base;

namespace object {

class Object;

////////////////////////////////////////////////////////////////////////////////
/// @brief 3D Object events.
///
/// CRITICAL: All modules holding a reference to an Object
/// should listen for the DestroyObject event and release their reference.
/// Else zombie objects will accumulate and waste memory (esp. from 3D files).
///
class Events
{
public:
                            DEFINE_GetInstance( Events )  // Singleton
#define EVENT_DESTROY_OBJECT (object::Events::GetInstance().GetDestroyObjectEvent())
    Event<shptr<Object> >&  GetDestroyObjectEvent( void ) { return mDestroyObjectEvent; }

private:
    CLASS_VAR Events*       msInstance;
    Event<shptr<Object> >   mDestroyObjectEvent;
};

#if OBJECT_OBJECT_CC
Events* Events::msInstance;
#endif

////////////////////////////////////////////////////////////////////////////////
/// @brief Any container of an Object must listen for destroying of an Object.
///
/// 3D models may consume large amounts of memory.
/// So releasing all references to an Object being destroyed is critical!
///
/// Object::Zombify() broadcasts this event (a counterpart is in Lua).
/// This convenience macro expands the functor class.
///
/// mDestroyObjectListener(new DestroyObjectListener(*this))
/// OBJECT_EVENTS.mDestroyObject.Listen( mDestroyObjectListener );
/// OBJECT_EVENTS.mDestroyObject.Unlisten( mDestroyObjectListener );
/// void Collision::DestroyObjectListener::operator()( shptr<Object> object )
/// {
///     mCollision.mCollidables.erase( object );
/// }
///
#define CLASS_DESTROY_OBJECT_LISTENER( OUTER_CLASS, M_OUTER_VAR )                   \
    class DestroyObjectListener : public Event<shptr<Object> >::ListenerFunctor     \
    {                                                                               \
    PREVENT_COPYING(DestroyObjectListener)                                          \
    public:                                                                         \
        DestroyObjectListener( OUTER_CLASS& outer ) : M_OUTER_VAR(outer) { }        \
        virtual void operator()( shptr<Object> object );                            \
    private:                                                                        \
        OUTER_CLASS& M_OUTER_VAR;                                                   \
    };                                                                              \
    friend class DestroyObjectListener;

} // namespace object

#endif // OBJECT_EVENTS_HH
