/* 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_FORMAT_HPP
#define NMM_FORMAT_HPP NMM_FORMAT_HPP

#include "nmm/nmm_prefix.hpp"

#include "FormatExceptions.hpp"
#include <memory>

#include "visibility.hpp"

namespace NMM {
class IValueStream;
class OValueStream;

/** Objects of this class represent one format.
 *  
 * You can distinguish formats by the following ways:
 * 1. A format is classified by its format_type: the Type/SubType-Notation
 *    Note: Several parameters can have the same Type/SubType
 * 2. A format is specified by its Parameter-List:
 *    Every parameter consists of a set of values or a set of ranges.
*/

  class DLLEXPORT Format
  {
  private:
    string m_format_type; ///< The Type/SubType of the Format.
  
    string m_format_ID; ///< The format-ID

    parameter_list m_parameter_list; ///< The STL-List stores pointer to the different parameters.
     
    mutable parameter_iterator m_value_counter; ///< Internal counter for the function getNextParameter()

    /** The "partner" of the format. 
     *	
     * If the Node is a CONVERTER or a FILTER, every input and output
     * format has exactly one partner-format that expresses the conversion
     * for this pair.
     * If the Node is a SOURCE or SINK, there is either no input 
     * partner format or no output partner format.
    **/
    Format * m_IOPartner;
  
    /** The partners of the format. 
     * 
     * Use this list if the node is a MULTIPLEXER or DEMULTIPLEXER.
     * For a MULTIPLEXER: every input format has several output
     *   formats which are stored in the m_IOPartner_list.
     *   The output formats on their parts use only the IOPartner
     *	 above.
     * For a DEMULTIPLEXER: every output format has severel input
     *   formats which are stored in the m_IOPartner_list.
     *   The input formats on theirs parts use only the m_IOPartner
     *   above.
    **/
    format_list m_IOPartner_list;

    string m_jack_tag; ///< Connects every format to a jack of the node.


    /** Checks if the given argument is a valid format.
     *
     * This function checks if the given argument is a valid format what
     * means that all the parameters of the reference_format have at least
     * one value. Use this method after a createFormatIntersection().
     *
     * @param reference_format a format which will be checked.
     * @return true if reference_format is a valid format, otherwise false
    */
    bool isValidFormat(const Format * reference_format) const;

    /** Checks if parameter is included.
     *
     * @param parameter_name name of parameter
     * @param value value of parameter
     * @return true if parameter is included, false otherwise.
     */
    bool isParamValueIncludedInternal(const string & parameter_name, void * value) const;

    /** Reads parameter and IOPartner format from IValueStream. 
     *
     * @param iv IValueStream to read from
     */
    void createParameter(IValueStream& iv);
    
    /** Relaeses the allocated memory.
     *
     * Deletes all parameter and IOPartner.
     */
    void erase();

  public:
    
    /** The default constructor.
     */
    Format ();
    
    /** Constructor that sets directly type/subtype of the format.
     *  
     *  @param p_m_format_type the type/subtype of the format.
     *  @param jackTag the jack-tag of the format.
    */
    Format (const string & p_m_format_type, const string & jackTag = "default");
    
    /** Default destructor.
     */
    ~Format ();
    
    /** Copy constructor.
     *
     * @param format Format to copy
     */
    Format (const Format& format);

    /** Returns the Type/Subtype of the format.
     *  
     *  @return the Type/Subtype of the format
    */
    const string & getFormatType() const;

    /** Sets the Type/SubType of the format.
     *
     * @param type the Type/Subtype of the format.
    **/
    void setFormatType(const string & type);
    
    /**  Returns all the parameters of the format in a list.
     *
     * @return list of all parameters
    */
    const parameter_list & getParameterList() const;	

    /** Returns list of parameter with specified type.
     *       
     * @param type PType parameter
     * @return list of parameter
    */
    parameter_list getParameterList(Parameter::PType type) const;

    /** Adds an INT value to the specified Parameter.
     *  
     * If the Parameter exists, the value will be enqueued.
     * If the Parameter doesn't exist, a new Parameter will be constructed with the new value.
     *
     * @param pParameterName the parameter name.
     * @param pValue the integer value of the parameter.
     * @param weight the weight of the value.
    */
    void addIntParamValue(const string & pParameterName, 
			  int32_t pValue, 
			  float weight = DEFAULT_WEIGHT) throw (ParameterException);
    
    /** Adds an FLOAT value to the specified Parameter.
     *       
     * If the Parameter exists, the value will be enqueued.
     * If the Parameter doesn't exist, a new Parameter will be constructed with the new value.
     *
     * @param pParameterName The parameter name
     * @param pValue The float value of the parameter
     * @param weight the weight of the value.
    */
    void addFloatParamValue(const string & pParameterName, 
			    float pValue,
			    float weight = DEFAULT_WEIGHT) throw (ParameterException);
    
    /** Adds an STRING value to the specified Parameter.
     * 
     * If the Parameter exists, the value will be enqueued.
     * If the Parameter doesn't exist, a new Parameter will be constructed with the new value.
     * @param pParameterName the parameter name.
     * @param pValue the string value of the parameter.
     * @param weight the weight of the value.
    */
    void addStringParamValue(const string & pParameterName, 
			     const string & pValue, 
			     float weight = DEFAULT_WEIGHT) throw (ParameterException);
    
    /** Adds an FPOINTER (Format-Pointer) value to the specified Parameter.
     *
     * If the Parameter exists, the value will be enqueued.
     * If the Parameter doesn't exist, a new Parameter will be constructed with the new value.
     *
     * @param pParameterName The parameter name
     * @param pValue The pointer-value of the parameter
    */
    void addFPointerParamValue(const string & pParameterName, 
			       Format * pValue) throw (ParameterException);

    /** Adds an INT-Range to the specified Parameter.
     *  
     * If the Parameter exists, the value will be enqueued.
     * If the Parameter doesn't exist, a new Parameter will be constructed with the new value.
     *
     * @param parameter_name the name of the parameter.
     * @param lValue the lower bound value of the range.
     * @param hValue the upper bound value of the range.
     * @param lweight the lower bound weight of the range.
     * @param hweight the upper bound weight of the range.
    */
    void addRIntParamValue(const string & parameter_name ,
			   int32_t lValue, 
			   int32_t hValue, 
			   float lweight = DEFAULT_WEIGHT, 
			   float hweight = DEFAULT_WEIGHT) throw (ParameterException);
    
    /** Adds an FLOAT-Range to the specified Parameter.
     *  
     * If the Parameter exists, the value will be enqueued.
     * If the Parameter doesn't exist, a new Parameter will be constructed with the new value.
     *
     * @param pParameterName the name of the parameter.
     * @param lValue the lower bound value of the range.
     * @param hValue the upper bound value of the range.
     * @param lweight the lower bound weight of the range.
     * @param hweight the upper bound weight of the range.
    */
    void addRFloatParamValue(const string & pParameterName, 
			     float lValue,
			     float hValue, 
			     float lweight = DEFAULT_WEIGHT, 
			     float hweight = DEFAULT_WEIGHT) throw (ParameterException);
    
    /** Gives this Parameter a wildcard value.
     *
     * If the Parameter exists, the value will be set to wildcard
     * It the Parameter doesn't exist, a new Parameter will be constructed with the given value.
     *
     * @param pParameterName The parameter name
    */
    void addWildcard(const string & pParameterName) throw (ParameterException);

    /** Returns the default value of the parameter.
     * 
     * @param parameter_name the name of the parameter.
     * @return the default value for int32_t
     **/
    int32_t getIntValue(const string & parameter_name) const throw (ParameterException);

    /** Returns the default value of the parameter.
     *   
     * @param parameter_name the name of the parameter.
     * @return the default value for float 
     **/
    float getFloatValue(const string & parameter_name) const throw (ParameterException);

    /** Returns the default value of the parameter.
     *
     * @param parameter_name the name of the parameter.
     * @return the default value for string  
    **/
    string getStringValue(const string & parameter_name) const throw (ParameterException);

    /** Returns the first range-value of the parameter.
     *  
     * @param parameter_name the name of the parameter.
     * @return the first range-value 
     **/
    R_INT * getRIntValue(const string & parameter_name) const throw (ParameterException);

    /** Returns the first range-value of the parameter.
     * 
     * @param parameter_name the name of the parameter.
     * @return the first range-value of the parameter.
    **/
    NMM::R_FLOAT * getRFloatValue(const string & parameter_name) const throw (ParameterException);

    /** Returns the first value of the parameter.
     *
     * @param parameter_name the name of the parameter.
     * @return the first value of the parameter.
    **/
    Format * getFPointerValue(const string & parameter_name) const throw (ParameterException);

    /** Sets the default value of the parameter.
     * 
     * @param parameter_name the name of the parameter.
     * @param default_value the default value.
    **/
    void setDefaultValue(const string & parameter_name, int32_t default_value) const throw (ParameterException);

    /** Sets the default value of the parameter.
     *       
     * @param parameter_name the name of the parameter.
     * @param  default_value the default value.
    **/
    void setDefaultValue(const string & parameter_name, float default_value) const throw (ParameterException);

    /** Sets the default value of the parameter.
     *
     * @param parameter_name the name of the parameter.
     * @param default_value the default value.
    **/
    void setDefaultValue(const string & parameter_name, string default_value) const throw (ParameterException);
    
    /** Returns the complete value list of the specified parameter.
     * 
     * @param parameter_name the name of the parameter.
     * @return the complete list with int32_t values.
    **/
    const int32_t_list getIntValueList(const string & parameter_name) const throw (ParameterException);

    /** Returns the complete value list of the specified parameter.
     *  
     * @param parameter_name the name of the parameter.
     * @return the complete list with float values.
    **/
    const float_list getFloatValueList(const string & parameter_name) const throw (ParameterException);

    /** Returns the complete value list of the specified parameter.
     * 
     * @param parameter_name the name of the parameter.
     * @return the complete list with string values.
    **/
    const string_list getStringValueList(const string & parameter_name) const throw (ParameterException);

    /** Returns the complete value list of the specified parameter.
     *
     * @param parameter_name the name of the parameter.
     * @return the complete list with R_INT32 values.
    **/
    const r_int32_t_list getRIntValueList(const string & parameter_name) const throw (ParameterException);

    /** Returns the complete value list of the specified parameter.
     *
     * @param parameter_name the name of the parameter.
     * @return the complete list with R_FLOAT values.
    **/
    const r_float_list getRFloatValueList(const string & parameter_name) const throw (ParameterException);

    /** Returns the complete value list of the specified parameter.
     *
     * @param parameter_name the name of the parameter.
     * @return the complete list with format-pointer values.
    **/
    const format_list getFPointerValueList(const string & parameter_name) const throw (ParameterException);

    /** Sets the weight of the specified parameter.
     *
     * @param parameter_name the name of the parameter.
     * @param weight the weight of the parameter.
    **/
    void setParameterWeight(const string & parameter_name, float weight) const throw (ParameterException);
    
    /** Returns the weight of the specified parameter.
     *  
     * @param parameter_name the name of the parameter.
     * @return float: the weight of the parameter.
    **/
    float getParameterWeight(const string & parameter_name) const throw (ParameterException);

    /** Deletes the specified parameter.
       
       @param parameter_name the name of the parameter.
    **/
    void deleteParameter(const string & parameter_name) throw (ParameterException);

    /** Debugging method.
       
       Prints out all the parameters from the Parameter_List (deprecated).
    */
    void showParameter() const;
    
    /** Helper for output stream operator.
       
       Prints out all the parameters from the Parameter_List via given ostream.
       @param output_stream output stream
    */
    ostream& showParameter(ostream& output_stream) const;
    
    /** Helper for output stream operator.
       
       Prints out all the parameters from the Parameter_List via given ostream in the old verbose format (deprecated).
       @param output_stream output stream
    */
    ostream& showParameterVerbose(ostream& output_stream) const;

    /** Checks if a given Paramter is included in the parameter list.
       
       @param pParameterName The name of the parameter
       @return	true if a parameter with the ParameterName is included in the Format, otherwise false
    */
    bool isParameterIncluded(const string & pParameterName) const;

    /** Checks if a given Paramter is specified in the parameter list.
       
       This is the case if the parameter is included AND not a wildcard.

       @param pParameterName The name of the parameter
       @return	true if a parameter with the ParameterName is specified in the Format, otherwise false
    */
    bool isParameterSpecified(const string & pParameterName) const;
    
    /** Returns the ParameterType of the specified Parameter.
       
       @param pParameterName The Name of the parameter.
    */
    Parameter::PType getParameterType(const string & pParameterName) const throw (ParameterException);
    
    /** Checks if a given parameter-value is included in a specified parameter.
       
       @param parameter_name The parameter that will be checked.
       @param value The value that will be checked
       @return true if the given value is included, otherwise false.
    */
    bool isParamValueIncluded(const string & parameter_name, int32_t value) const;

    /** Checks if a given parameter-value is included in a specified parameter.
       
       @param parameter_name The parameter that will be checked.
       @param value The value that will be checked
       @return true if the given value is included, otherwise false.
    */
    bool isParamValueIncluded(const string & parameter_name, float value) const;

    /** Checks if a given parameter-value is included in a specified parameter.
       
       @param parameter_name The parameter that will be checked.
       @param value The value that will be checked
       @return true if the given value is included, otherwise false.
    */
    bool isParamValueIncluded(const string & parameter_name, const string & value) const;

    /** Checks if a given parameter-value is included in a specified parameter.
       
       @param parameter_name The parameter that will be checked.
       @param value The value that will be checked
       @return true if the given value is included, otherwise false.
    */
    bool isParamValueIncluded(const string & parameter_name, Format * value) const;
    
    /** Checks if a given parameter-range is included in a specified parameter.
       
       @param parameter_name The parameter that will be checked.
       @param l_value The lower bound of the parameter.
       @param h_value The lower bound of the parameter.
       @return true if the given value is included, otherwise false.
    */
    bool isParamRangeValueIncluded(const string & parameter_name, int32_t l_value, int32_t h_value) const ;

    /** Checks if a given parameter-range is included in a specified parameter.
       
       @param parameter_name The parameter that will be checked.
       @param l_value The lower bound of the parameter.
       @param h_value The upper bound of the parameter.
       @return true if the given value is included, otherwise false.
    */
    bool isParamRangeValueIncluded(const string & parameter_name, float l_value, float h_value) const;

    /** Returns a pointer to the desired format.
       
       @param pParameterName The name of the parameter.
       @return Parameter * if the format exists, otherwise NULL.
    */
    Parameter * getParameter(const string & pParameterName) const;

    /** Adds a Parameter to the list of parameters, m_parameter_list.
       
       @param parameter the parameter which will be added to the list.
    **/
    void addParameter(Parameter *parameter);
    
    /** Creates a copy of specified parameter.
     *
     * This functions takes a name of a parameter as argument and
     * copies the given parameter with all values and weights.
     * If there is no parameter with the specified name, the
     * functions returns NULL.
     *
     * @param parameter_name the name of the parameter.
     * @return the new parameter (the copy).
    **/
    Parameter * duplicateParameter(const string & parameter_name) const;
    
    /** Copies format.
     *
     * Duplicates the current format and returns a pointer to the
     * new created format.
     * return the new format.
    **/
    Format * duplicateFormat() const;

    /** Set the IOPartner for this Format.
     *       
     * Look at the member variable IOPartner for a description.
     * @param pFormat The "Partner"-Format
    */
    void setIOPartner(const Format *pFormat);

    /** Get the IOPartner for this Format.
     *
     * @return Format *: The "Partner"-Format or NULL
    */
    const Format * getIOPartner() const;

    /** Get the IOPartner for this Format.
     * 
     * @return Format *: The "Partner"-Format or NULL
    */
          Format * getIOPartner();

    /** Adds an IOPartner to the list of io partner.
     *   
     *    Note: this is only important for (DE-)Multiplexer
     *       nodes. All other types have only ONE
     *     IOPartner.
     * @param pValue a format that will be added as IOPartner.
    **/
    void addIOPartnerInList(Format *pValue);

    /** Get the list of IOPartner.
     *   
     * @return parameter_list: the list of IOPartners.
    **/
    const format_list & getIOPartnerList() const;

    /** Check if the given parameter param is mutable or not.
     *   
     * A Parameter is mutable if the co-domain of his input is 
     * not equal to the co-domain of his output. It is also
     * mutable if his co-domain contains a wildcard or is empty.
     *
     * @param parameter_name the name of the parameter that will be checked.
     * @return true if the parameter is mutable or not.
     **/
    bool isParameterIdentical(const string & parameter_name) const;

    /** Returns next parameter.
     *
     * This function returns a pointer to a parameter which
     * is included in the m_parameter_list. If you call the 
     * function several times, you can iterate through the 
     * whole list. If the list comes to his end, you will 
     * get a NULL pointer.
     *
     * @return pointer to next parameter.
    **/
    const Parameter *getNextParameter() const;

    /** Resets internal value counter.
     *
     * This function resets the internal m_value_counter of 
     * the format class.
    **/
    void resetValueCounter() const;

    /** Gets size of cross product of parameter values.
     *
     * This functions computes the size of the cross product
     * from the containing parameter-values. This function
     * is needed by splitting CONVERTER during the 
     * graph-algorithm.
     *
     * @return int: the size of the cross product.
    **/
    int getCrossProduct() const;

    /** Returns number of values in parameter list.
     *
     * This function returns the number of values stored in
     * the m_parameter_list.
     *
     * @return int: the number of values.
    **/
    uint getNumberOfValues() const;

    /** Returns parameter only in output format but not in input format.
     *
     * This function finds parameter which are not in the input-format-list
     * but in the output-format-list. These parameters are then given back
     * in the return value parameter_list.
     * Note: This function is necessary during the format-negotiation.
     *
     * @return list of parameters, NULL if no such parameter found
     **/
    const parameter_list getLostParameter() const;

    /** Checks if formats are identical.
     *
     * This function compares the current instance of the format-class with the given
     * argument of the function.
     *
     * @param reference_format the format which is compared.
     * @return true if the Formats are identical in all parameters and theirs values, otherwise false.
     **/
    bool isFormatIdentical(const Format * reference_format) const;

    /** Checks if formats are matching.
     *
     * This function matches the current instance with the given parameter reference_format.
     * Matching means unlike the "isFormatIdentical(Format *)" function, that there is only an
     * intersection in the co-domain of the parameters. 
     *
     * @param reference_format the format which is compared.
     * @param compare_type_subtype true if subtype should be compared also, false otherwise
     * @return true if the format is matching, otherwise false.
     **/
    bool isFormatMatching(const Format * reference_format, bool compare_type_subtype = true) const;

    /** Checks if format is included.
     *
     * Checks if a given format is included in the current instance. This camparison is not so strong as in the
     * matching and the identical-function.
     *
     * @param reference_format the format that will be checked.
     * @return bool if the format is included, otherwise false.
    **/
    bool isFormatIncluded(const Format *reference_format) const;

    /** Creates intersection format.
     *
     * This function creates an intersection between the current instance and the given
     * argument reference_format.
     * Note: If one of the parameters fails to participate at the intersection, you will 
     *       get NULL.
     *
     * @param reference_format a format with which there will be created an intersection.
     * @return Format * if succeded, otherwise NULL
    **/
    Format * createIntersectionFormat(const Format * reference_format) const;

    /** Creates best intersection format.
     *
     * This function creates a 'best match' intersection between the current instance and the given
     * argument subset_format. A 'best match' means that all parameter values of the subset_format
     * are tried to matched against this format. If not possible, the values of this format are taken.
     *
     * @param subset_format a format with which there will be created an intersection.
     * @param param_counter the number of matched parameters
     * @return Format * if succeeded, otherwise NULL
    **/
    Format* createBestIntersectionFormat(const Format* subset_format, unsigned int& param_counter) const;

    /** Creates intersection with subset format.
     *
     * This function creates an intersection between the current instance and the given
     * argument subset_format. The intersection is only performed on the subset of
     * parameters that is included in subset_format. All other parameters are copied
     * of the current instance.
     * Note: If one of the parameters fails to participate at the intersection, you will 
     *       get NULL.
     *
     * @param subset_format a format with which there will be created an intersection.
     * @return Format* if succeeded, otherwise NULL
    **/
    Format * createSubsetIntersectionFormat(const Format * subset_format) const;

    /** Create intersection format.
     *
     * This function creates an intersection between the current instance and the given
     * argument reference_format.
     * Note: If one of the parameters fails to participate at the intersection, you will 
     *       get NULL.
     * Note: If the given format is NULL, a copy of this Format object will be returned
     *
     * @param reference_format a format with which there will be created an intersection.
     * @return Format * if succeded, otherwise NULL
    **/
    Format * createCheckedIntersectionFormat(const Format * reference_format) const;

    /** Set jack tag.
     *
     * @param param jack tag to set
    **/
    void setJackTag(const string & param);

    /** Returns the jack associated to the format.
     *
     * @return jack tag 
    **/
    const string & getJackTag() const;

    /** Checks if the format has a specified jackTag.
     *
     * @return true if the format has a jacktag, otherwise false.
    **/
    bool hasJackTag() const;

    /** Returns the standardized weight for this format. 
     *
     * This weight is calculated
     * by all included parameter standardized weights.
     * @return float: the standardized weight.
    **/
    float getStandardizedWeight() const;

    /** Sets the ID of the format.
     *
     * @param ID ID of the format
    **/
    void setFormatID(const string & ID);

    /** Returns the format-ID.
     *
     * @return the format ID.
    **/
    const string & getFormatID() const;

    /** Checks if the given constraints can be fulfilled. 
     *
     * Every key-value-pair of the commited constraint-format represents a constraint that will be checked.
     * Note: this criterion is stronger than matching.
     *
     * @param constraint a format representing the constraints.
     * @return true if all key-value-pairs of the commited format can be fulfilled, otherwise false.
    **/
    bool fulfilConstraints(const Format * constraint) const;
    
    /** Returns a list of unique formats including their corresponding IO-Partner.
     *
     * Note: this function is used for creating the dependenttree.
     *
     * @param reference_format reference format
     * @return format_list: a list of unique formats.
     */
    format_list getUniqueFormatList(Format * reference_format = NULL) const;

    /** Returns a list of unique formats without considering their coressponding IO-Partner.
     *
     * Note: this function is used for creating the dependenttree.
     *
     * @return format_list: a list of unique formats.
    */
    format_list getUniqueFormatListSingle() const;

    /** Returns a list of parameter which will be splitted during the getUniqueFormatList().
     *
     * Note: this function is used for creating the dependenttree.
     *
     * @return parameter_list: a list of parameters.
    */
    parameter_list getSplittedParameterList() const;

    /** Checks if a format is unique and has only parameters (keys) with one value.
     *
     * @return true if the format is unique, otherwise false.
    */
    bool isFormatUnique() const;

    /** Sets the parameter (R_INT32 or R_FLOAT) of the format to the optimized value.
    */
    void buildOptimizedFormat();

    /** Checks if a format has parameter with ranges of values.
     *
     * @return true if a format has at least one parameter with ranges, otherwise false.
    */
    bool hasFormatRanges() const;

    /** Checks if a format has a wildcard-parameter.
     *
     *  @return true if the format has at least one wildcard-parameter.
    **/
    bool hasFormatWildcards() const;

    /** Actualizes Format.
     *
     * Updates Format by creating intersection format with given format
     *
     * @param format format to create intersection with
    **/
    void actualizeFormat(const Format * format);

    /** Resolves all wildcards in format with the values of the given format. 
     *
     * Attention, the parameters with wildcards have to 
     * match!
     *
     * @param format format to use as source
     */
    void resolveWildcards(const Format * format);

    /** Resolves all wildcards in format with the values of the given format. 
     *
     * Only wildcards of matching parameters are resolved.
     *
     * @param format format to use as source
     */
    void resolveMatchingWildcards(const Format * format);

    /** Compares standardized weight of formats.
     *
     * @param f1 first format
     * @param f2 second format
     * @return true if standardized weigth of f1 is smaller than that of f2, false otherwise.
     */
    friend bool operator< (const Format& f1, const Format& f2);

    /** Check if formats are identical.
     * @param lhs first format
     * @param rhs second format
     * @return true if formats are identical, false otherwise.
     */
    DLLEXPORT friend bool operator== (const Format& lhs, const Format& rhs);

    /** Assignment operator.
     * @param reference Format to assign to this format
     * @return reference to this format
     */
    const Format & operator = (const Format & reference);

    /** Writes Format to given ostream.
     * 
     * @param os ostream to write to
     * @param format reference to Format to write
     */
    DLLEXPORT friend ostream & operator << (ostream& os, const Format& format);

    /** Reads Format from given IValueStream.
     * 
     * @param iv IVlaueStream to read from
     * @param format variable to read Format value to 
     */
    DLLEXPORT friend IValueStream& operator>>(IValueStream& iv, Format& format);
    
    /** Writes Format to given OValueStream.
     * 
     * @param ov OVlaueStream to write to
     * @param format reference to Format to write
     */
    DLLEXPORT friend OValueStream& operator<<(OValueStream& ov, const Format& format);
    
    /* static strings for all known format types to have static type safety */
    static const char* wild_wild_type;
    static const char* audio_wild_type;
    static const char* audio__type;
    static const char* audio_ac3_type;
    static const char* audio_mp3_type;
    static const char* audio_amr_type;
    static const char* audio_mpa_type;
    static const char* audio_mpeg_type;
    static const char* audio_mpeg1_type;
    static const char* audio_x_ogg_type;
    static const char* audio_x_wav_type;
    static const char* audio_ogg_type;
    static const char* audio_pcma_type;
    static const char* audio_pcmu_type;
    static const char* audio_raw_type;
    static const char* audio_wambi_type;
    static const char* audio_wma_type;
    static const char* av_wild_type;
    static const char* av_asf_type;
    static const char* av_avi_type;
    static const char* av_mpeg_type;
    static const char* av_mpegps_type;
    static const char* av_ogg_type;
    static const char* av_ogm_type;
    static const char* video_wild_type;
    static const char* video_h263_type;
    static const char* video_h264_type;
    static const char* video_h263plus_type;
    static const char* video_jpeg_type;
    static const char* video_mpeg_type;
    static const char* video_mpeg2_type;
    static const char* video_mpeg2pes_type;
    static const char* video_mpeg4_type;
    static const char* video_mpv_type;
    static const char* video_raw_type;
    static const char* video_rgb_type;
    static const char* video_rtjpeg_type;
    static const char* video_spu_type;
    static const char* video_test_type;
    static const char* video_yuv_type;
    
    /* static strings for all known format parameters to have static type safety */
    static const char* audio_codec_param;
    static const char* audio_format_param;
    static const char* audio_format_string_param;
    static const char* bitperpixel_param;
    static const char* bitpersample_param;
    static const char* bitrate_param;
    static const char* blockalign_param;
    static const char* channelorder_param;
    static const char* channels_param;
    static const char* colorspace_param;
    static const char* compressor_param;
    static const char* encoding_param;
    static const char* endian_param;
    static const char* extradata_param;
    static const char* extradata_size_param;
    static const char* format_param;
    static const char* format_ac3_audio_streams_param;
    static const char* format_mpeg_audio_streams_param;
    static const char* format_dts_audio_streams_param;
    static const char* format_lpcm_audio_streams_param;
    static const char* format_mpeg_video_streams_param;
    static const char* format_spu_streams_param;
    static const char* framerate_param;
    static const char* layer_param;
    static const char* lfe_param;
    static const char* map_ac3_audio_streams_param;
    static const char* map_mpeg_audio_streams_param;
    static const char* map_dts_audio_streams_param;
    static const char* map_lpcm_audio_streams_param;
    static const char* map_mpeg_video_streams_param;
    static const char* map_spu_streams_param;
    static const char* num_audio_streams_param;
    static const char* num_video_streams_param;
    static const char* quality_param;
    static const char* ratio_x_param;
    static const char* ratio_y_param;
    static const char* sample_rate_param;
    static const char* sign_param;
    static const char* speaker_setup_param;
    static const char* version_param;
    static const char* video_format_param;
    static const char* x_resolution_param;
    static const char* y_resolution_param;

  };


  typedef auto_ptr<Format> Format_var;
}
#include "nmm/nmm_suffix.hpp"

#endif
