/* 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_EDGEDESCRIPTION_HPP
#define NMM_EDGEDESCRIPTION_HPP

#include "nmm/nmm_prefix.hpp"
 
#include "InstreamBindingDescription.hpp"

#include "nmm/comm/serialize/SerializedValue.hpp"
#include "nmm/comm/format/Format.hpp"

#include "visibility.hpp"

namespace NMM {

class ISession;
class InstreamChannel;

 /** This class describes an edge of two connected Nodes. 
  */
struct DLLEXPORT EdgeDescription : public SerializedValue {
/*! @name Constructor & Destructor
  */
//@{
 /** Constructor.
  */ 
  EdgeDescription();

 /** Constructor.
  *
  * @param out_id specifies the id of the OutputJack of the 'left' Node
  * @param out_tag specifies the jack tag of the OutputJack of the 'left' Node
  * @param in_id specifies the id of the InputJack of the 'right' Node
  * @param in_tag specifies the jack tag of the InputJack of the 'right' Node
  * @param format connection format that is used by both nodes
  * @param id ID of this edge
  */ 
  EdgeDescription(int out_id, const string& out_tag, int in_id, const string& in_tag, const Format* format, int id);

 /** Copy Constructor.
  *
  * @param edge reference to Edge that should be copied. 
  */
  EdgeDescription(const EdgeDescription& edge);

 /** Destructor.
  */
  virtual ~EdgeDescription();

 /** Virtual copy constructor.
  *
  * @return a copy of this object. 
  */
  virtual EdgeDescription* copy() const { return new EdgeDescription(*this); }

  enum EdgeStatus { UNCONNECTED_IN_ID = -1, UNCONNECTED_OUT_ID = -1, UNDEF_EDGE_ID = -1, HELP_EDGE_ID = -2 };

  enum OverlapStatus { COMPLETE = 0, PARTIAL_COPY = 1, PARTIAL_OUTPUT = 2, NONE = 3  };
  
  /** @name Access Methods
   */
  //@{
  /** Returns the ID of this edge.
   * 
   * @return the ID of this edge
   */
  inline int getEdgeID() const { return __id.getRValue(); }
  
  /** Returns the ID of the "left" (q) edge for session sharing.
   * 
   * @return the ID of the "left" (q) edge for session sharing.
   */
  inline int getLeftEdgeID() const { return __q_id.getRValue(); }
  
  /** Returns the ID of the "right" (r) edge for session sharing.
   * 
   * @return the ID of the "right" (r) edge for session sharing.
   */
  inline int getRightEdgeID() const { return __r_id.getRValue(); }
  
  /** Returns the ID of the input node.
   * 
   * @return the ID of the input node.
   */
  inline int getInputNodeID() const { return __in_id.getRValue(); }
  
  /** Returns the ID of the output node.
   * 
   * @return the ID of the output node.
   */
  inline int getOutputNodeID() const { return __out_id.getRValue(); }
  
  /** Returns the ID of the "left" (q) input node for session sharing.
   * 
   * @return the ID of the "left" (q) input node for session sharing.
   */
  inline int getLeftInputNodeID() const { return __q_in_id.getRValue(); }
  
  /** Returns the ID of the "left" (q) output node for session sharing.
   * 
   * @return the ID of the "left" (q) output node for session sharing.
   */
  inline int getLeftOutputNodeID() const { return __q_out_id.getRValue(); }
  
  /** Returns the output jack tag.
   * 
   * @return the output jack tag.
   */
  inline const string& getOutputJackTag() const { return __out_tag.getRValue(); }
  
  /** Returns the input  jack tag.
   * 
   * @return the input jack tag.
   */
  inline const string& getInputJackTag()  const { return __in_tag.getRValue(); }
  
  /** Returns the edge format.
   * 
   * @return the format of this edge. 
   */
  inline const Format* getFormat() const {
    if(__format.getValue() != 0) {
      return __format.getValue()->getPValue();
    } else {
      return 0;
    }
  }
  
  /** Returns the edge format.
   * 
   * @return the format of this edge. 
   */
  inline Format* getFormat() {
    if(__format.getValue() != 0) {
      return __format.getValue()->getPValue();
    } else {
      return 0;
    }
  }
  
  /** Returns the overlap type for session sharing. This is used by session sharing algorithm,
   *  
   * @return the overlap type for session sharing.
   */
  inline OverlapStatus getOverlapType() const { return __overlap_type.getRValue(); }
  
  /** Sets the "left" (q) input node ID for session sharing.
   *
   * @param q_in_id set the "left" (q) input node ID for session sharing.
   */
  inline void setLeftInputNodeID(int q_in_id) { __q_in_id.setValue(q_in_id); }
  
  /** Sets the "left" (q) output node ID for session sharing.
   *
   * @param q_out_id set the "left" (q) output node ID for session sharing.
   */
  inline void setLeftOutputNodeID(int q_out_id) { __q_out_id.setValue(q_out_id); }
  
  /** Sets the "left" (q) edge ID for session sharing.
   *
   * @param q_id set the "left" (q) input node ID for session sharing.
   */
  inline void setLeftEdgeID(int q_id) { __q_id = q_id; }
  
  /** Sets the "right" (r) edge ID for session sharing.
   *
   * @param r_id set the "right" (r) edge ID for session sharing.
   */
  inline void setRightEdgeID(int r_id) { __r_id = r_id; }
  
  /** Sets the overlap type for session sharing.
   *
   * @param overlap_type Sets the overlap type for session sharing.
   */
  inline void setOverlapType(OverlapStatus overlap_type) { __overlap_type = overlap_type; }
  
  /** Sets the connection format.
   *
   * @param format specifies the connection format between two nodes. 
   */
  void setFormat(const Format* format);
  
  /** Returns the binding description.
   *
   * @return BindingDescription for the connection between both nodes. 
   */
   const InstreamBindingDescription& getBindingDescription() const {
     return __binding_description;
   }
  
  /** Returns the binding description.
   *
   * @return BindingDescription for the connection between both nodes. 
   */
   InstreamBindingDescription& getBindingDescription() {
     return __binding_description;
   }
  
  /** Returns the instream channel.
   *
   * @return InstreamChannel which is the binding object for this connection. 
   */
  inline InstreamChannel* getInstreamChannel() const {
    return __instream_channel.getRValue();
  }
  
  /** Sets the instream channel.
   * 
   * @param channel sets the InstreamChannel for this connection
   */
  inline void setInstreamChannel(InstreamChannel* channel) {
    __instream_channel.setValue(channel);
  }
  
  /** Checks if the output of this edge is connected to a node.
   * 
   * @return true if the output of this edge is connected to a node, otherwise false.
   */
  bool isOutConnected() const { if(__out_id.getValue() == UNCONNECTED_OUT_ID) return false; else return true; }
  
  /** Checks if the input of this edge is connected to a node
   * 
   * @return true if the output of this edge is connected to a node, otherwise false. 
   */
  bool isInConnected() const  { if(__in_id.getValue() == UNCONNECTED_IN_ID) return false; else return true; }
  
  /** Checks if this edge is an input helper edge.
   * 
   * @return true if this edge is an input helper edge. 
   */
  bool isInHelper() const     { if(__in_id.getValue()  == HELP_EDGE_ID) return true; else return false; }
  
  /** Checks if this edge identically overlaps with anther edge.
   *
   * @param edge whose overlap type should be compared to  the overlap type of this edge
   * @return true if the overlap type of given edge is identical to the overlap type of this edge, otherwise false.
   */
  bool isIdenticalOverlap(const EdgeDescription& edge) const;
  //@}
  
  /** Assignment operator.
   * 
   * @param edge that should be assigned to this EdgeDescription
   * @return Reference to this EdgeDescription
   */
  EdgeDescription& operator=(const EdgeDescription& edge);
  
private:
  /** Registers attributes for serialization/deserialization.
   */
  void registerAttributes();

private:
  TValue<int>                 __out_id;                 ///< ID for the outgoing jack of this Edge
  TValue<string>              __out_tag;                ///< Tag of the outgoing jack of this Edge
  TValue<int>                 __in_id;                  ///< ID for the incoming jack of this Edge
  TValue<string>              __in_tag;                 ///< Tag of the incoming jack of this Edge
  TValue< TValue<Format> * >  __format;                 ///< Connection format used by the two connected Nodes. 
  TValue<OverlapStatus>       __overlap_type;           ///< Specifies the overlap type of this connection
  TValue<int>                 __q_out_id;               ///< Internal attribute to specify the left node in session sharing algorithm
  TValue<int>                 __q_in_id;                ///< Internal attribute to specify the right node in session sharing algorithm
  TValue<int>                 __id;                     ///< Stores the ID of this Edge
  TValue<int>                 __q_id;                   ///< Internal attribute to specifiy the left ID of the Jack 
  TValue<int>                 __r_id;                   ///< Internal attribute to specifiy the right ID of the Jack
  InstreamBindingDescription  __binding_description;    ///< stores the BindingDescription of this Edge
  TValue<InstreamChannel*>    __instream_channel;       ///< stores the instream channel of a connected edge. 
  static const char* __EdgeDescription_type_name;       ///< stores the type name of this class 
  static const char* __EdgeDescription_type_ns;         ///< stores the namespace of this class 
};

  /** Writes OverlapStatus to OValueStream.
   *
   * @param ov OValueStream to write to
   * @param eo OverlapStatus to write
   * @return reference to OValueStream given by argument
   */
  OValueStream& operator<<(OValueStream& ov, const EdgeDescription::OverlapStatus& eo);
  
  /** Reads OverlapStatus from IValueStream.
   *
   * @param iv IValueStream to read from
   * @param eo OverlapStatus variable to write to
   * @return reference to IValueStream given by argument
   */
  IValueStream& operator>>(IValueStream& iv, EdgeDescription::OverlapStatus& eo);


  /** Writes vector of EdgeDescriptions to OValueStream.
   *
   * @param ov OValueStream to write to
   * @param string_map vector of EdgeDescriptions to write
   * @return reference to OValueStream given by argument
   */
  NMM::OValueStream& operator<<(NMM::OValueStream& ov, const vector<NMM::EdgeDescription> & string_map) ;

  /** Reads vector of EdgeDescriptions from IValueStream.
   *
   * @param iv IValueStream to read from
   * @param  string_map vector variable to write to
   * @return reference to IValueStream given by argument
   */
  NMM::IValueStream& operator>>(NMM::IValueStream& iv, vector<NMM::EdgeDescription> & string_map) ;

}
#include "nmm/nmm_suffix.hpp"

#endif
