/* 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_NODE_HPP
#define NMM_NODE_HPP NMM_NODE_HPP

#include "nmm/nmm_prefix.hpp"

#include "nmm/multimedia/INodeImpl.hpp"
#include "nmm/comm/StdNamedObject.hpp"

#include "ReferenceCount.hpp"

#include "visibility.hpp"

namespace NMM {

  /** A node in an NMM flow graph.
   * This is the abstract base class of all node classes in NMM. It implements the interface of a node
   * for both the application and plug-ins (subclasses of the generic node classes)
   * as well as basic functionality for format specification.
   */
  class DLLEXPORT Node
    : public INodeImpl,
      public StdNamedObject,
      public ReferenceCount
  {
    friend class ThreadedNode;
    
  private:
    ThreadMutex internal_mutex;                     ///< Mutex for internal synchronization
    mutable Property* input_property;               ///< Input property
    mutable Property* output_property;              ///< Output property
    mutable Property* working_input_property;       ///< Working input property
    mutable Property* working_output_property;      ///< Working output property
    INode::Type node_type;                          ///< Node type

    ComputationConfig* computation_config;          ///< Computation configuration
    ComputationConfig* working_computation_config;  ///< Working computation configuration

  private:
    /** Internal method for requesting the input property of this node.
     * This method allocates the input property of this node, if necessary, and returns a pointer to it.
     * The caller must not delete the returned Property object. The object is destroyed when this node
     * is destroyed.
     *
     * @return A pointer to the input property of this node
     */
    Property* getInternalInputProperty()          const;

    /** Internal method for requesting the output property of this node.
     * This method allocates the output property of this node, if necessary, and returns a pointer to it.
     * The caller must not delete the returned Property object. The object is destroyed when this node
     * is destroyed.
     *
     * @return A pointer to the output property of this node
     */
    Property* getInternalOutputProperty()         const;

    /** Internal method for requesting the working input property of this node.
     * This method allocates the working input property of this node, if necessary, and returns a pointer to it.
     * The caller must not delete the returned Property object. The object is destroyed when this node
     * is destroyed.
     *
     * @return A pointer to the working input property of this node
     */
    Property* getInternalWorkingInputProperty()   const;

    /** Internal method for requesting the working output property of this node.
     * This method allocates the working output property of this node, if necessary, and returns a pointer to it.
     * The caller must not delete the returned Property object. The object is destroyed when this node
     * is destroyed.
     *
     * @return A pointer to the working output property of this node
     */
    Property* getInternalWorkingOutputProperty()  const;

  protected:
    ThreadMutex state_mutex;                        ///< Mutex for synchronizing state changes

    /** Handle state transition from CONSTRUCTED to INITIALIZED.
     * This method can be implemented by plug-ins to perform special handling when the node performs
     * a specific state transition. The default implementation does nothing and always succeeds.
     * Subclasses are free whether or not to call the base class implementation.
     *
     * If an error occurs which causes the state transition to fail, then this method must either return
     * FAILURE or throw a StateTransitionFailedException (or a subclass thereof). All initialization
     * successfully performed by this method before the error occurred must be reverted by this method
     * before returning or throwing an exception.
     *
     * @return SUCCESS if the state transition succeeded, otherwise FAILURE
     * @exception StateTransitionFailedException if the state transition failed
     */
    virtual Result doInit()         { return SUCCESS; }

    /** Handle state transition from INITIALIZED to CONSTRUCTED.
     * This method can be implemented by plug-ins to perform special handling when the node performs
     * a specific state transition. The default implementation does nothing and always succeeds.
     * Subclasses are free whether or not to call the base class implementation.
     *
     * If an error occurs which causes the state transition to fail, then this method must either return
     * FAILURE or throw a StateTransitionFailedException (or a subclass thereof). All initialization
     * successfully performed by this method before the error occurred must be reverted by this method
     * before returning or throwing an exception.
     *
     * @return SUCCESS if the state transition succeeded, otherwise FAILURE
     * @exception StateTransitionFailedException if the state transition failed
     */
    virtual Result doDeinit()       { return SUCCESS; }

    /** Handle state transition from INITIALIZED to OUTPUT_INITIALIZED.
     * This method can be implemented by plug-ins to perform special handling when the node performs
     * a specific state transition. The default implementation does nothing and always succeeds.
     * Subclasses are free whether or not to call the base class implementation.
     *
     * If an error occurs which causes the state transition to fail, then this method must either return
     * FAILURE or throw a StateTransitionFailedException (or a subclass thereof). All initialization
     * successfully performed by this method before the error occurred must be reverted by this method
     * before returning or throwing an exception.
     *
     * @return SUCCESS if the state transition succeeded, otherwise FAILURE
     * @exception StateTransitionFailedException if the state transition failed
     */
    virtual Result doInitOutput()   { return SUCCESS; }

    /** Handle state transition from OUTPUT_INITIALIZED to INITIALIZED.
     * This method can be implemented by plug-ins to perform special handling when the node performs
     * a specific state transition. The default implementation does nothing and always succeeds.
     * Subclasses are free whether or not to call the base class implementation.
     *
     * If an error occurs which causes the state transition to fail, then this method must either return
     * FAILURE or throw a StateTransitionFailedException (or a subclass thereof). All initialization
     * successfully performed by this method before the error occurred must be reverted by this method
     * before returning or throwing an exception.
     *
     * @return SUCCESS if the state transition succeeded, otherwise FAILURE
     * @exception StateTransitionFailedException if the state transition failed
     */
    virtual Result doDeinitOutput() { return SUCCESS; }

    /** Handle state transition from OUTPUT_INITIALIZED to ACTIVATED.
     * This method can be implemented by plug-ins to perform special handling when the node performs
     * a specific state transition. The default implementation does nothing and always succeeds.
     * Subclasses are free whether or not to call the base class implementation.
     *
     * If an error occurs which causes the state transition to fail, then this method must either return
     * FAILURE or throw a StateTransitionFailedException (or a subclass thereof). All initialization
     * successfully performed by this method before the error occurred must be reverted by this method
     * before returning or throwing an exception.
     *
     * @return SUCCESS if the state transition succeeded, otherwise FAILURE
     * @exception StateTransitionFailedException if the state transition failed
     */
    virtual Result doActivate()     { return SUCCESS; }

    /** Handle state transition from ACTIVATED to OUTPUT_INITIALIZED.
     * This method can be implemented by plug-ins to perform special handling when the node performs
     * a specific state transition. The default implementation does nothing and always succeeds.
     * Subclasses are free whether or not to call the base class implementation.
     *
     * If an error occurs which causes the state transition to fail, then this method must either return
     * FAILURE or throw a StateTransitionFailedException (or a subclass thereof). All initialization
     * successfully performed by this method before the error occurred must be reverted by this method
     * before returning or throwing an exception.
     *
     * @return SUCCESS if the state transition succeeded, otherwise FAILURE
     * @exception StateTransitionFailedException if the state transition failed
     */
    virtual Result doDeactivate()   { return SUCCESS; }

    /** Handle state transition from ACTIVATED to STARTED.
     * This method can be implemented by plug-ins to perform special handling when the node performs
     * a specific state transition. The default implementation does nothing and always succeeds.
     * Subclasses are free whether or not to call the base class implementation.
     *
     * If an error occurs which causes the state transition to fail, then this method must either return
     * FAILURE or throw a StateTransitionFailedException (or a subclass thereof). All initialization
     * successfully performed by this method before the error occurred must be reverted by this method
     * before returning or throwing an exception.
     *
     * @return SUCCESS if the state transition succeeded, otherwise FAILURE
     * @exception StateTransitionFailedException if the state transition failed
     */
    virtual Result doStart()        { return SUCCESS; }

    /** Handle state transition from STARTED to ACTIVATED.
     * This method can be implemented by plug-ins to perform special handling when the node performs
     * a specific state transition. The default implementation does nothing and always succeeds.
     * Subclasses are free whether or not to call the base class implementation.
     *
     * If an error occurs which causes the state transition to fail, then this method must either return
     * FAILURE or throw a StateTransitionFailedException (or a subclass thereof). All initialization
     * successfully performed by this method before the error occurred must be reverted by this method
     * before returning or throwing an exception.
     *
     * @return SUCCESS if the state transition succeeded, otherwise FAILURE
     * @exception StateTransitionFailedException if the state transition failed
     */
    virtual Result doStop()         { return SUCCESS; }

    /** Handle flushing of the input queue.
     * This method can be implemented by plug-ins to perform special handling when the input queue of
     * this node is flushed. The default implementation does nothing and always succeeds.
     * Subclasses are free whether or not to call the base class implementation.
     *
     * @return SUCCESS if the operation succeeded, otherwise FAILURE
     */
    virtual Result doFlush()        { return SUCCESS; }

    /** Get an output jack of this node.
     * This method returns a pointer to an existing output jack of this node
     * with the given jack tag. If no such jack exists, a null pointer is returned.
     * If the output jack is cloned, only the master of the jack group is returned.
     * The caller must not delete the returned object.
     *
     * @return A pointer to the requested output jack or 0
     */
    virtual OutputJack* getOwnOutputStream(const string&  = "default") = 0;

    /** Get an output jack of this node.
     * This method returns a pointer to an existing output jack of this node
     * with the given jack tag. If no such jack exists, a null pointer is returned.
     * If the output jack is cloned, only the master of the jack group is returned.
     * The caller must not delete the returned object.
     *
     * @return A pointer to the requested output jack or 0
     */
    virtual const OutputJack* getOwnOutputStream(const string&  = "default") const = 0;

    /** Get an input jack of this node.
     * This method returns a pointer to an existing input jack of this node
     * with the given jack tag. If no such jack exists, a null pointer is returned.
     * If the input jack is cloned, only the master of the jack group is returned.
     * The caller must not delete the returned object.
     *
     * @return A pointer to the requested input jack or 0
     */
    virtual InputJack* getOwnInputStream(const string&  = "default") = 0;

    /** Get an input jack of this node.
     * This method returns a pointer to an existing input jack of this node
     * with the given jack tag. If no such jack exists, a null pointer is returned.
     * If the input jack is cloned, only the master of the jack group is returned.
     * The caller must not delete the returned object.
     *
     * @return A pointer to the requested input jack or 0
     */
    virtual const InputJack* getOwnInputStream(const string&  = "default") const = 0;

    /** Get the input property of this node.
     * This method returns a pointer to the input property of this node.
     * The caller must not delete the returned object. The object is destroyed when this node
     * is destroyed.
     *
     * @return A pointer to the input property of this node
     */
    virtual Property* getOwnInputProperty()  ;

    /** Get the output property of this node.
     * This method returns a pointer to the output property of this node.
     * The caller must not delete the returned object. The object is destroyed when this node
     * is destroyed.
     *
     * @return A pointer to the input property of this node
     */
    virtual Property* getOwnOutputProperty() ;

    /** Get the working input property of this node.
     * This method returns a pointer to the working input property of this node.
     * The caller must not delete the returned object. The object is destroyed when this node
     * is destroyed.
     *
     * @return A pointer to the working input property of this node
     */
    virtual Property* getOwnWorkingInputProperty()  ;

    /** Get the working output property of this node.
     * This method returns a pointer to the working output property of this node.
     * The caller must not delete the returned object. The object is destroyed when this node
     * is destroyed.
     *
     * @return A pointer to the working output property of this node
     */
    virtual Property* getOwnWorkingOutputProperty() ;

    /** Lock the state mutex.
     * This is an internal method which should not be used by plug-ins.
     */
    void stateLock()   {state_mutex.lock();  }

    /** Unlock the state mutex.
     * This is an internal method which should not be used by plug-ins.
     */
    void stateUnlock() {state_mutex.unlock();}

    /** Set the type of this node.
     *
     * @param type Node type
     */
    virtual void setType(INode::Type type);

    /** Reset execution state for all events in the given state.
     * This method resets the state variables which record which out-of-band event has been executed successfully
     * in the given state. After calling this method, the state of all events for the given node state
     * is "not executed successfully".
     *
     * @param state The node state
     */
    inline void reset(int state)                    { getEventDispatcher().reset(state); }

    /** Reset execution state for an event in the given state.
     * This method resets the state variables which record which out-of-band event has been executed successfully
     * in the given state for the given event. After calling this method, the state of the events for the given
     * node state is "not executed successfully".
     *
     * @param key The key of the event
     * @param state The node state
     */
    inline void reset(const string& key, int state) { getEventDispatcher().reset(key, state); }

  public:
    /** Create a new node.
     *
     * @param name Node name
     */
    Node(const char* name = "Node");

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

    /** Change the state of the node.
     * This method puts the node into the given state,
     * performing multiple state transitions if necessary.
     *
     * @param state The state of the node that should be reached
     * @exception StateTransitionFailedException if a state transition has failed
     * @exception UnsuccessfulRequiredCallException if a required interface method was not called successfully
     */
    virtual void reachState(const INode::State& state) 
      throw(const StateTransitionFailedException&, const UnsuccessfulRequiredCallException&);

    /** Change the state of the node to CONSTRUCTED.
     * This method puts the node into the COSTRUCTED state,
     * performing multiple state transitions if necessary.
     *
     * @exception StateTransitionFailedException if a state transition has failed
     * @exception UnsuccessfulRequiredCallException if a required interface method was not called successfully
     */
    virtual void reachConstructed() 
      throw(const StateTransitionFailedException&, const UnsuccessfulRequiredCallException&);

    /** Change the state of the node to INITIALIZED.
     * This method puts the node into the INITIALIZED state,
     * performing multiple state transitions if necessary.
     *
     * @exception StateTransitionFailedException if a state transition has failed
     * @exception UnsuccessfulRequiredCallException if a required interface method was not called successfully
     */
    virtual void reachInitialized() 
      throw(const StateTransitionFailedException&, const UnsuccessfulRequiredCallException&);

    /** Change the state of the node to OUTPUT_INITIALIZED.
     * This method puts the node into the OUTPUT_INITIALIZED state,
     * performing multiple state transitions if necessary.
     *
     * @exception StateTransitionFailedException if a state transition has failed
     * @exception UnsuccessfulRequiredCallException if a required interface method was not called successfully
     */
    virtual void reachOutputInitialized() 
      throw(const StateTransitionFailedException&, const UnsuccessfulRequiredCallException&);

    /** Change the state of the node to ACTIVATED.
     * This method puts the node into the ACTIVATED state,
     * performing multiple state transitions if necessary.
     *
     * @exception StateTransitionFailedException if a state transition has failed
     * @exception UnsuccessfulRequiredCallException if a required interface method was not called successfully
     */
    virtual void reachActivated() 
      throw(const StateTransitionFailedException&, const UnsuccessfulRequiredCallException&);

    /** Change the state of the node to STARTED.
     * This method puts the node into the STARTED state,
     * performing multiple state transitions if necessary.
     *
     * @exception StateTransitionFailedException if a state transition has failed
     * @exception UnsuccessfulRequiredCallException if a required interface method was not called successfully
     */
    virtual void reachStarted() 
      throw(const StateTransitionFailedException&, const UnsuccessfulRequiredCallException&);

    /** Perform state transition from CONSTRUCTED to INITIALIZED.
     * This method changes the state and invokes the doInit method of the node.
     * The state transition fails if doInit fails or a required interface method for this
     * state transition has not been called successfully.
     *
     * This implementation changes the state of the internal event dispatcher
     * invokes doInit().
     * Plug-ins should reimplement doInit() rather than init() to implement special handling
     * for this state transition.
     *
     * @exception StateTransitionFailedException if doInit has failed
     * @exception UnsuccessfulRequiredCallException if a required interface method was not called successfully
     */
    virtual void init()
      throw (const StateTransitionFailedException&, const UnsuccessfulRequiredCallException&) ;

    /** Perform state transition from INITIALIZED to OUTPUT_INITIALIZED.
     * This method changes the state and invokes the doInitOutput method of the node.
     * The state transition fails if doInitOutput fails or a required interface method for this
     * state transition has not been called successfully.
     *
     * This implementation changes the state of the internal event dispatcher
     * invokes doInitOutput().
     * Plug-ins should reimplement doInitOutput() rather than initOutput() to implement special handling
     * for this state transition.
     *
     * @exception StateTransitionFailedException if doInitOutput has failed
     * @exception UnsuccessfulRequiredCallException if a required interface method was not called successfully
     */
    virtual void initOutput()
      throw (const StateTransitionFailedException&, const UnsuccessfulRequiredCallException&) ;

    /** Perform state transition from OUTPUT_INITIALIZED to ACTIVATED.
     * This method changes the state and invokes the doActivate method of the node.
     * The state transition fails if doActivate fails or a required interface method for this
     * state transition has not been called successfully.
     *
     * This implementation changes the state of the internal event dispatcher
     * invokes doActivate().
     * Plug-ins should reimplement doActivate() rather than activate() to implement special handling
     * for this state transition.
     *
     * @exception StateTransitionFailedException if doActivate has failed
     * @exception UnsuccessfulRequiredCallException if a required interface method was not called successfully
     */
    virtual void activate()
      throw (const StateTransitionFailedException&,  const UnsuccessfulRequiredCallException&);

    /** Perform state transition from ACTIVATED to STARTED.
     * This method changes the state and invokes the doStart method of the node.
     * The state transition fails if doStart fails or a required interface method for this
     * state transition has not been called successfully.
     *
     * This implementation changes the state of the internal event dispatcher
     * invokes doStart().
     * Plug-ins should reimplement doStart() rather than start() to implement special handling
     * for this state transition.
     *
     * @exception StateTransitionFailedException if doStart has failed
     * @exception UnsuccessfulRequiredCallException if a required interface method was not called successfully
     */
    virtual void start()
      throw (const StateTransitionFailedException&,  const UnsuccessfulRequiredCallException&)  ;

    /** Perform state transition from STARTED to ACTIVATED.
     * This method changes the state and invokes the doStop method of the node.
     * The state transition fails if doStop fails or a required interface method for this
     * state transition has not been called successfully.
     *
     * This implementation changes the state of the internal event dispatcher
     * invokes doStop().
     * Plug-ins should reimplement doStop() rather than stop() to implement special handling
     * for this state transition.
     *
     * @exception StateTransitionFailedException if doStop has failed
     * @exception UnsuccessfulRequiredCallException if a required interface method was not called successfully
     */
    virtual void stop()
      throw (const StateTransitionFailedException&,  const UnsuccessfulRequiredCallException&);

    /** Perform state transition from ACTIVATED to OUTPUT_INITIALIZED.
     * This method changes the state and invokes the doDeactivate method of the node.
     * The state transition fails if doDeactivate fails or a required interface method for this
     * state transition has not been called successfully.
     *
     * This implementation changes the state of the internal event dispatcher
     * invokes doActivate().
     * Plug-ins should reimplement doActivate() rather than activate() to implement special handling
     * for this state transition.
     *
     * @exception StateTransitionFailedException if doDeactivate has failed
     * @exception UnsuccessfulRequiredCallException if a required interface method was not called successfully
     */
    virtual void deactivate()
      throw (const StateTransitionFailedException&,  const UnsuccessfulRequiredCallException&);

    /** Perform state transition from OUTPUT_INITIALIZED to INITIALIZED.
     * This method changes the state and invokes the doDeinitOutput method of the node.
     * The state transition fails if doDeinitOutput fails or a required interface method for this
     * state transition has not been called successfully.
     *
     * This implementation changes the state of the internal event dispatcher
     * invokes doDeinitOutput().
     * Plug-ins should reimplement doDeinitOutput() rather than deinitOutput() to implement special handling
     * for this state transition.
     *
     * @exception StateTransitionFailedException if doDeinitOutput has failed
     * @exception UnsuccessfulRequiredCallException if a required interface method was not called successfully
     */
    virtual void deinitOutput()
      throw (const StateTransitionFailedException&,  const UnsuccessfulRequiredCallException&);

    /** Perform state transition from INITIALIZED to CONSTRUCTED.
     * This method changes the state and invokes the doDeinit method of the node.
     * The state transition fails if doDeinit fails or a required interface method for this
     * state transition has not been called successfully.
     *
     * This implementation changes the state of the internal event dispatcher
     * invokes doDeinit().
     * Plug-ins should reimplement doDeinit() rather than deinit() to implement special handling
     * for this state transition.
     *
     * @exception StateTransitionFailedException if doDeinithas failed
     * @exception UnsuccessfulRequiredCallException if a required interface method was not called successfully
     */
    virtual void deinit()
      throw (const StateTransitionFailedException&,  const UnsuccessfulRequiredCallException&);

    /** Flush the input queue of the node.
     * This method flushes the queues of all input jacks of the node.
     * It may only be called in state ACTIVATED or STARTED.
     *
     * This implementation invokes doFlush.
     * Plug-ins should not reimplement this method. Instead, special handling for flushing the queue
     * should be implemented in doFlush.
     *
     * @return SUCCESS if the method succeeded, otherwisew FAILURE
     */
    virtual Result flush();

    /** Check if the node is in CONSTRUCTED state.
     *
     * @return @c true if the node is in state CONSTRUCTED, otherwise @c false
     */
    virtual nmm_bool isConstructed()       const { return (getState() == INode::CONSTRUCTED ? true : false); }


    /** Check if the node is in INITIALIZED state.
     *
     * @return @c true if the node is in state INITIALIZED, otherwise @c false
     */
    virtual nmm_bool isInitialized()       const { return (getState() == INode::INITIALIZED ? true : false); }

    /** Check if the node is in OUTPUT_INITIALIZED state.
     *
     * @return @c true if the node is in state OUTPUT_INITIALIZED, otherwise @c false
     */
    virtual nmm_bool isOutputInitialized() const { return (getState() == INode::OUTPUT_INITIALIZED ? true : false); }

    /** Check if the node is in ACTIVATED state.
     *
     * @return @c true if the node is in state ACTIVATED, otherwise @c false
     */
    virtual nmm_bool isActivated()         const { return (getState() == INode::ACTIVATED ? true : false); }

    /** Check if the node is in STARTED state.
     *
     * @return @c true if the node is in state STARTED, otherwise @c false
     */
    virtual nmm_bool isStarted()           const { return (getState() == INode::STARTED ? true : false); }

    /** Get the current state of the node.
     *
     * @return The current state of the node
     */
    virtual INode::State getState()               const { return static_cast<INode::State>(getEventDispatcher().getState()); }

    /** Block this node.
     * This method blocks all instream message processing of this node.
     * The behaviour is the same as for stop(), except that the state of the node does not change.
     *
     * @deprecated Blocking of nodes is deprecated. Nodes should be stopped instead.
     */
    virtual void block() = 0;

    /** Unblock this node.
     * This method unblocks all instream message processing of this node if it was previously blocked.
     * The behaviour is the same as for start(), except that the state of the node does not change.
     *
     * @deprecated Blocking of nodes is deprecated. Nodes should be stopped instead.
     */
    virtual void unblock() = 0;

    /** Request an input jack.
     * This method requests an input jack with the given format and jack tag
     * and returns an interface to the requested jack.
     * If the request fails, a null pointer is returned.
     * The caller is responsible for deleting the jack interface.
     *
     * This method may only be called in state INITIALIZED.
     *
     * @param format The format of the jack
     * @param jack_tag The name of an input stream
     * @return An interface to the requested jack or 0
     */
    virtual const InputJack* getInputJack(const Format* format, const char* jack_tag = 0) const = 0;

    /** Request an input jack.
     * This method requests an input jack with the given format and jack tag
     * and returns an interface to the requested jack.
     * If the request fails, a null pointer is returned.
     * The caller is responsible for deleting the jack interface.
     *
     * This method may only be called in state INITIALIZED.
     *
     * @param format The format of the jack
     * @param jack_tag The name of an input stream
     * @return An interface to the requested jack or 0
     */
    virtual IInputJack* getInputJack(const Format& format, const string& jack_tag);

    /** Request an output jack.
     * This method requests an output jack with the given format and jack tag
     * and returns an interface to the requested jack.
     * If the request fails, a null pointer is returned.
     * The caller is responsible for deleting the jack interface.
     *
     * This method can bypass the check whether the format is supported.
     *
     * This method may only be called in state OUTPUT_INITIALIZED.
     *
     * @param format The format of the jack
     * @param jack_tag The name of an output stream
     * @param output_initialized @c false to disable format checking, @c true for normal operation
     * @return An interface to the requested jack or 0
     */
    virtual const OutputJack* getOutputJack(const Format* format, 
					    const char* jack_tag = 0, 
					    bool output_initialized = true) const = 0;

    /** Request an output jack.
     * This method requests an output jack with the given format and jack tag
     * and returns an interface to the requested jack.
     * If the request fails, a null pointer is returned.
     * The caller is responsible for deleting the jack interface.
     *
     * This method may only be called in state OUTPUT_INITIALIZED.
     *
     * @param format The format of the jack
     * @param jack_tag The name of an output stream
     * @return An interface to the requested jack or 0
     */
    virtual IOutputJack* getOutputJack(const Format& format, const string& jack_tag);

    /** Get the format of an input stream.
     * This method returns the connection format of the given stream if the stream is connected.
     * If the stream is not connected or does not exist, a null pointer is returned.
     *
     * This method should be used by plug-ins to request the current connection format.
     * The caller must not delete the returned object. The object stays valid until the
     * connection format changes.
     *
     * @param jack_tag The name of an input stream
     * @returns A pointer to a Format object describing the connection format or 0
     */
    virtual const Format* getInputFormat(const char * jack_tag = "default") const = 0;

    /** Get the format of an output stream.
     * This method returns the connection format of the given stream if the stream is connected.
     * If the stream is not connected or does not exist, a null pointer is returned.
     *
     * This method should be used by plug-ins to request the current connection format.
     * The caller must not delete the returned object. The object stays valid until the
     * connection format changes.
     *
     * @param jack_tag The name of an output stream
     * @returns A pointer to a Format object describing the connection format or 0
     */
    virtual const Format* getOutputFormat(const char * jack_tag = "default") const = 0;

    /** Get the cost of an input stream.
     * This method returns the cost of the input stream with the given jack tag.
     * If no such stream exists, the returned cost is zero.
     *
     * @param jack_tag The name of an input stream
     * @return The cost of the stream or zero
     *
     * @deprecated This interface is part of the resource manager which is not available in this release
     */
    virtual nmm_float getCost(const string& jack_tag) const;


    /** Get the type of the node.
     *
     * @return The type of the node
     */
    virtual INode::Type getType() const;

    /** Get the internal cost of the node.
     *
     * This method returns the cost of all internal computation performed by a node
     * which is not dependent on input and output format parameters.
     *
     * @return The internal cost of the node
     *
     * @deprecated This interface is part of the resource manager which is not available in this release
     */
    virtual nmm_float getInternalCost()  const;

    /** Get an interface to a connected input jack.
     * This method returns an interface to an existing and connected input jack with the
     * given jack tag. If no such jack exists, a null pointer is returned.
     * The caller is responsible for deleting the jack interface.
     *
     * @param jack_tag The name of an input stream
     * @return An interface to the existing and connected jack or 0
     */
    virtual IInputJack*   getInputStream(const string& jack_tag);

    /** Get an interface to a connected input jack.
     * This method returns an interface to an existing and connected input jack with the
     * given jack tag. If no such jack exists, a null pointer is returned.
     * The caller is responsible for deleting the jack interface.
     *
     * @param jack_tag The name of an input stream
     * @return An interface to the existing and connected jack or 0
     */
    virtual IOutputJack*  getOutputStream(const string& jack_tag);

    /** Check if an output stream is connected.
     * This method returns a flag which indicates if the output stream
     * with the given jack tag is connected.
     * If no such stream exists, the result is @c false.
     *
     * @param jack_tag The name of an output stream
     * @return @c true if the stream is connected, @c false if the stream is not connected or does not exist
     */
    virtual nmm_bool isOutputConnected(const string& jack_tag) const;

    /** Check if an input stream is connected.
     * This method returns a flag which indicates if the input stream
     * with the given jack tag is connected.
     * If no such stream exists, the result is @c false.
     *
     * @param jack_tag The name of an input stream
     * @return @c true if the stream is connected, @c false if the stream is not connected or does not exist
     */
    virtual nmm_bool isInputConnected(const string& jack_tag) const;

    /** Send upstream composite event.
     * This method asynchronously sends a composite event in upstream direction from this node.
     * The actual CEvent sent is a copy of the given CEvent.
     *
     * If a null pointer is passed for the jack tag, the event is sent to all connected input jacks.
     *
     * @param cevent The composite event to send
     * @param jack_tag Jack tag of jack over which the event is sent, or 0 to send to all jacks
     */
    virtual Result sendEventUpstr(CEvent* cevent, const char*  jack_tag = "default") = 0;

    /** Send upstream composite event.
     * This method asynchronously sends a composite event in upstream direction from this node.
     * The actual CEvent sent is a copy of the given CEvent.
     *
     * If a null pointer is passed for the jack tag, the event is sent to all connected input jacks.
     *
     * @param cevent The composite event to send
     * @param jack_tag Jack tag of jack over which the event is sent, or 0 to send to all jacks
     */
    virtual Result sendEventUpstr(CEvent& cevent, const char*  jack_tag = "default") = 0;

    /** Send upstream event.
     * This method asynchronously sends a composite event in upstream direction from this node.
     * The actual CEvent sent is a composite event containing exactly the given Event.
     *
     * If a null pointer is passed for the jack tag, the event is sent to all connected input jacks.
     *
     * @param event The event to send
     * @param jack_tag Jack tag of jack over which the event is sent, or 0 to send to all jacks
     */
    virtual Result sendEventUpstr(Event&  event, const char*  jack_tag = "default")  = 0;

    /** Send downstream composite event.
     * This method asynchronously sends a composite event in downstream direction from this node.
     * The actual CEvent sent is a copy of the given CEvent.
     *
     * If a null pointer is passed for the jack tag, the event is sent to all connected input jacks.
     *
     * @param cevent The composite event to send
     * @param jack_tag Jack tag of jack over which the event is sent, or 0 to send to all jacks
     */
    virtual Result sendEventDownstr(CEvent* cevent, const char*  jack_tag = "default") = 0;

    /** Send downstream composite event.
     * This method asynchronously sends a composite event in downstream direction from this node.
     * The actual CEvent sent is a copy of the given CEvent.
     *
     * If a null pointer is passed for the jack tag, the event is sent to all connected input jacks.
     *
     * @param cevent The composite event to send
     * @param jack_tag Jack tag of jack over which the event is sent, or 0 to send to all jacks
     */
    virtual Result sendEventDownstr(CEvent& cevent, const char*  jack_tag = "default") = 0;

    /** Send downstream event.
     * This method asynchronously sends a composite event in downstream direction from this node.
     * The actual CEvent sent is a composite event containing exactly the given Event.
     *
     * If a null pointer is passed for the jack tag, the event is sent to all connected input jacks.
     *
     * @param event The event to send
     * @param jack_tag Jack tag of jack over which the event is sent, or 0 to send to all jacks
     */
    virtual Result sendEventDownstr(Event&   event, const char*  jack_tag = "default") = 0;

    /** Get the input property of the node.
     * This method returns a copy of the input property of the node.
     * The input property is the set of formats which are supported by the input streams of the node.
     * The caller is responsible for deleting the returned Property object.
     *
     * The input property is valid in the states INITIALIZED, OUTPUT_INITIALIZED, ACTIVATED and STARTED.
     * In all other states, the property is empty.
     *
     * @return A pointer to a Property object describing the set of formats
     */
    virtual const Property *getInputProperty() const; 

    /** Get the input property of the node.
     * This method returns a copy of the input property of the node.
     * The input property is the set of formats which are supported by the input streams of the node.
     * The caller is responsible for deleting the returned Property object.
     *
     * The input property is valid in the states INITIALIZED, OUTPUT_INITIALIZED, ACTIVATED and STARTED.
     * In all other states, the property is empty.
     *
     * @return A pointer to a Property object describing the set of formats
     */
     virtual       Property *getInputProperty();


    /** Get the output property of the node.
     * This method returns a copy of the output property of the node.
     * The output property is the set of formats which are supported by the output streams of the node.
     * The caller is responsible for deleting the returned Property object.
     *
     * The output property is valid in the states INITIALIZED, OUTPUT_INITIALIZED, ACTIVATED and STARTED.
     * In all other states, the property is empty.
     *
     * @return A pointer to a Property object describing the set of formats
     */
    virtual const Property *getOutputProperty() const;

    /** Get the output property of the node.
     * This method returns a copy of the output property of the node.
     * The output property is the set of formats which are supported by the output streams of the node.
     * The caller is responsible for deleting the returned Property object.
     *
     * The output property is valid in the states INITIALIZED, OUTPUT_INITIALIZED, ACTIVATED and STARTED.
     * In all other states, the property is empty.
     *
     * @return A pointer to a Property object describing the set of formats
     */
    virtual       Property *getOutputProperty();

    /** Get the working input property of the node.
     * This method returns a copy of the working input property of the node.
     * The working input property is the set of formats which are supported by the input streams of the node
     * with the current configuration of connected input streams.
     * The caller is responsible for deleting the returned Property object.
     *
     * The input property is valid in the states OUTPUT_INITIALIZED, ACTIVATED and STARTED.
     * In all other states, the property is empty.
     *
     * @return A pointer to a Property object describing the set of formats
     */
    virtual const Property *getWorkingInputProperty() const;

    /** Get the working input property of the node.
     * This method returns a copy of the working input property of the node.
     * The working input property is the set of formats which are supported by the input streams of the node
     * with the current configuration of connected input streams.
     * The caller is responsible for deleting the returned Property object.
     *
     * The input property is valid in the states OUTPUT_INITIALIZED, ACTIVATED and STARTED.
     * In all other states, the property is empty.
     *
     * @return A pointer to a Property object describing the set of formats
     */
    virtual       Property *getWorkingInputProperty() ;


    /** Get the working output property of the node.
     * This method returns a copy of the working output property of the node.
     * The working output property is the set of formats which are supported by the output streams of the node
     * with the current configuration of connected input streams.
     * The caller is responsible for deleting the returned Property object.
     *
     * The output property is valid in the states OUTPUT_INITIALIZED, ACTIVATED and STARTED.
     * In all other states, the property is empty.
     *
     * @return A pointer to a Property object describing the set of formats
     */
    virtual const Property *getWorkingOutputProperty() const;

    /** Get the working output property of the node.
     * This method returns a copy of the working output property of the node.
     * The working output property is the set of formats which are supported by the output streams of the node
     * with the current configuration of connected input streams.
     * The caller is responsible for deleting the returned Property object.
     *
     * The output property is valid in the states OUTPUT_INITIALIZED, ACTIVATED and STARTED.
     * In all other states, the property is empty.
     *
     * @return A pointer to a Property object describing the set of formats
     */
    virtual       Property *getWorkingOutputProperty() ;

  protected: //events
    /** Get the cost of an input stream.
     * This method returns the cost of the input stream with the given jack tag.
     * If no such stream exists, the returned cost is zero.
     *
     * @param jack_tag The name of an input stream
     * @param cost Returns the cost
     * @return SUCCESS
     *
     * @deprecated This method is no longer used and deprecated
     */
    virtual Result getCost(const string& jack_tag, float& cost) const { cost = getCost(jack_tag.c_str()); return SUCCESS;}

    /** Get the internal cost of the node.
     *
     * This method returns the cost of all internal computation performed by a node
     * which is not dependent on input and output format parameters.
     *
     * @param cost Returns the internal cost
     * @return SUCCESS
     *
     * @deprecated This method is no longer used and deprecated
     */
    virtual Result getInternalCost(float& cost)  const {cost = getInternalCost(); return SUCCESS;}

    /** Get the computation configuration of the node.
     * This method returns a copy of the computation configuration of the node.
     * The computation configuration is a set of parameters which control the operation of a node and which
     * are not parameters of input and output formats, such as quality parameters of an encoder.
     * The caller is responsible for deleting the returned ComputationConfig object.
     *
     * The computation configuration is valid in the states INITIALIZED, OUTPUT_INITIALIZED, ACTIVATED and STARTED.
     * In all other states, the configuration has no parameters.
     *
     * @return A pointer to a ComputationConfig object describing the computation configuration
     *
     * @deprecated This interface is part of the resource manager which is not available in this release
     */
    virtual ComputationConfig* getComputationConfig() const ;

    /** Set the computation configuration of the node.
     *
     * @param computation_config A computation configuration
     *
     * @deprecated This interface is part of the resource manager which is not available in this release
     */
    virtual void setComputationConfig(const ComputationConfig* computation_config);

    /** Get the working computation configuration of the node.
     * This method returns a copy of the working computation configuration of the node.
     * working The computation configuration is a set of parameters which control the operation of a node and which
     * are not parameters of input and output formats, such as quality parameters of an encoder.
     * Unlike the computation configuration, the working computation configuration also depends on the configuration
     * of connected input streams.
     * The caller is responsible for deleting the returned ComputationConfig object.
     *
     * The working computation configuration is valid in the states OUTPUT_INITIALIZED, ACTIVATED and STARTED.
     * In all other states, the configuration has no parameters.
     *
     * @return A pointer to a ComputationConfig object describing the computation configuration
     *
     * @deprecated This interface is part of the resource manager which is not available in this release
     */
    virtual ComputationConfig* getWorkingComputationConfig() const ;

    /** Set the working computation configuration of the node.
     *
     * @param computation_config A computation configuration
     *
     * @deprecated This interface is part of the resource manager which is not available in this release
     */
    virtual void setWorkingComputationConfig(const ComputationConfig* computation_config);
  };


  // IMPLEMENTATION

  inline nmm_float Node::getCost(const string&) const {return 1;}

  inline nmm_float Node::getInternalCost() const {return 1;}

  inline IInputJack* Node::getInputStream(const string&) {return 0;}

  inline IOutputJack* Node::getOutputStream(const string&) {return 0;}

}

#include "nmm/nmm_suffix.hpp"

#endif
