/* 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_INodeImpl_HPP
#define NMM_INodeImpl_HPP

#include "nmm/nmm_prefix.hpp"

#include "nmm/comm/NMMObject.hpp"
#include "INode.hpp"

#include "nmm/comm/IInputJackImpl.hpp"
#include "nmm/comm/IOutputJackImpl.hpp"

#include "visibility.hpp"

namespace NMM
{
  /** Interface for controlling and configuring a node.
   *
   * This interface is implemented by all nodes. It defines methods for querying and
   * changing the current state of a node, format negotiation, prefetching and requesting
   * jacks.
   */

  class DLLEXPORT INodeImpl  : public virtual NMM::NMMObject { 
  public:
    INodeImpl() { addInterface(new INode(*this)); registerEvents(); };

    virtual ~INodeImpl() {};

  protected:
    /** 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&) = 0;
    /** 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&) = 0;
    /** 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&) = 0;
    /** 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&) = 0;
    /** 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&) = 0;
    /** 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&) = 0;
    /** Set prefetch queue size and enable prefetching.
     * This method enables prefetching for the node. It may only be called in state CONSTRUCTED.
     * If prefetching is enabled using this method, the node will not start processing data
     * before at least the given number of messages have been queued in its input queue.
     *
     * @param pre_fetch_queue_size Number of messages to prefetch
     */

    virtual void setPrefetchQueueSize(const nmm_uint32& pre_fetch_queue_size) /* limited(INode::CONSTRUCTED) */ = 0;
    /** Set prefetch queue duration and enable prefetching.
     * This method enables prefetching for the node. It may only be called in state CONSTRUCTED.
     * If prefetching is enabled using this method, the node will not start processing data
     * before messages with at least the given total duration have been queued in its input queue.
     *
     * @param pre_fetch_queue_duration Total duration to prefetch
     */

    virtual void setPrefetchQueueDuration(const Interval& pre_fetch_queue_duration) /* limited(INode::CONSTRUCTED) */ = 0;
    /** Get the prefetch queue size.
     * This method gets the number of messages to be prefetched if prefetching was enabled
     * with setPrefetchQueueSize. Otherwise, it returns zero.
     *
     * @return Number of messages to prefetch or 0
     */

    virtual nmm_uint32 getPrefetchQueueSize() = 0;
    /** Wait until prefetching is finished.
     * This method waits until the process of prefetching is finished, i.e. the
     * number of messages in the input queue or their total duration has reached
     * the value specified by setPrefetchQueueSize or setPrefetchQueueDuration.
     * This method may only to be called in state ACTIVATED.
     */

    virtual void waitPrefetchFinished() /* limited(INode::ACTIVATED) */ = 0;
    /** 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.
     *
     * @exception StateTransitionFailedException if doInit has failed
     * @exception UnsuccessfulRequiredCallException if a required interface method was not called successfully
     */

    virtual void init() /* limited(INode::CONSTRUCTED) */ 
      throw(const StateTransitionFailedException&, const UnsuccessfulRequiredCallException&) = 0;
    /** 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.
     *
     * @exception StateTransitionFailedException if doInitOutput has failed
     * @exception UnsuccessfulRequiredCallException if a required interface method was not called successfully
     */

    virtual void initOutput() /* limited(INode::INITIALIZED) */ 
      throw(const StateTransitionFailedException&, const UnsuccessfulRequiredCallException&) = 0;
    /** 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.
     *
     * @exception StateTransitionFailedException if doActivate has failed
     * @exception UnsuccessfulRequiredCallException if a required interface method was not called successfully
     */

    virtual void activate() /* limited(INode::OUTPUT_INITIALIZED) */ 
      throw(const StateTransitionFailedException&, const UnsuccessfulRequiredCallException&) = 0;
    /** 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.
     *
     * @return SUCCESS if the method succeeded, otherwisew FAILURE
     */

    virtual Result flush() /* limited(INode::ACTIVATED) */ /* limited(INode::STARTED) */ = 0;
    /** 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.
     *
     * @exception StateTransitionFailedException if doStart has failed
     * @exception UnsuccessfulRequiredCallException if a required interface method was not called successfully
     */

    virtual void start() /* limited(INode::ACTIVATED) */ 
      throw(const StateTransitionFailedException&, const UnsuccessfulRequiredCallException&) = 0;
    /** 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.
     *
     * @exception StateTransitionFailedException if doStop has failed
     * @exception UnsuccessfulRequiredCallException if a required interface method was not called successfully
     */

    virtual void stop() /* limited(INode::STARTED) */ 
      throw(const StateTransitionFailedException&, const UnsuccessfulRequiredCallException&) = 0;
    /** 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.
     *
     * @exception StateTransitionFailedException if doDeactivate has failed
     * @exception UnsuccessfulRequiredCallException if a required interface method was not called successfully
     */

    virtual void deactivate() /* limited(INode::ACTIVATED) */ 
      throw(const StateTransitionFailedException&, const UnsuccessfulRequiredCallException&) = 0;
    /** 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.
     *
     * @exception StateTransitionFailedException if doDeinitOutput has failed
     * @exception UnsuccessfulRequiredCallException if a required interface method was not called successfully
     */

    virtual void deinitOutput() /* limited(INode::OUTPUT_INITIALIZED) */ 
      throw(const StateTransitionFailedException&, const UnsuccessfulRequiredCallException&) = 0;
    /** 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.
     *
     * @exception StateTransitionFailedException if doDeinithas failed
     * @exception UnsuccessfulRequiredCallException if a required interface method was not called successfully
     */

    virtual void deinit() /* limited(INode::INITIALIZED) */ 
      throw(const StateTransitionFailedException&, const UnsuccessfulRequiredCallException&) = 0;
    /** 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 = 0;
    /** 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 = 0;
    /** 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 = 0;
    /** 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 = 0;
    /** 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 = 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) /* limited(INode::INITIALIZED) */ = 0;
    /** 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) /* limited(INode::INITIALIZED) */ = 0;
    /** Get all input stream tags.
     * This method returns a list of the jack tags of all input streams of the node.
     *
     * @return List of input streams as jack tags
     */

    virtual list<string >  getInputStreamTags() const = 0;
    /** 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 = "default") const = 0;
    /** 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.
     * The caller is responsible for deleting the returned Format object.
     *
     * @param jack_tag The name of an input stream
     * @returns A pointer to a Format object describing the connection format or 0
     */

    virtual Format* getInputStreamFormat(const string& jack_tag = "default") = 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) /* limited(INode::OUTPUT_INITIALIZED) */ = 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.
     *
     * Unlike getOutputJack, this method may only be called in state INITIALIZED.
     * This method bypasses format negotiation and should only be used for debugging.
     *
     * @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* getUnintializedOutputJack(const Format& format, const string& jack_tag) /* limited(INode::INITIALIZED) */ = 0;
    /** Get an interface to a connected output jack.
     * This method returns an interface to an existing and connected output 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 output stream
     * @return An interface to the existing and connected jack or 0
     */

    virtual IOutputJack* getOutputStream(const string& jack_tag) /* limited(INode::OUTPUT_INITIALIZED) */ = 0;
    /** Get all output stream tags.
     * This method returns a list of the jack tags of all output streams of the node.
     *
     * @return List of output streams as jack tags
     */

    virtual list<string >  getOutputStreamTags() const = 0;
    /** 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 = "default") const = 0;
    /** Clone an output jack.
     * This method requests a clone of an existing and connected output jack with the
     * given jack tag.
     * It returns an interface to the cloned jack and the connection format.
     * The cloned jack is unconnected.
     * If no matching jack exists, a null pointer is returned.
     * The caller is responsible for deleting the jack interface and the returned
     * format object.
     *
     * This method is used for connecting an output jack to multiple input jacks.
     *
     * @param jack_tag The name of an output stream
     * @param intersec_format Returns a pointer to a Format object describing the connection format or 0
     * @return An interface to the cloned jack or 0
     */

    virtual IOutputJack* cloneOutputJack(Format*& intersec_format, const string& jack_tag = "default") /* limited(INode::OUTPUT_INITIALIZED) */ /* limited(INode::ACTIVATED) */ = 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.
     * The caller is responsible for deleting the returned Format object.
     *
     * @param jack_tag The name of an output stream
     * @returns A pointer to a Format object describing the connection format or 0
     */

    virtual Format* getOutputStreamFormat(const string& jack_tag = "default") = 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 = 0;
    /** Get the type of the node.
     *
     * @return The type of the node
     */

    virtual INode::Type getType() const = 0;
    /** Get the current state of the node.
     *
     * @return The current state of the node
     */

    virtual INode::State getState() const = 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 Property* getInputProperty() = 0;
    /** 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() = 0;
    /** 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() = 0;
    /** 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() = 0;
    /** 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 = 0;
    /** 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 = 0;
    /** 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) = 0;
    /** 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) = 0;
    /** 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 = 0;
    /** Request data from the predecessor node.
     * This is an instream event which is used by dynamic data analysis.
     * It is sent internally between nodes and should not be sent manually by applications or plug-ins.
     *
     * @return DELETE
     */

    virtual Result sendData() /* limited(INode::OUTPUT_INITIALIZED) */ /* limited(INode::ACTIVATED) */ /* limited(INode::STARTED) */ /* in-stream */  = 0;
    /** Data request from the predecessor node has failed.
     * This is an instream event which is used by dynamic data analysis.
     * It is sent internally between nodes and should not be sent manually by applications or plug-ins.
     *
     * @return DELETE
     */

    virtual Result sendDataFailed() /* limited(INode::INITIALIZED) */ /* in-stream */  = 0;


  private:
    void registerEvents();
  };

}

#include "nmm/nmm_suffix.hpp"

#endif
