/* 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_JACKGROUP_HPP
#define NMM_JACKGROUP_HPP

#include "nmm/nmm_prefix.hpp"

#include "QueuedOutputJack.hpp"

namespace NMM {

  class Node;

  /** A group of queued output jacks.
   * This class encapsulates a group of QueuedOutputJack objects. The group consists of a master jack
   * and zero or more clones of the master jack.
   * It is used for connecting an output stream of a node to multiple input streams and for
   * session sharing.
   *
   * A jack group sends downstream messages to all output jacks in the group.
   * Upstream messages are received from all output jacks in a round-robin fashion.
   */
  class JackGroup {
    
  private:
    size_t curr_dequeue_jack;   ///< Current jack in the group from which messages are received
    Node* parent;               ///< Parent node

   /** Information about a jack in the group.
    */
    class InternalJack_t {
    public:
      QueuedOutputJack* jack;   ///< The jack
      bool connected;           ///< Jack is connected
      bool switch_to;           ///< Helper flag used for output switching

      /** Default constructor.
       */
      InternalJack_t() : jack(0), connected(true), switch_to(false) {};

      /** Explicit constructor.
       *
       * @param _jack The jack
       * @param _connected Jack is connected
       * @param _switch_to Helper flag used for output switching
       */
      InternalJack_t(QueuedOutputJack* _jack, bool _connected, bool _switch_to)
        : jack(_jack), connected(_connected), switch_to(_switch_to) {};

      /** Destructor.
       */
      ~InternalJack_t() { };
    };

    /** Information about all jacks in a group.
     */
    typedef vector< InternalJack_t > InternalJacks_t;
    mutable InternalJacks_t jacks;    ///< Information about all jacks in the group

  public:

    /** Create a new jack group.
     * This constructor creates a new group around an existing master jack.
     *
     * @param parent_node The parent node
     * @param jack Master jack
     */
    JackGroup(Node* parent_node, QueuedOutputJack* jack);

    /** Destructor.
     * This destructor destroys all jacks in the group.
     */
    ~JackGroup();

    /** Send a message to this group.
     * This method seds a message to all jacks in this group by calling their sendMessage() method.
     * The reference count of the message is increased as many times as necessary.
     * No copies of messages are created.
     *
     * @param message The message to be sent
     * @return Number of jacks in the group whose partner queues are blocked after receiving the message
     */
    int sendMessage(Message* message) const;

    /** Check if there are new connections.
     * This method checks if an output jack that was not connected after the last call to this
     * method is connected now.
     *
     * @return @c true if a new connection was detected, @c false otherwise
     *
     * @deprecated Output switching is no longer used and deprecated
     */
    bool checkNewConnections();

    /** Add a jack to this group.
     * This method adds a jack to this group. The jack must not be connected.
     *
     * @param jack Jack to add
     * @return SUCCESS
     */
    Result addJack(const QueuedOutputJack* jack) const;

    /** Remove a jack from this group.
     *
     * @param jack Jack to be removed
     * @return SUCCESS if the jack was removed, FAILURE if the jack was not in the group
     */
    Result removeJack(const QueuedOutputJack* jack);

    /** Dequeue a message from this group.
     * This method fetches the next upstream message from a jack in this group.
     * Jacks in the group are serviced in a round-robin fashion.
     * The message is removed from the queue of the jack.
     *
     * @return The next upstream message
     */
    Message* dequeueMessage();

    /** Flush the queues of all jacks in this group.
     */
    Result flush();

    /** Get the master jack of this group.
     * This method returns the master jack of this group. The returned pointer must not be deleted.
     *
     * @return A pointre to master jack
     */
    inline QueuedOutputJack* getMaster() { return jacks[0].jack; }

    /** Check if this jack group is connected.
     * A jack group is connected if and only if at least one jack in the group is connected.
     *
     * @return @c true if this jack group is connected, @c false otherwise
     */
    bool isConnected();

    /** Send switch messages.
     * This method sends a message to all jacks in this group which were disconnected before the last
     * call to checkNewConnections() and are connected now. A second message is sent to all other
     * jacks in this group.
     *
     * @deprecated Output switching is no longer used and deprecated
     *
     * @param switch_to_msg Message to send to all jacks which were previously disconnected
     * @param switch_from_msg Message to send to all other jacks
     */
    int sendSwitchMessages(Message* switch_to_msg, Message* switch_from_msg);

    /** Reset output switching state.
     * This method resets the switching state of all jacks in this group.
     * the switching state is set by checkNewConnections().
     *
     * @param status Value to set the switching state to
     *
     * @deprecated Output switching is no longer used and deprecated
     */
    void resetSwitchTo(bool status = false);

  };
}

#include "nmm/nmm_suffix.hpp"

#endif // NMM_JACKGROUP_HPP
