/* 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_JACK_HPP
#define NMM_JACK_HPP NMM_JACK_HPP

#include "nmm/nmm_prefix.hpp"

#include "nmm/comm/IJackImpl.hpp"
#include "nmm/comm/StdNamedObject.hpp"
#include "nmm/comm/InstreamObject.hpp"

#include "nmm/comm/messaging/ISignalReceiver.hpp"
#include "nmm/comm/messaging/IMessageReceiver.hpp"
#include "nmm/comm/messaging/IMessageSender.hpp"

#include "visibility.hpp"

namespace NMM {

  class Node;

  class InstreamCompositeStrategy;

  /** A jack for connecting a node to another node.
   * An input or output jack is an instance of an input or output stream of a node.
   * This class is the common base class of the InputJack and OutputJack class, which implements
   * common functionality and defines common attributes of input and output jacks.
   *
   * Every jack has a parent node and a jack tag, which is a free-form string which identifies
   * the jack. Jacks communicate with their partners through an IMessageReceiver and an ISignalReceiver
   * interface.
   *
   * For locally connected jacks, a jack has a direct reference to its partner jack.
   * If jacks are connected by a non-local binding, the partner jack is not available directly.
   *
   * InputJack and OutputJack are the only subclasses of this class.
   * New jack classes must be derived from one of these subclasses.
   */
  class DLLEXPORT Jack
    : public IMessageReceiver, 
      public IMessageSender,
      public ISignalReceiver,
      public InstreamObject,
      virtual public IJackImpl,
      public StdNamedObject
  {
  public:
    /** Create a new 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
     */
    Jack(Node* parent, const string& jack_tag = "default", const string& name = "Jack");

    /** Virtual destructor.
     */
    virtual ~Jack() {};

    /** Get the parent node of this jack.
     *
     * @return The parent node of this jack
     */
    virtual           Node* getParent();

    /** Get the parent node of this jack.
     *
     * @return The parent node of this jack
     */
    virtual     const Node* getParent() const;

    /** Get the local partner jack.
     * This method returns a pointer to the partner jack if the jack is connected locally.
     * If the jack is not connected, or it is not connected to a local partner jack,
     * then this method returns a null pointer.
     *
     * @return A pointer to the partner jack or 0
     */
    inline const Jack* getPartner()  const  {return __partner;}

    /** Get the local partner jack.
     * This method returns a pointer to the partner jack if the jack is connected locally.
     * If the jack is not connected, or it is not connected to a local partner jack,
     * then this method returns a null pointer.
     *
     * @return A pointer to the partner jack or 0
     */
    inline       Jack* getPartner()         {return __partner;}

    /** Get the jack tag of this jack.
     *
     * @return The jack tag of this jack
     */
    virtual  string getJackTag()       const {return __jack_tag;}

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

    /** Check if this jack is connected.
     *
     * @return @c true if this jack is connected, otherwise @c false
     */
    virtual nmm_bool isConnected() const = 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) = 0;

    /** 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) = 0;
    
  protected: //interface methods
    /** Get interface to parent node.
     * This method returns an interface to the parent node of this jack.
     * The caller is responsible for deleting the returned interface.
     *
     * @return An interface to the parent node
     */
    virtual INode* getIParent();

  protected:
    /** Set the local partner jack.
     * This method sets the local partner jack of this jack.
     *
     * @param partner A pointer to the partner jack
     */
    inline void  setPartner(Jack *partner)                                  const { __partner = partner; }

    /** Set the message receiver interface.
     * This method sets the message receiver interface to the partner of this jack.
     *
     * @param message_receiver Message receiver interface to the partner of this jack
     */
    inline void  setMessageReceiver(IMessageReceiver* message_receiver)           { __message_receiver = message_receiver; }

    /** Get the message receiver interface.
     * This method gets the message receiver interface to the partner of this jack.
     *
     * @return Message receiver interface to the partner of this jack
     */
    inline       IMessageReceiver* getMessageReceiver()                           { return __message_receiver; }

    /** Get the message receiver interface.
     * This method gets the message receiver interface to the partner of this jack.
     *
     * @return Message receiver interface to the partner of this jack
     */
    inline const IMessageReceiver* getMessageReceiver()                     const { return __message_receiver; }

    /** Get the signal receiver interface.
     * This method gets the signal receiver interface to the partner of this jack.
     *
     * @return Signal receiver interface to the partner of this jack
     */
    inline       ISignalReceiver*  getSignalReceiver()                            { return __signal_receiver; }

  private:
    Node*                   __parent;             ///< Parent node
    string                  __jack_tag;           ///< Jack tag
    mutable Jack*           __partner;            ///< Local partner jack
    IMessageReceiver*       __message_receiver;   ///< Message receiver interface of partner
    ISignalReceiver*        __signal_receiver;    ///< Signal receiver interface of partner
  };

}

#include "nmm/nmm_suffix.hpp"

#endif
