/*
 *  ZThreads, a platform-independant, multithreading and 
 *  synchroniation library
 *
 *  Copyright (C) 2000-2002 Eric Crahen, See LGPL.TXT for details
 *
 *  This library 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.1 of the License, or (at your option) any later version.
 *
 *  This library 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 library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 *  SUNY @ Buffalo, hereby disclaims all copyright interest in the
 *  ZThreads library written by Eric Crahen
 */

#ifndef __ZTOBSERVABLE_H__
#define __ZTOBSERVABLE_H__

#include "zthread/ZThread.h"
#include "zthread/Mutex.h"
#include "zthread/Guard.h"

#include <set>
#include <algorithm>


namespace ZThread {

/**
 * @class Observable
 *
 * @author Eric Crahen <crahen@cse.buffalo.edu>
 * @date <2002-02-24T09:27:34-0500>
 * @version 1.4.1
 *
 * This is a very useful template for creating objects that work using 
 * the Observer pattern. You can use this template for both weakly typed
 * listeners and strongly typed listeners. By weakly or strongly typed 
 * listeners, I mean listener objects that just implicitly define the 
 * needed notify methods (weak) to a listener derived from a virtual base 
 * that defines the needed notify methods (strong). Better explanation
 * is given with the examples below.
 *
 * The template creates the subject of the observer pattern to which listener
 * objects of type 'T' can subscribe to. The listener objects are notified 
 * of each event as the notify() methods of the Observable object are invoked
 *
 * The only requirement is that the listener object must implement the correct
 * notify methods. So if you are using a parameterless notify() method on the 
 * Observer - the you need only implement notify() on the listener class.
 * If you use a parameterized notify method, then you need implement the
 * correct type method.
 * 
 * This means if you are calling notify(int) on the observer, then the listener
 * class needs to implement the notify(int) method. These listener notify methods
 * should be public
 *
 * You need only to implement the notify function you use. This template includes
 * three types of notify() methods, but if you don't use them all the compiler
 * will ignore the unused portions of the template quietly.
 *
 * The nice thing about this template is that is very flexible.
 *
 * Consider a case where you have several type of log events, and you have an 
 * object that is interested in all of these event types - but will not 
 * necessarily take the take action for each. It might just be easier in general
 * to implement a class with the different notify functions on them directly
 * rather than creating several virtual base classes for each type and inheriting
 * from them all. Of you may want to define a single virtual base class that
 * implements all three of the needed notify() functions and maintain a strongly
 * type system. Its up to the programmer how to define his listener classes no
 * inheritance is forced here unless the programmer wishes to impose it, and no
 * one is forced to use implicitly defined notify() methods either.
 *
 * @code
 *
 *   Observer<ListenerType> O;
 *   ListenerType L;
 *
 *   O.subscribe(&L);
 *
 *   O.notify( int(9) ); // Basic example
 *   O.notify( "Hello" );
 * 
 *   // Or
 *
 *   O.notify( LogMessage("Its OK") ); // More useful example
 *   O.notify( LogCritical("Error!") );
 *
 * }
 *
 * @endcode
 *
 * The ListenerType can be implemented as (Assuming LogMessage & LogCritical
 * are valid classes)
 *
 * @code
 *
 * // Weakly typed listener
 * // just implements the notify methods that are implicitly defined 
 * // in the template
 * class ListenerType { 
 * public:
 *
 *   void notify(LogMessage);  // These are function signatures for 
 *   void notify(LogCritical); // simplicity sake
 *
 * };
 *
 *
 * // Strongly typed listener
 *
 * // The base just implements the notify methods that are implicitly defined 
 * // in the template, but forced some class to derive from this. The programmer
 * // will need to realize what functions the observer will need to call to 
 * // define the abstract base correctly.
 * class ListenerBaseType { 
 * public:
 *
 *   virtual ~ListenerBaseType() {}
 *
 *   virtual void notify(LogMessage) = 0;
 *   virtual void notify(LogCritical) = 0;
 *
 * };
 *
 * class ListenerImpl : public ListenerBaseType { 
 * public:
 *
 *   virtual void notify(LogMessage);
 *   virtual void notify(LogCritical);
 *
 * };
 *
 * @endcode
 */
template <class T, class LOCK = Mutex>
class ZTHREAD_API Observable {

  LOCK* _lock;
  const bool _ownLock;

  typedef std::set<T*> List;
  List _observers;

  public:

  /**
   * Create a new Observable object that owns its own Lockable object
   * (which is used to manipulate its data)
   */
  Observable();

  /**
   * Create a new Observable object that shares it Lockable object
   * (which is used to manipulate its data)
   *
   * @param LOCK* - lock owned by some other object
   */
  Observable(LOCK*);

  /**
   * Destroy this Observable
   */
  virtual ~Observable() throw();

  /**
   * Subscribe to an observer
   */
  virtual void subscribe(T*);

  /**
   * Unsubscribe from an observer
   */
  virtual void unsubscribe(T*);

  /** 
   * Distribute an event of type U to all subscribed 
   * objects, via their no-parameter notify function
   */
  inline void notify() const {

    _lock->acquire();
    List cp(_observers);  
    _lock->release();
  
    void(T::*pf)() = &T::notify;  
  
    // Distribute the event using the given function context
    for(List::const_iterator i = cp.begin(); i != cp.end(); ++i) {
    
      try {
        ((*i)->*pf)();
      } catch(...) {}
    
    }
    
  }


  /**
   * Distribute an event of type U to all subscribed 
   * objects, via their single parameter notify function
   */
  template<class U>
  inline void notify(const U& u) const {  

    _lock->acquire();
    List cp(_observers);  
    _lock->release();

    void(T::*pf)(const U&) = &T::notify;
 
    // Distribute the event using the given function context
    for(List::const_iterator i = cp.begin(); i != cp.end(); ++i) {

      try {
        ((*i)->*pf)(u);
      } catch(...) {}

    }

  }


  /**
   * Distribute an event of type U to all subscribed 
   * objects, via their double parameter notify function
   */
  template<class U, class V>
  inline void notify(const U* u, const V& v) const {

    _lock->acquire();
    List cp(_observers);  
    _lock->release();

    void(T::*pf)(const U*,const V&) = &T::notify;
   
    // Distribute the event using the given function context
    for(List::const_iterator i = cp.begin(); i != cp.end(); ++i) {

      try {
        ((*i)->*pf)(u, v);
      } catch(...) {}
    }

  }


};


template <class T, class LOCK>
Observable<T, LOCK>::Observable(LOCK *lock) 
 : _lock(lock), _ownLock(false) { }


template <class T, class LOCK>
Observable<T, LOCK>::Observable() 
 : _lock(new LOCK), _ownLock(true) { }


template <class T, class LOCK>
Observable<T, LOCK>::~Observable() throw() {

  if(_ownLock)
    delete _lock;

}

template <class T, class LOCK>
void Observable<T, LOCK>::subscribe(T* l) {

  ZThread::Guard<LOCK> g(*_lock);
  _observers.insert(l);

}

template <class T, class LOCK>
void Observable<T, LOCK>::unsubscribe(T* l) {

  ZThread::Guard<LOCK> g(*_lock);
  
  List::iterator i = std::find(_observers.begin(), _observers.end(), l);

  if(i != _observers.end())
    _observers.erase(i);
  
}

};

#endif
