/* Network-Integrated Multimedia Middleware (NMM)
 * http://www.motama.com/nmm.html
 * 
 * Copyright (C) 2006-2007
 * Motama GmbH, Saarbruecken, Germany
 * http://www.motama.com
 *  
 * This file is part of NMM. 
 * 
 * NMM 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; only version 2 of the License.      
 * 
 * NMM 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 NMM; if not, write to the Free Software Foundation,    
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */

#ifndef NMM_OUT_OF_BAND_COMPOSITE_STRATEGY_HPP
#define NMM_OUT_OF_BAND_COMPOSITE_STRATEGY_HPP NMM_OUT_OF_BAND_COMPOSITE_STRATEGY_HPP

#include "nmm/nmm_prefix.hpp"

#include "CompositeStrategy.hpp"
#include "IOutOfBandCompositeStrategyImpl.hpp"
#include "nmm/comm/messaging/ICSEventReceiver.hpp"
#include "nmm/comm/messaging/ITSRequestReplyEventReceiver.hpp"

#include "visibility.hpp"

namespace NMM {
  
  class ITSOneWayEventSender;
  class ITSOneWayEventReceiver;
  class ITSRequestReplyEventSender;
  class ITSRequestReplyEventReceiver;
  
  /** A composite top-level %TransportStrategy for realizing
   * out-of-band bindings.  This %TransportStrategy can be used as a
   * top-level strategy for realizing an out-of-band binding. It
   * combines multiple leaf transport strategies using the composite
   * design pattern.
   *
   * This strategy uses either request-reply leaf strategies or
   * one-way leaf strategies to realize request-reply interaction in
   * both cases.
   *
   * @see OutOfBandCompositeAddress InstreamCompositeStrategy
   */
  class DLLEXPORT OutOfBandCompositeStrategy
    : public CompositeStrategy,
      public IOutOfBandCompositeStrategyImpl,
      public ICSEventReceiver,
      public ITSRequestReplyEventReceiver
  {
  public:
    /** @name Constructor & Destructor
     */
    //@{
    /** Constructs a %OutOfBandCompositeStrategy with default attributes.
     *
     * @param name name of NamedObject
     */
    OutOfBandCompositeStrategy(const string& name = "OutOfBandCompositeStrategy");
    
    /** Virtual destructor.
     */
    virtual ~OutOfBandCompositeStrategy();
    //@}
    
    /** @name %TransportStrategy Information
     */
    //@{
    /** Returns the typename of this %TransportStrategy.
     *
     * @return typename of this %TransportStrategy
     */
    virtual string getStrategyType() const;
    
    /** This method checks if the binding is complete.
     *
     * A binding is complete if to each communication role a transport
     * strategy is assigned. The transport strategy need not be connected.
     * Each subclass must implement this method to define when a binding is
     * complete.
     *
     * @return true if binding is complete, false otherwise
     *
     * @see CompositeStrategy::isConnected
     */
    virtual bool isBindingComplete() const throw();
    //@}
    
    /** @name Connection & Configuration
     */
    //@{
    /** Sets address and connects to peer.
     *
     * This method connects this %TransportStrategy with its peer. The given peer @c address must be of a type
     * which is supported by the type of this %TransportStrategy. 
     *
     * @param address Address of peer to connect to
     */
    virtual void setAddress(const TSAddress& address)
      throw (const BindingException&);
    
    /** Returns child strategy for receiving one-way %Event requests.
     *
     * If this method returns 0, then the binding is realized by a request-reply
     * leaf strategy, which is returned by getRequestReplyEventReceiverStrategy().
     *
     * @return child strategy for receiving one-way %Event requests
     */
    virtual ITransportStrategy* getOneWayEventRequestReceiverStrategy() const;
    
    /** Returns child strategy for receiving one-way %Event replies.
     *
     * If this method returns 0, then the binding is realized by a request-reply
     * leaf strategy, which is returned by getRequestReplyEventSenderStrategy().
     *
     * @return child strategy for receiving one-way %Event replies.
     */
    virtual ITransportStrategy* getOneWayEventReplyReceiverStrategy() const;
    
    /** Returns child strategy for sending one-way %Event requests.
     *
     * If this method returns 0, then the binding is realized by a request-reply
     * leaf strategy, which is returned by getRequestReplyEventReceiverStrategy().
     *
     * @return child strategy for sending one-way %Event requests.
     */
    virtual ITransportStrategy* getOneWayEventRequestSenderStrategy() const;
    
    /** Returns child strategy for sending one-way %Event replies.
     *
     * If this method returns 0, then the binding is realized by a request-reply
     * leaf strategy, which is returned by getRequestReplyEventSenderStrategy().
     *
     * @return child strategy for sending one-way %Event replies
     */
    virtual ITransportStrategy* getOneWayEventReplySenderStrategy() const;
    
    /** Returns child strategy for receiving request-reply Events.
     *
     * If this method returns 0, then the binding is realized by two one-way
     * leaf strategies, which are returned by getOneWayEventRequestReceiverStrategy()
     * and getOneWayEventReplySenderStrategy().
     *
     * @return child strategy for receiving request-reply Events
     */
    virtual ITransportStrategy* getRequestReplyEventReceiverStrategy() const;
    
    /** Returns child strategy for sending request-reply Events.
     *
     * If this method returns 0, then the binding is realized by two one-way
     * leaf strategies, which are returned by getOneWayEventRequestSenderStrategy()
     * and getOneWayEventReplyReceiverStrategy().
     *
     * @return child strategy for sending request-reply Events
     */
    virtual ITransportStrategy* getRequestReplyEventSenderStrategy() const;
    
    /** Returns child strategy for receiving one-way %Event requests.
     *
     * If this method returns 0, then the binding is realized by a request-reply
     * leaf strategy, which is returned by getOwnRequestReplyEventReceiverStrategy().
     *
     * @return child strategy for receiving one-way %Event requests
     */
    TransportStrategy* getOwnOneWayEventRequestReceiverStrategy() const;
    
    /** Returns child strategy for receiving one-way %Event replies.
     *
     * If this method returns 0, then the binding is realized by a request-reply
     * leaf strategy, which is returned by getOwnRequestReplyEventSenderStrategy().
     *
     * @return child strategy for receiving one-way %Event replies
     */
    TransportStrategy* getOwnOneWayEventReplyReceiverStrategy() const;
    
    /** Returns child strategy for sending one-way %Event requests.
     *
     * If this method returns 0, then the binding is realized by a request-reply
     * leaf strategy, which is returned by getOwnRequestReplyEventReceiverStrategy().
     *
     * @return child strategy for sending one-way %Event requests
     */
    TransportStrategy* getOwnOneWayEventRequestSenderStrategy() const;
    
    /** Returns child strategy for sending one-way %Event replies.
     *
     * If this method returns 0, then the binding is realized by a request-reply
     * leaf strategy, which is returned by getOwnRequestReplyEventSenderStrategy().
     *
     * @return child strategy for sending one-way %Event replies
     */
    TransportStrategy* getOwnOneWayEventReplySenderStrategy() const;
    
    /** Returns child strategy for receiving request-reply Events.
     *
     * If this method returns 0, then the binding is realized by two one-way
     * leaf strategies, which are returned by getOwnOneWayEventRequestReceiverStrategy()
     * and getOwnOneWayEventReplySenderStrategy().
     *
     * @return child strategy for receiving request-reply Events
     */
    TransportStrategy* getOwnRequestReplyEventReceiverStrategy() const;
    
    /** Returns child strategy for sending request-reply Events.
     *
     * If this method returns 0, then the binding is realized by two one-way
     * leaf strategies, which are returned by getOwnOneWayEventRequestSenderStrategy()
     * and getOwnOneWayEventReplyReceiverStrategy().
     *
     * @return child strategy for sending request-reply Events
     */
    TransportStrategy* getOwnRequestReplyEventSenderStrategy() const;
    
    /** Returns child strategy for sending %Event requests.
     *
     * If the result is 0, then a request-reply capable child strategy
     * is used in this direction, which is returned by
     * getRequestReplyEventSender.
     *
     * @return child strategy for sending %Event requests
     */
    ITSOneWayEventSender* getOneWayEventRequestSender() const;
    
    /** Returns child strategy for receiving %Event replies.
     *
     * If the result is 0, then a request-reply capable child strategy
     * is used in this direction, which is returned by
     * getRequestReplyEventSender.
     *
     * @return child strategy for receiving %Event replies
     */
    ITSOneWayEventReceiver* getOneWayEventReplyReceiver() const;

    /** Returns child strategy for sending %Event requests.
     *
     * If the result is 0, then a request-reply capable child strategy
     * is used in this direction, which is returned by
     * getRequestReplyEventReceiver.
     *
     * @return child strategy for sending %Event requests
     */
    ITSOneWayEventReceiver* getOneWayEventRequestReceiver() const;
    
    /** Returns child strategy for receiving %Event replies.
     *
     * If the result is 0, then a request-reply capable child strategy
     * is used in this direction, which is returned by
     * getRequestReplyEventReceiver.
     *
     * @return child strategy for receiving %Event replies
     */
    ITSOneWayEventSender* getOneWayEventReplySender() const;
    
    /** Returns child strategy for sending request-reply Events.
     *
     * If the result is 0, then two one-way child strategies are used
     * in this direction for sending requests and receiving replies,
     * which are returned by getOneWayEventRequestSender and
     * getOneWayEventReplyReceiver.
     *
     * @return child strategy for sending request-reply Events
     */
    ITSRequestReplyEventSender* getRequestReplyEventSender() const;

    /** Returns child strategy for receiving request-reply Events.
     *
     * If the result is 0, then two one-way child strategies are used
     * in this direction for receiving requests and sending replies,
     * which are returned by getOneWayEventRequestReceiver and
     * getOneWayEventReplySender.
     *
     * @return child strategy for receiving request-reply Events
     */
    ITSRequestReplyEventReceiver* getRequestReplyEventReceiver() const;
    
    /** Sets child strategy for receiving one-way event requests.
     *
     * This method should not be called directly by normal applications.
     * Use setAddress instead.
     *
     * @param strategy TransportStrategy to set
     */
    void setOneWayEventRequestReceiverStrategy(TransportStrategy* strategy)
      throw(const BindingException&);
    
    /** Sets child strategy for sending one-way event requests.
     *
     * This method is called internally by setAddress and should not
     * be called directly by normal applications.  It is public for
     * testing purposes only. Applications should call setAddress
     * instead.
     *
     * @param strategy TransportStrategy to set
     */    
    void setOneWayEventRequestSenderStrategy(TransportStrategy* strategy)
      throw(const BindingException&);
    
    /** Sets child strategy for receiving one-way event replies.
     *
     * This method is called internally by setAddress and should not
     * be called directly by normal applications.  It is public for
     * testing purposes only. Applications should call setAddress
     * instead.
     *
     * @param strategy TransportStrategy to set
     */
    void setOneWayEventReplyReceiverStrategy(TransportStrategy* strategy)
      throw(const BindingException&);
    
    /** Sets child strategy for sending one-way event replies.
     *
     * This method is called internally by setAddress and should not
     * be called directly by normal applications.  It is public for
     * testing purposes only. Applications should call setAddress
     * instead.
     *
     * @param strategy TransportStrategy to set
     */
    void setOneWayEventReplySenderStrategy(TransportStrategy* strategy)
      throw(const BindingException&);
    
    /** Sets child strategy for receiving request-reply events.
     *
     * This method is called internally by setAddress and should not
     * be called directly by normal applications.  It is public for
     * testing purposes only. Applications should call setAddress
     * instead.
     *
     * @param strategy TransportStrategy to set
     */
    void setRequestReplyEventReceiverStrategy(TransportStrategy* strategy)
      throw(const BindingException&);
    
    /** Sets child strategy for receiving request-reply events.
     *
     * This method is called internally by setAddress and should not
     * be called directly by normal applications.  It is public for
     * testing purposes only. Applications should call setAddress
     * instead.
     *
     * @param strategy TransportStrategy to set
     */
    void setRequestReplyEventSenderStrategy(TransportStrategy* strategy)
      throw(const BindingException&);
    
    /** Adds a child strategy with the given roles.
     *
     * This method is called by the acceptor to connect a child
     * strategy to the composite strategy. It should not be used
     * directly in applications.
     *
     * @param strategy Transport strategy to add
     * @param roles Transport roles
     */
    virtual void addTransportStrategy(TransportStrategy* strategy, unsigned int roles)
      throw(const BindingException&);
    
    /** Sends reliable event.
     *
     * This implementation sends the reliable event as an ordinary out-of-band event.
     *
     * @param event Event to be sent
     * @return SUCCESS if sending was successful, FAILURE otherwise
     */
    virtual Result sendReliableEvent(Event& event) const;
    
    /** Send reliable config event.
     *
     * @param event config event to be sent
     * @return SUCCESS if sending was successful, FAILURE otherwise
     */
    virtual Result sendReliableConfigEvent(Event& event) const;
    //@}
    
    /** @name Receiver Interface
     */
    //@{
    /** This method passes an event to a top-level %TransportStrategy and returns the event result.
     *
     * @param event The event
     * @return The result of the event
     */
    virtual Result receiveCSEvent(Event& event);
    
    /** Receives %Event request and waits for reply.
     *
     * This method passes an %Event to the %TransportStrategy and returns the reply.
     *
     * @param event The event to be passed to the %TransportStrategy. Also returns the reply.
     * @return result of event
     */
    virtual Result receiveRequestReplyEvent(Event& event);
    //@}
    
  private:
    ITSOneWayEventReceiver*  __one_way_event_request_receiver;  ///< Strategy for receiving one-way event requests.
    ITSOneWayEventReceiver*  __one_way_event_reply_receiver;    ///< Strategy for receiving one-way event replies.
    ITSOneWayEventSender*    __one_way_event_request_sender;    ///< Strategy for sending   one-way event requests.
    ITSOneWayEventSender*    __one_way_event_reply_sender;      ///< Strategy for sending   one-way event replies.
    ITSRequestReplyEventReceiver* __request_reply_event_receiver;    ///< Strategy for receiving request-reply events.
    ITSRequestReplyEventSender*   __request_reply_event_sender;      ///< Strategy for sending   request-reply events.
  };
  
};

#include "nmm/nmm_suffix.hpp"

#endif
