/* 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_GRAPHBUILDER_HPP
#define NMM_GRAPHBUILDER_HPP NMM_GRAPHBUILDER_HPP

#include "nmm/nmm_prefix.hpp"

#include "nmm/multimedia/NodeDescription.hpp"
#include "nmm/multimedia/sync/interfaces/IMultiAudioVideoSynchronizer.hpp"
#include "nmm/misc/graphurl/GraphURL.hpp"
#include "nmm/services/registry/NMMApplication.hpp"
#include "nmm/services/registry/GraphDescription.hpp"
#include "CompositeNode.hpp"

#include <string>

#include "visibility.hpp"

namespace NMM {

  class DLLEXPORT GraphBuilder {

  public:
    GraphBuilder();

    ~GraphBuilder();

    /**
     * Set URL for graph building
     *
     * \param url The URL as string
     * \return true if vaild URL was given, else false
     */
    bool setURL(const string& url);

    /**
     * Set URL for graph building
     *
     * \param utl The URL as %GraphURL
     */
    void setURL(const GraphURL& url);

    /**
     * Enable/disable visualization (currently not supported)
     *
     * \param true to enable, else false
     */
    void setVisualization(const bool);

    /**
     * The main functionality: create a flow graph from the given URL
     * using the given NMM application object.  If a synchronizer was
     * set, sink nodes will be added to it.  If node descriptions were
     * set, corresponding sink nodes will be added to the composite
     * node.  If INode of sink nodes were set, these sink nodes remain
     * under the full control of the application.
     *
     * \param NMM application object
     * \return created composite node
     */
    CompositeNode* createGraph(NMMApplication& app);

    /**
     * Returns the URL of the graph builder
     *
     * \param the URL
     */
    const GraphURL* getURL() const { return &__url; }

    /**
     * Sets the audio sink to be used during the creation of the flow
     * graph. Either this method or the corresponding method taking a
     * NodeDescription must be called before calling createGraph().
     *
     * \param audio sink (e.g. PlaybackNode)
     * \param the jack tag of its input
     */
    void setAudioSink(INode* sink, const string& input_jack = "default");

    /**
     * Sets the node description for the audio sink to be created
     * during the creation of the flow graph. Either this method or
     * the corresponding method taking an INode must be called before
     * calling createGraph().
     *
     * \param audio sink (e.g. PlaybackNode)
     * \param the jack tag of its input
     */
    void setAudioSink(const NodeDescription& sink, const string& input_jack = "default");

    /**
     * Returns the node description for the audio sink.
     * \return node description for the audio sink
     */
    const NodeDescription& getAudioSinkNodeDescription();

    /**
     * Explicitly sets the input format to be used by the audio sink. 
     * If this methods is not called prior to calling createGraph(),
     * the connection format will be negotiated.
     *
     * \param format to be used by audio sink
     */
    void setAudioSinkFormat(const Format& format);

    /**
     * Sets the jack tag for audio streams to request from any
     * demultiplexer nodes to be included during the graph building
     * process. This allows to control which audio track to choose.
     *
     * \param a substring of the wanted jack tag 
     */
    void setDemuxAudioJackTag(const string& tag);

    /**
     * Sets the number of messages to be prefetched for the audio
     * sink. 
     *
     * \param the number of messages, needs to be greater than zero to
     * enable prefetching
     */
    void setAudioPrefetchQueueSize(const unsigned int& prefetch_queue_size);

    /**
     * Sets the node desription for the video sink to be created
     * during the creation of the flow graph. Either this method or
     * the corresponding method taking an INode must be called before
     * calling createGraph().
     *
     * \param video sink (e.g. XDisplayNode)
     * \param the jack tag of its input
     */
    void setVideoSink(INode* sink, const string& input_jack = "default");

    /**
     * Sets the node desription for the video sink to be created
     * during the creation of the flow graph. Either this method or
     * the corresponding method taking an INode must be called before
     * calling createGraph().
     *
     * \param video sink (e.g. XDisplayNode)
     * \param the jack tag of its input
     */
    void setVideoSink(const NodeDescription& sink, const string& input_jack = "default");

    /**
     * Returns the node description for the video sink.
     * \return node description for the video sink
     */
    const NodeDescription& getVideoSinkNodeDescription();

    /**
     * Explicitly sets the input format to be used by the video sink. 
     * If this methods is not called prior to calling createGraph(),
     * the connection format will be negotiated.
     *
     * \param format to be used by video sink
     */
    void setVideoSinkFormat(const Format& format);

    /**
     * Sets the jack tag for video streams to request from any
     * demultiplexer nodes to be included during the graph building
     * process. This allows to control which video track to choose.
     *
     * \param a substring of the wanted jack tag 
     */
    void setDemuxVideoJackTag(const string& tag);

    /**
     * Sets the number of messages to be prefetched for the video
     * sink. 
     *
     * \param the number of messages, needs to be greater than zero to
     * enable prefetching
     */
    void setVideoPrefetchQueueSize(const unsigned int& prefetch_queue_size);

    /**
     * Enables prefetching for audio and video sink by setting
     * suitable values.
     *
     * \param true for enabling prefetching
     */
    void setAudioVideoPrefetchingEnabled(bool enable);

    /**
     * Sets the synchronizer to be used for the given sinks.  Sinks
     * will get connected to this synchronizer during the graph
     * building process.
     *
     * \param the synchronizer
     */
    void setMultiAudioVideoSynchronizer(IMultiAudioVideoSynchronizer* sync);

    /**
     * Sets the sharing type for all nodes that are requested during
     * the graph building alogorithm.
     *
     * \param the sharing type to be used for all requested nodes
     */
    void setSharingType(NodeDescription::SharingType type);

    /**
     * Get the graph description of current flow graph. Should be
     * called after createGraph() was completed successfully.
     *
     * \return the graph description of the created flow graph
     */
    const GraphDescription& getGraphDescription();

  private:
    class SinkNode_t {
    public:
      SinkNode_t(INode* n, const string& t, Format* f, Property* p) : node(n), jack_tag(t), format(f), property(p), connected(false) {};
      ~SinkNode_t() { };
      INode* node;
      string jack_tag;
      Format* format;
      Property* property;
      bool connected;
    };
    typedef list<SinkNode_t> SinkNodes_t;

    INode* requestSinkNode(const NodeDescription& sink_nd, NMMApplication* app);

    list<Response> initRequest(ClientRegistry& registry, NodeDescription& nd);
    INode* requestNode(ClientRegistry& registry, const Response& response);
    INode* requestNode(ClientRegistry& registry, const list<Response>& response_list);
    INode* requestNode(ClientRegistry& registry, const RegistryID& reg_id, const ObjectID& node_id);

    void connectNodes(INode* n1, const string& out_jack, INode* n2, const string& in_jack, const Format* format);

    void cleanupFormatList(const const_format_list& l);

    bool __use_vis;

    GraphURL __url;

    NMMApplication* __app;

    INode*          __audio_sink;
    NodeDescription __audio_sink_nd;
    Format*         __audio_sink_format;
    Property*       __audio_sink_property;
    string          __audio_demux_out_jack_tag;
    string          __audio_sink_in_jack_tag;
    unsigned int    __audio_sink_prefetch_queue_size;
    bool            __is_audio_sink_set_from_external;

    INode*          __video_sink;
    NodeDescription __video_sink_nd;
    Format*         __video_sink_format;
    Property*       __video_sink_property;
    string          __video_demux_out_jack_tag;
    string          __video_sink_in_jack_tag;
    unsigned int    __video_sink_prefetch_queue_size;
    bool            __is_video_sink_set_from_external;

    IMultiAudioVideoSynchronizer* __sync;

    NodeDescription::SharingType __sharing_type;

    typedef map<INode*, NodeDescription> GraphNodes_t; 
    GraphNodes_t __graph_nodes;

    GraphDescription __graph_descr;
  };
}

#include "nmm/nmm_suffix.hpp"

#endif //NMM_GRAPHBUILDER_HPP
