/**
 *******************************************************************************
 * Copyright (C) 2001-2003, International Business Machines Corporation and    *
 * others. All Rights Reserved.                                                *
 *******************************************************************************
 */
#ifndef ICUNOTIF_H
#define ICUNOTIF_H

#include "unicode/utypes.h"

#if UCONFIG_NO_SERVICE

U_NAMESPACE_BEGIN

/*
 * Allow the declaration of APIs with pointers to BreakIterator
 * even when break iteration is removed from the build.
 */
class ICUNotifier;

U_NAMESPACE_END

#else

#include "unicode/uobject.h"
#include "unicode/unistr.h"

#include "mutex.h"
#include "uvector.h"

U_NAMESPACE_BEGIN

class U_COMMON_API EventListener : public UObject {
 public: 
  virtual ~EventListener() {}

 public:
    static inline UClassID getStaticClassID() { 
        return (UClassID)&fgClassID;
    }

    virtual UClassID getDynamicClassID() const {
        return getStaticClassID();
    }

 public:
    virtual UnicodeString& debug(UnicodeString& result) const {
      return debugClass(result);
    }

    virtual UnicodeString& debugClass(UnicodeString& result) const {
      return result.append("Key");
    }

 private:
    static const char fgClassID;
};

/**
 * <p>Abstract implementation of a notification facility.  Clients add
 * EventListeners with addListener and remove them with removeListener.
 * Notifiers call notifyChanged when they wish to notify listeners.
 * This queues the listener list on the notification thread, which
 * eventually dequeues the list and calls notifyListener on each
 * listener in the list.</p>
 *
 * <p>Subclasses override acceptsListener and notifyListener 
 * to add type-safe notification.  AcceptsListener should return
 * true if the listener is of the appropriate type; ICUNotifier
 * itself will ensure the listener is non-null and that the
 * identical listener is not already registered with the Notifier.
 * NotifyListener should cast the listener to the appropriate 
 * type and call the appropriate method on the listener.
 */

class U_COMMON_API ICUNotifier : public UMemory  {
 private: UMTX notifyLock;
 private: UVector* listeners;

 public: 
 ICUNotifier(void) 
   : notifyLock(0), listeners(NULL) 
   {
     umtx_init(&notifyLock);
   }

 virtual ~ICUNotifier(void) {
   {
     Mutex lmx(&notifyLock);
     delete listeners;
     listeners = NULL;
   }
   umtx_destroy(&notifyLock);
 }

 /**
  * Add a listener to be notified when notifyChanged is called.
  * The listener must not be null. AcceptsListener must return
  * true for the listener.  Attempts to concurrently
  * register the identical listener more than once will be
  * silently ignored.  
  */
 virtual void addListener(const EventListener* l, UErrorCode& status);

 /**
  * Stop notifying this listener.  The listener must
  * not be null.  Attemps to remove a listener that is
  * not registered will be silently ignored.
  */
 virtual void removeListener(const EventListener* l, UErrorCode& status);

 /**
  * ICU doesn't spawn its own threads.  All listeners are notified in
  * the thread of the caller.  Misbehaved listeners can therefore
  * indefinitely block the calling thread.  Callers should beware of
  * deadlock situations.  
  */
 virtual void notifyChanged(void);

 protected: 
 /**
  * Subclasses implement this to return TRUE if the listener is
  * of the appropriate type.
  */
 virtual UBool acceptsListener(const EventListener& l) const = 0;

 /**
  * Subclasses implement this to notify the listener.
  */
 virtual void notifyListener(EventListener& l) const = 0;
};

U_NAMESPACE_END

/* UCONFIG_NO_SERVICE */
#endif

/* ICUNOTIF_H */
#endif
