/* 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_INSTREAM_COMPOSITE_STRATEGY_HPP
#define NMM_INSTREAM_COMPOSITE_STRATEGY_HPP NMM_INSTREAM_COMPOSITE_STRATEGY_HPP

#include "nmm/nmm_prefix.hpp"

#include "CompositeStrategy.hpp"
#include "IInstreamCompositeStrategyImpl.hpp"

#include "nmm/comm/messaging/ICSMessageReceiver.hpp"
#include "nmm/comm/messaging/IMessageSender.hpp"
#include "nmm/comm/messaging/ISignalReceiver.hpp"
#include "nmm/comm/messaging/ISignalSender.hpp"

#include "visibility.hpp"

namespace NMM {
  
  class ICSSignalReceiver;
  
  /** A signal adapter for transport strategies.
   *
   * This is a helper class needed by InstreamCompositeStrategy.
   */
  class TSSignalAdapter : public ISignalReceiver {
  public:
    inline TSSignalAdapter() throw()
      : __receiver(0),
        __sender(0)
    {}
    
    /** Sets ICSSignalReceiver.
     *
     * @param receiver ICSSignalReceiver to set.
     */
    inline void setCSSignalReceiver(ICSSignalReceiver* receiver) throw() { __receiver = receiver; }
     
    /** Sets ISignalSender.
     *
     * @param sender ISignalSender to set.
     */
    inline void setSignalSender(ISignalSender* sender) throw() { __sender = sender; }
    
    /** Receives Singal.
     *
     * @param signal Signal to receive
     */
    virtual void receiveSignal(Signal signal);
    
  private:
    ICSSignalReceiver* __receiver; ///< signal receiver 
    ISignalSender*     __sender;   ///< signal sender
  };
  
  
  class ITSOneWayBufferReceiver;
  class ITSOneWayBufferSender;
  class ITSOneWayCEventReceiver;
  class ITSOneWayCEventSender;
  class Format;
  class InstreamMultiplexer;
  class InstreamDemultiplexer;
  
  /** A composite top-level %TransportStrategy for realizing instream bindings.
   *
   * This %TransportStrategy can be used as a top-level strategy for realizing an instream binding and is
   * realized using the composite design pattern.
   * @see InstreamCompositeAddress
   */
  class DLLEXPORT InstreamCompositeStrategy
    : public CompositeStrategy,
      public IInstreamCompositeStrategyImpl,
      public ICSMessageReceiver,
      public IMessageSender,
      public ISignalReceiver,
      public ISignalSender
  {
  public:
    /** @name Constructor & Destructor
     */
    //@{
    /** Constructs a %InstreamCompositeStrategy with default attributes.
     *
     * @param name name of InstreamCompositeStrategy
     */
    InstreamCompositeStrategy(const string& name = "InstreamCompositeStrategy");
    
    /** Virtual destructor.
     */
    virtual ~InstreamCompositeStrategy();
    //@}
    
    /** @name %TransportStrategy Information
     */
    //@{
    /** Returns the 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.
     *
     * @see CompositeStrategy::isConnected
     */
    virtual bool isBindingComplete() const throw();
    //@}
    
    /** @name Connection & Configuration
     */
    //@{
    /** Set address and connect 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 Buffers.
     *
     * @return child strategy for receiving one-way Buffers
     */
    virtual ITransportStrategy* getOneWayBufferReceiverStrategy() const;
    
    /** Returns child strategy for receiving one-way CEvents.
     *
     * @return child strategy for receiving one-way CEvents
     */
    virtual ITransportStrategy* getOneWayCEventReceiverStrategy() const;
    
    /** Returns child strategy for sending one-way Buffers.
     *
     * @return child strategy for sending one-way Buffers
     */
    ITransportStrategy* getOneWayBufferSenderStrategy() const;
    
    /** Returns child strategy for sending one-way CEvents.
     *
     * @return child strategy for sending one-way CEvents
     */
    virtual ITransportStrategy* getOneWayCEventSenderStrategy() const;

    /** Returns child strategy for receiving one-way Buffers.
     *
     * @return child strategy for receiving one-way Buffers
     */
    TransportStrategy* getOwnOneWayBufferReceiverStrategy() const;
    
    /** Returns child strategy for receiving one-way CEvents.
     *
     * @return child strategy for receiving one-way CEvents
     */
    TransportStrategy* getOwnOneWayCEventReceiverStrategy() const;
    
    /** Returns child strategy for sending one-way Buffers.
     *
     * @return child strategy for sending one-way Buffers
     */
    TransportStrategy* getOwnOneWayBufferSenderStrategy() const;
    
    /** Returns child strategy for sending one-way CEvents.
     *
     * @return child strategy for sending one-way CEvents
     */
    TransportStrategy* getOwnOneWayCEventSenderStrategy() const;
    
    /** Returns child strategy for receiving one-way Buffers.
     *
     * @return child strategy for receiving one-way Buffers
     */
    ITSOneWayBufferReceiver* getOneWayBufferReceiver() const;
    
    /** Returns child strategy for receiving one-way CEvents.
     *
     * @return child strategy for receiving one-way CEvents
     */
    ITSOneWayCEventReceiver* getOneWayCEventReceiver() const;
    
    /** Returns child strategy for sending one-way Buffers.
     *
     * @return child strategy for sending one-way Buffers
     */
    ITSOneWayBufferSender* getOneWayBufferSender() const;
    
    /** Returns child strategy for sending one-way CEvents.
     *
     * @return child strategy for sending one-way CEvents
     */
    ITSOneWayCEventSender* getOneWayCEventSender() const;
    
    /** Add 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.
     *
     * @param strategy child strategy to add
     * @param roles roles of child strategy 
     */
    virtual void addTransportStrategy(TransportStrategy* strategy, unsigned int roles);
    
    /** This method does nothing.
     */
    virtual void configure(const Format&) throw(const BindingException&) {}
    //@}
    
    /** @name Receiver Interface
     */
    //@{
    /** This method passes a message to a top-level %TransportStrategy and returns the queue status.
     *
     * @param message The message
     * @return The queue status of the %TransportStrategy
     */
    virtual Result receiveCSMessage(Message* message);
    
    /** Receives a signal.
     *
     * @param signal Signal to receive
     */
    virtual void receiveSignal(Signal signal);
    //@}
    
    /** @name Debugging and Benchmarking
     */
    //@{
    /** Sets message multiplexing strategy.  
     * 
     * This method sets the strategy for multiplexing messages from sub-bindings. 
     * Normally, the strategy is chosen automatically after the composite
     * strategy has been configured. This method should only be used
     * for debuggung and benchmark purposes.
     *
     * @param strategy Multiplexing strategy
     */
    virtual void setInstreamMuxStrategy(const IInstreamCompositeStrategy::MuxDemuxStrategy& strategy);
    
    /** Sets message demultiplexing strategy.  
     * This method sets the strategy for demultiplexing messages from
     * sub-bindings. Normally, the strategy is chosen automatically
     * after the composite strategy has been configured. This method
     * should only be used for debuggung and benchmark purposes.
     *
     * @param strategy Demultiplexing strategy
     */
    virtual void setInstreamDemuxStrategy(const IInstreamCompositeStrategy::MuxDemuxStrategy& strategy);
    
    /** Sets interval for data loss simulation.  
     * 
     * This method sets the interval for simulating data loss. 
     * If the interval is not 0, it specifies the interval of buffers that should be dropped to
     * simulate an unreliable buffer sub-binding. Only use this method
     * for debugging and benchmark purposes.
     *
     * @param loss_interval interval for data loss simulation
     */
    virtual void setBufferLossInterval(const nmm_uint32& loss_interval);
    //@}
    
  protected:
    /** Sets one-way %Buffer sender strategy.
     *
     * @param strategy one-way %Buffer sender strategy 
     */
    void setOneWayBufferSenderStrategy(TransportStrategy* strategy)
      throw(const BindingException&);
    
    /** Sets one-way %CEvent sender strategy.
     *
     * @param strategy one-way %CEvent sender strategy
     */
    void setOneWayCEventSenderStrategy(TransportStrategy* strategy)
      throw(const BindingException&);
    
    /** Sets one-way %Buffer receiver strategy.
     *
     * @param strategy one-way %Buffer receiver strategy
     */
    void setOneWayBufferReceiverStrategy(TransportStrategy* strategy)
      throw(const BindingException&);
    
    /** Sets one-way %CEvent receiver strategy.
     *
     * @param strategy one-way %CEvent receiver strategy
     */
    void setOneWayCEventReceiverStrategy(TransportStrategy* strategy)
      throw(const BindingException&);
    
    /** Sets the instream multiplexer.
     *
     * @param message_mux instream multiplexer
     */
    void setInstreamMultiplexer(InstreamMultiplexer* message_mux);
    
    /** Sets the instream demultiplexer.
     *
     * @param message_demux instream demultiplexer
     */
    void setInstreamDemultiplexer(InstreamDemultiplexer* message_demux);
    
    /** Event acknowledgement.  
     *
     * This event is sent reliably to the
     * partner strategy that sent an instream event. It is used for
     * synchronization of a reliable event sub-binding and an
     * unreliable buffer sub-binding which doesn't preserve message
     * headers.
     *
     * @param stream_counter Sequence number of the event
     */
    virtual void notifyEventReceived(const nmm_int32& stream_counter);
    
    /** Reconfigures the composite strategy based on the new sub-bindings.
     *
     * This method is called automatically after a sub-binding was
     * added or removed.  It reconfigures the composite strategy based
     * on the new sub-bindings.
     */
    void reconfigure();
    
  private:
    /* BEGIN> Child strategy interfaces */
    ITSOneWayBufferSender*   __one_way_buffer_sender;    ///< One-way %Buffer sender interface
    ITSOneWayBufferReceiver* __one_way_buffer_receiver;  ///< One-way %Buffer receiver interface
    ITSOneWayCEventSender*   __one_way_cevent_sender;    ///< One-way %CEvent sender interface
    ITSOneWayCEventReceiver* __one_way_cevent_receiver;  ///< One-way %CEvent receiver interface
    /* END< */
    
    /* BEGIN> Message multiplexing/demultiplexing */
    InstreamMultiplexer*     __message_mux;              ///< Message multiplexer
    InstreamDemultiplexer*   __message_demux;            ///< Message demultiplexer
    TSSignalAdapter          __buffer_adapter;           ///< Signal adapter for %Buffer child strategy
    TSSignalAdapter          __cevent_adapter;           ///< Signal adapter for %CEvent child strategy
    /* END< */
  };
  
};

#include "nmm/nmm_suffix.hpp"

#endif
