/* 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_QUEUED_OUTPUT_JACK_HPP
#define NMM_QUEUED_OUTPUT_JACK_HPP NMM_QUEUED_OUTPUT_JACK_HPP

#include "nmm/nmm_prefix.hpp"

#include "OutputJack.hpp"
#include "nmm/comm/messaging/StreamQueue.hpp"

#include "visibility.hpp"

namespace NMM {

  class Message;
  class InputJack;

  /** An output jack with a queue.
   * This class is the standard implementation of an output jack. It uses a StreamQueue for queueing incoming
   * upstream messages. NMM signals are used for communication with the parent node and with the partner jack
   * or the transport strategy. The jack notifies the node when there are messages in the queue by sending an
   * UPSTR_QUEUE_NOT_EMPTY signal, and it notifies the partner jack or the transport strategy by sending a
   * FREE_QUEUE_SLOT signal.
   */
  class DLLEXPORT QueuedOutputJack : public OutputJack {

  public:

    /** Create a new queued input jack.
     *
     * @param parent The parent node of the jack
     * @param jack_tag The name of the jack
     * @param name The class name of the jack
     * @param mode The queue mode of the StreamQueue
     * @param size The maximum size of the StreamQueue
     */
    QueuedOutputJack(Node* parent,
                     const string& jack_tag = "default",
                     const string& name = "QueuedOutputJack",
                     const StreamQueue::Mode mode = StreamQueue::DEFAULT_MODE,
                     const unsigned int size = StreamQueue::DEFAULT_SIZE);

    /** Virtual destructor.
     */
    virtual ~QueuedOutputJack();

    /** Connect this jack to a local partner jack.
     * This method connects this jack to a local partner jack.
     * If the connection fails, a BindingException is thrown.
     *
     * @param jack Partner jack to connect with this jack
     */
    virtual void connectTo(const InputJack* jack) const
      throw(const BindingException& );

    /** Receive a message.
     * This method handles incoming messages received from the partner jack or the transport strategy.
     * The incoming message is placed in the queue.
     *
     * The result of this method is the queue state of this jack. If this jack can
     * accept more messages after receiving the message, the queue state is @c SUCCESS. Otherwise,
     * the queue state is @c BLOCKED until this jack sends a @c FREE_QUEUE_SLOT or
     * @c UPSTR_FREE_QUEUE_SLOT signal, depending on the direction of the message (@c DOWNSTREAM or
     * @c UPSTREAM, respectively).
     *
     * @param message The message
     * @param sender The sender of the message
     * @return The queue state after inserting the message into the queue
     */
    virtual Result receiveMessage(Message* message, const IMessageSender* sender = 0);

    /** Send a message to the partner jack of this jack.
     * This method forwards the given message to the partner jack of this jack.
     * How this is done depends on the type of binding between this jack and the partner jack
     * as well as the jack class.
     * If this jack is not connected, then this method fails.
     *
     * The result of this method is the queue state of the partner jack. If the partner jack can
     * accept more messages after receiving the message, the queue state is @c SUCCESS. Otherwise,
     * the queue state is @c BLOCKED until the partner jack sends a @c FREE_QUEUE_SLOT or
     * @c UPSTR_FREE_QUEUE_SLOT signal, depending on the direction of the message (@c DOWNSTREAM or
     * @c UPSTREAM, respectively).
     *
     * @param message The message to forward to the partner jack
     * @return The queue state of the partner jack or @c FAILURE if this method failed
     */
    virtual Result sendMessage(Message *message);

    /** Dequeue a message from this jack.
     * This method fetches the next message from the StreamQueue of this jack and returns it.
     *
     * @return The next message
     */
    inline Message* dequeueMessage() { return stream_queue->dequeueMessage(); }

    /** Get the current size of the queue.
     *
     * @return The current size of the queue.
     */
    inline unsigned int getQueueSize() { return stream_queue->getSize(); }

    /** Flush the queue.
     *
     * @return SUCCESS
     */
    Result flush();

    /** @name Methods for accessing the StreamQueue
     */
    //@{
    /** Get the current size of the queue.
     * This method returns the number of buffers currently queued.
     *
     * @return Current size of the queue (in number of buffers)
     */
    unsigned int getSize() const;

    /** Get the maximum size of the queue.
     * This method returns the maximum number of buffers that may be queued.
     *
     * @return Maximum size of the queue (in number of buffers)
     */
    unsigned int getMaxSize() const;

    /** Set the maximum size of the queue.
     * This method sets the maximum number of buffers that may be queued.
     *
     * @param size Maximum size of the queue (in number of buffers)
     */
    Result setMaxSize(unsigned int size);

    /** Get the mode of the queue.
     * This method returns the queue mode.
     *
     * @return Queue mode
     */
    StreamQueue::Mode getMode() const;

    /** Set the mode of the queue.
     * This method sets the queue mode.
     *
     * @param mode Queue mode
     */
    Result setMode(StreamQueue::Mode mode);
    //@}

    /** Handle a signal.
     * This implementation forwards the signal to the signal receiver of this jack.
     *
     * @param sig A signal
     */
    virtual void receiveSignal(Signal sig);

  protected:
    /** Set the transport strategy used by this jack.
     * This method sets the transport strategy which is used by the jack to communicate with its
     * partner jack. If this method succeeded, the jack is connected to a partner jack through
     * a non-local binding using the given tarnsport strategy.
     *
     * @param strategy The transport strategy used by this jack
     */
    virtual  void setTransportStrategy(InstreamCompositeStrategy* strategy)
      throw(const BindingException&);

    /** Disconnect this jack from its partner jack.
     */
    virtual void disconnect();

  protected:

    StreamQueue *stream_queue;    ///< The input stream_queue for this stream.

  };

}

#include "nmm/nmm_suffix.hpp"

#endif
