/* 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_PARAMETER_HPP
#define _NMM_PARAMETER_HPP

#include "nmm/nmm_prefix.hpp"

#include "definition.hpp"

namespace NMM 
{
  class IValueStream;
  class OValueStream;
  class Format;
  class R_INT;
  class R_FLOAT;

  /** 
   * This is the abstract superclass for every kind of parameter.
   */

  class Parameter 
  {
  public:
  
    /** The enum PType represents the type of the parameter. 
     */
    enum PType{	INT32  = 0,    /*!< 32-Bit Integer. */
		FLOAT,    /*!< Float */
		STRING,   /*!< C++ String */
		FPOINTER, /*!< Format Pointer for recursive Formats */
		R_INT32,  /*!< Range of 32-Bit Integer */
		R_FLOAT,  /*!< Range of Floats */
		WILDCARD  /*!< Wildcart */
    };
    
  protected:
    
    std::string m_parameter_name; 	///< The name of the Parameter.
    
    PType m_parameter_type; ///< The type of the parameter. See in enum PType for a description.

    float m_parameter_weight; ///< The weighting factor of the parameter.
    
  public:
    
    /** The default constructur.
     *  
     * Note: You have to specify always a name for the parameter.
     *
     * @param pName The parameter-name.
    **/
    Parameter(const std::string& pName);
    
    /** The default destructor.
    */
    virtual ~Parameter();
    
    /** Returns the name of the parameter.
     *
     *	@return string: name of the parameter.
     */
    virtual const std::string & getParameterName() const;
    
    /** Sets the name of the parameter.
     *
     *  @param parameter_name the name of the parameter.
     */
    virtual void setParameterName(const std::string & parameter_name);

    /** Returns the type of the parameter.
     *
     *  @return PType: type of the parameter.
     */
    virtual Parameter::PType getParameterType() const;
    
    /** Adds Value.
     *
     * Adds the value specified in pValue to the set or set of range 
     * of this parameter. This is an abstract function an must be 
     * implemented in every inherited class to cast the void-ptr in
     * the proper type.
     *
     * @param pValue pointer to value 
    */
    virtual void addValue(void * pValue);
    
    /** Adds an int32_t value to the set or set of ranges.
     *
     * @param value an integer value.
     * @param weight the weight of the value.
    */
    virtual void addValue(int32_t value, float weight /*= DEFAULT_WEIGHT*/);
    
    /** Adds a float value to the set or set of ranges.
     *
     * @param value a float value.
     * @param weight the weight of the value.
    */
    virtual void addValue(float value, float weight /*= DEFAULT_WEIGHT*/);

    /** Adds a string value to the set or set of ranges.
     *
     * @param value a string value.
     * @param weight the weight of the value.
    */
    virtual void addValue(const std::string & value, float weight /*= DEFAULT_WEIGHT*/);
    
    /** Adds a Format-pointer to the set of values.
     *
     * @param value a pointer to an already existant format.
     * @param weight the weight of the format.
    */
    virtual void addValue(Format* value, float weight /*= DEFAULT_WEIGHT*/);
    
    /** Adds the value specified in pValue with the appropriate weight.
     *
     * @param pValue the value.
     * @param weight the weight of this value.
    */
    virtual void addValue(void * pValue, float weight);

    /** Adds integer range.
     *
     * Adds an integer-range from lValue to hValue with the specified range of weights to the set of ranges.
     *
     * @param lValue the lower bound of the range.
     * @param hValue the upper bound of the range.
     * @param lWeight the weight of the lower bound.
     * @param hWeight the weight of the upper bound.
     */
    virtual void addValue(int32_t lValue,
                          int32_t hValue,
                          float lWeight /*= DEFAULT_WEIGHT*/,
     float hWeight /*= DEFAULT_WEIGHT*/);

    /** Adds integer range.
     *
     * Adds an float-range from lValue to hValue with the specified range of weights to the set of ranges.
     * @param lValue the lower bound of the range.
     * @param hValue the upper bound of the range.
     * @param lWeight the lower bound of the range.
     * @param hWeight the upper bound of the range.
     */
    virtual void addValue(float lValue,
			  float hValue,
			  float lWeight /* = DEFAULT_WEIGHT*/,
			  float hWeight /* = DEFAULT_WEIGHT*/);

    /** Adds an already existing integer-range to the set of ranges.
     *
     * @param value the integer-range.
     */
    virtual void addValue(R_INT * value);

    /** Adds an already existing float-range to the set of ranges.
     *
     * @param value the float-range.
     */
    virtual void addValue(NMM::R_FLOAT * value);

    /**	Debugging method, prints out the Parameter-Name.
     */
    virtual void showParameterName() const;
    
    /** Debugging method, prints out every Parameter-Value.
     *
     * Debugging method, prints out every Parameter-Value and is
     * reimplemented in every inherited class (deprecated).
     *
     * @deprecated 
    **/
    virtual void showParameter() const {};
    
    /** Prints out every Parameter-Value to the given ostream.
     *
     * Prints out every Parameter-Value to the given ostream and is
     * reimplemented in every inherited class.
     *
     *  @param os output stream
    **/
    virtual std::ostream& showParameter(std::ostream& os) const { return os; }
    
    /** Prints out every Parameter-Value to the given ostream.
     *
     * Prints out every Parameter-Value to the given ostream and is
     * reimplemented in every inherited class in the old verbose format (deprecated).
     *
     *  @param os output stream
     */
    virtual std::ostream& showParameterVerbose(std::ostream& os) const { return os; }

    /** Checks if the parameter pValue is included in the set of values of this parameter.
     *
     * Abstract function which is implemented in all inherited classes.
     *
     * @param pValue the value that will be checked.
     * @return Returns true if the value pValue is included in the set, otherwise false.
    */
    virtual bool isValueIncluded(void *pValue) const = 0;
    
    /** Checks if an integer value is included.
     * 
     * @param value integer value that will be checked.
     * @return true if the value is included, otherwise false.
     */
    virtual bool isValueIncluded(int32_t value) const;

    /** Checks if a float value is included.
     *
     * @param value float value that will be checked.
     * @return true if the value is included, otherwise false.
     */
    virtual bool isValueIncluded(float value) const;

    /** Checks if a string value is included.
     *
     * @param value string value that will be checked.
     * @return true if the value is included, otherwise false.
     */
    virtual bool isValueIncluded(const std::string & value) const;

    /** Checks if a format is included.
     *
     * @param value format pointer that will be checked.
     * @return true if the format is included, otherwise false.
     */
    virtual bool isValueIncluded(const Format * value) const;
    
    /** Checks if range is included.
     *
     * Checks if the range from lValue to hValue is included in the set of ranges of this parameter.
     * Note: the functions returns true if there is also an intersection between the two ranges!
     *
     * @param lValue the lower bound of the range
     * @param hValue the upper bound of the range
     * @return returns true if the range is included in the set of ranges, otherwise false.
     */
    virtual bool isValueIncluded(void *lValue,void *hValue) const;

    /** Checks if the range from lValue to hValue is included.
     *
     * @param lValue the lower bound of the range.
     * @param hValue the upper bound of the range.
     * @return true if the range is included otherwise false.
     */
    virtual bool isValueIncluded(float lValue, float hValue) const;

    /** Checks if the range from lValue to hValue is included.
     *
     * @param lValue the lower bound of the range.
     * @param hValue the uppper bound of the range.
     * @return true if the range is included, otherwise false.
     */
    virtual bool isValueIncluded(int32_t lValue, int32_t hValue) const;

    /** Checks if the range from lValue to hValue has an intersection with a range.
     *
     * @param lValue the lower bound of the range.
     * @param hValue the upper bound of the range.
     * @return true if the range has an intersetion, otherwise false.
     */
    virtual bool isRangeMatching(float lValue, float hValue) const;

    /** Checks if the range form lValue to hValue has an intersection with a range.
     *
     * @param lValue the lower bound of the range.
     * @param hValue the upper bound of the range.
     * @return true if the range has an intersection, otherwise false.
     */
    virtual bool isRangeMatching(int32_t lValue, int32_t hValue) const;

    /** Returns next value.
     *
     * This function iterates over the values and
     * returns the next value or the next range of the set. 
     * At the end of the list, the function returns NULL. Must be 
     * reimplemented in every inherited class.
     *
     * @return pointer to next value
     */
    virtual void * nextValue() const {return 0;}; 
    
    /** Returns first value.
     *
     * This function returns the first value stored in the
     * appropriate set and increases the internal value counter.
     * If you want to iterate over all values of a parameter, this
     * function guaranties to start always with the first value. After a
     * call of this function, just use the nextValue() function above.
     *
     * @return pointer to first value
     */
    virtual void * getFirstValue() const;

    /** Duplicates parameter.
     *
     * This functions makes a copy of the current parameter with all
     * values and weights and returns a pointer to the new parameter.
     *
     * @return Parameter * : the new copy of the parameter.
     */
    virtual Parameter *duplicate() const = 0;
    
    /** Returns the weight of the argument pValue.
     *
     * @param pValue the desired value.
     * @return float: the weight of the value.
     */
    virtual float getWeight(void * pValue) const;
    
    /** Checks if the given argument has the same co-domain.
     *
     * @param reference the parameter which will be compared with.
     * @return true if the given parameter has the same co-domain, otherwise false.
     */
    virtual bool isParameterIdentical(const Parameter* reference) const;

    /**
       Checks if the given argument has an intersection in the co-domain of the values.
       @param reference the parameter that will be matched.
       @return true if the parameters are matching, otherwise false.
     **/
    virtual bool isParameterMatching(const Parameter* reference) const;

    /** Returns the number of values stored in the data-structures.
     * 
     * @return the number of values.
    */
    virtual uint getNumberOfValues() const {return 0;} ;/* Should work ?!?*/
    
    /** Get intersection parameter with given format.
     *
     * This function creates an intersection between the current parameter
     * and given argument reference.
     *
     * @param reference a parameter which will be intersected with the current parameter.
     * @return Parameter *: a pointer to the new created parameter.
     */
    virtual Parameter * getIntersection(const Parameter *reference) const = 0 ;

    /** Gets standardized weight.
     *
     * This functions computes a standardized weight for the included
     * co-domain, depending on the parameter-type.
     *
     *  @return the standardized weight.
     */
    virtual float getStandardizedWeight() const {
      // cout << m_parameter_name << " " << m_parameter_type << " " << this << endl;
      return static_cast<float>(DEFAULT_WEIGHT * m_parameter_weight);
      
    };
    
    /** Sets the weight of the parameter.
     *
     * @param weight the weight of the parameter.
     */
    virtual void setParameterWeight(float weight);

    /** Returns the weight of the parameter.
     *
     * @return float: the weight of the parameter.
     */
    virtual float getParameterWeight() const;

    /** Calls showParameter on Parameter with given ostream.
     *
     * @param os ostream to call showParameter with
     * @param reference Parameter to call on showParameter
     */
    friend std::ostream & operator << (std::ostream & os, const Parameter & reference);

    /** Set input stream.
     *
     * @param stream input stream to set
     */
    virtual void fromStream(IValueStream& stream) = 0;

    /** Set output stream.
     *
     * @param stream output stream to set
     */
    virtual void toStream(OValueStream& stream) const  = 0;
  };

  // IMPLEMENTATION

  inline void Parameter::addValue(void *) {}

  inline void Parameter::addValue(int32_t, float) {}

  inline void Parameter::addValue(float, float) {}

  inline void Parameter::addValue(const std::string &, float ) {}

  inline void Parameter::addValue(Format*, float) {}

  inline void Parameter::addValue(void*, float) {}

  inline void Parameter::addValue(int32_t,
                        int32_t,
                        float,
                        float) {}

  inline void Parameter::addValue(float,
                        float,
                        float,
                        float) {}

  inline void Parameter::addValue(R_INT *) {}

  inline void Parameter::addValue(NMM::R_FLOAT *) {}

  inline float Parameter::getWeight(void *) const{return 1.0;}

  inline bool Parameter::isParameterIdentical(const Parameter*) const {return false;}

  inline bool Parameter::isParameterMatching(const Parameter*) const {return false;}

  inline void * Parameter::getFirstValue() const { return 0; }

}
#include "nmm/nmm_suffix.hpp"

#endif
