/*=============================================================================

  Library: CppMicroServices

  Copyright (c) German Cancer Research Center,
    Division of Medical and Biological Informatics

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

=============================================================================*/

#ifndef USSERVICELISTENERHOOK_H
#define USSERVICELISTENERHOOK_H

#include "usServiceInterface.h"
#include "usShrinkableVector.h"
#include "usSharedData.h"

#include <string>

US_BEGIN_NAMESPACE

class ModuleContext;
class ServiceListenerEntry;

/**
 * @ingroup MicroServices
 *
 * Service Listener Hook Service.
 *
 * <p>
 * Modules registering this service will be called during service listener
 * addition and removal.
 *
 * @remarks Implementations of this interface are required to be thread-safe.
 */
struct US_Core_EXPORT ServiceListenerHook
{

  class ListenerInfoData;

  /**
   * Information about a Service Listener. This class describes the module
   * which added the Service Listener and the filter with which it was added.
   *
   * @remark This class is not intended to be implemented by clients.
   */
  struct US_Core_EXPORT ListenerInfo
  {
    ListenerInfo();

    ListenerInfo(const ListenerInfo& other);

    ~ListenerInfo();

    ListenerInfo& operator=(const ListenerInfo& other);

    /**
     * Can be used to check if this ListenerInfo instance is valid,
     * or if it has been constructed using the default constructor.
     *
     * @return <code>true</code> if this listener object is valid,
     *         <code>false</code> otherwise.
     */
    bool IsNull() const;

    /**
     * Return the context of the module which added the listener.
     *
     * @return The context of the module which added the listener.
     */
    ModuleContext* GetModuleContext() const;

    /**
     * Return the filter string with which the listener was added.
     *
     * @return The filter string with which the listener was added. This may
     *         be empty if the listener was added without a filter.
     */
    std::string GetFilter() const;

    /**
     * Return the state of the listener for this addition and removal life
     * cycle. Initially this method will return \c false indicating the
     * listener has been added but has not been removed. After the listener
     * has been removed, this method must always returns \c true.
     *
     * <p>
     * There is an extremely rare case in which removed notification to
     * {@link ServiceListenerHook}s can be made before added notification if two
     * threads are racing to add and remove the same service listener.
     * Because {@link ServiceListenerHook}s are called synchronously during service
     * listener addition and removal, the CppMicroServices library cannot guarantee
     * in-order delivery of added and removed notification for a given
     * service listener. This method can be used to detect this rare
     * occurrence.
     *
     * @return \c false if the listener has not been been removed,
     *         \c true otherwise.
     */
    bool IsRemoved() const;

    /**
     * Compares this \c ListenerInfo to another \c ListenerInfo.
     * Two {@code ListenerInfo}s are equal if they refer to the same
     * listener for a given addition and removal life cycle. If the same
     * listener is added again, it will have a different
     * \c ListenerInfo which is not equal to this \c ListenerInfo.
     *
     * @param other The object to compare against this \c ListenerInfo.
     * @return \c true if the other object is a \c ListenerInfo
     *         object and both objects refer to the same listener for a
     *         given addition and removal life cycle.
     */
    bool operator==(const ListenerInfo& other) const;

  private:

    friend class ServiceListenerEntry;

    US_HASH_FUNCTION_FRIEND(ServiceListenerHook::ListenerInfo);

    ListenerInfo(ListenerInfoData* data);

    ExplicitlySharedDataPointer<ListenerInfoData> d;
  };

  virtual ~ServiceListenerHook();

  /**
   * Added listeners hook method. This method is called to provide the hook
   * implementation with information on newly added service listeners. This
   * method will be called as service listeners are added while this hook is
   * registered. Also, immediately after registration of this hook, this
   * method will be called to provide the current collection of service
   * listeners which had been added prior to the hook being registered.
   *
   * @param listeners A collection of \c ListenerInfo objects for newly added
   *        service listeners which are now listening to service events.
   */
  virtual void Added(const std::vector<ListenerInfo>& listeners) = 0;

  /**
   * Removed listeners hook method. This method is called to provide the hook
   * implementation with information on newly removed service listeners. This
   * method will be called as service listeners are removed while this hook is
   * registered.
   *
   * @param listeners A collection of \c ListenerInfo objects for newly removed
   *        service listeners which are no longer listening to service events.
   */
  virtual void Removed(const std::vector<ListenerInfo>& listeners) = 0;

};

US_END_NAMESPACE

US_HASH_FUNCTION_NAMESPACE_BEGIN
US_HASH_FUNCTION_BEGIN(US_PREPEND_NAMESPACE(ServiceListenerHook::ListenerInfo))
  return US_HASH_FUNCTION(const US_PREPEND_NAMESPACE(ServiceListenerHook::ListenerInfoData)*, arg.d.Data());
US_HASH_FUNCTION_END
US_HASH_FUNCTION_NAMESPACE_END

#endif // USSERVICELISTENERHOOK_H
