/* -*-c++-*-
 *
 * Copyright (C) 2006-2007 Mathias Froehlich 
 *
 * This program 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; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 *
 */

#ifndef _SG_EXPRESSION_HXX
#define _SG_EXPRESSION_HXX 1

#include <string>
#include <vector>
#include <functional>
#include <set>
#include <string>

#include <simgear/props/condition.hxx>
#include <simgear/props/props.hxx>
#include <simgear/math/interpolater.hxx>
#include <simgear/math/SGMath.hxx>
#include <simgear/scene/model/persparam.hxx>
#include <simgear/structure/exception.hxx>
#include <simgear/structure/Singleton.hxx>

namespace simgear
{
  /// Expression tree implementation.
  namespace expression
  {
    enum Type {
      BOOL = 0,
      INT,
      FLOAT,
      DOUBLE
    };
    template<typename T> struct TypeTraits;
    template<> struct TypeTraits<bool> {
      static const Type typeTag = BOOL;
    };
    template<> struct TypeTraits<int> {
      static const Type typeTag = INT;
    };
    template<> struct TypeTraits<float> {
      static const Type typeTag = FLOAT;
    };
    template<> struct TypeTraits<double> {
      static const Type typeTag = DOUBLE;
    };

    struct Value
    {
      Type typeTag;
      union {
        bool boolVal;
        int intVal;
        float floatVal;
        double doubleVal;
      } val;

      Value() : typeTag(DOUBLE)
      {
        val.doubleVal = 0.0;
      }

      Value(bool val_) : typeTag(BOOL)
      {
        val.boolVal = val_;
      }

      Value(int val_) : typeTag(INT)
      {
        val.intVal = val_;
      }

      Value(float val_) : typeTag(FLOAT)
      {
        val.floatVal = val_;
      }

      Value(double val_) : typeTag(DOUBLE)
      {
        val.doubleVal = val_;
      }

    };

    class Binding;
  }

  class Expression : public SGReferenced
  {
  public:
    virtual ~Expression() {}
    virtual expression::Type getType() const = 0;
  };

  const expression::Value eval(const Expression* exp,
                               const expression::Binding* binding = 0);

}

template<typename T>
class SGExpression : public simgear::Expression {
public:
  virtual ~SGExpression() {}
  typedef T result_type;
  typedef T operand_type;
  virtual void eval(T&, const simgear::expression::Binding*) const = 0;

  T getValue(const simgear::expression::Binding* binding = 0) const
  { T value; eval(value, binding); return value; }

  double getDoubleValue(const simgear::expression::Binding* binding = 0) const
  { T value; eval(value, binding); return value; }

  virtual bool isConst() const { return false; }
  virtual SGExpression* simplify();
  virtual simgear::expression::Type getType() const
  {
    return simgear::expression::TypeTraits<T>::typeTag;
  }
  virtual simgear::expression::Type getOperandType() const
  {
    return simgear::expression::TypeTraits<T>::typeTag;
  }
  virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const
  { }
};

/// Constant value expression
template<typename T>
class SGConstExpression : public SGExpression<T> {
public:
  SGConstExpression(const T& value = T()) : _value(value)
  { }
  void setValue(const T& value)
  { _value = value; }
  const T& getValue(const simgear::expression::Binding* binding = 0) const
  { return _value; }
  virtual void eval(T& value, const simgear::expression::Binding*) const
  { value = _value; }
  virtual bool isConst() const { return true; }
private:
  T _value;
};

template<typename T>
SGExpression<T>*
SGExpression<T>::simplify()
{
  if (isConst())
    return new SGConstExpression<T>(getValue());
  return this;
}

template<typename T>
class SGUnaryExpression : public SGExpression<T> {
public:
  const SGExpression<T>* getOperand() const
  { return _expression; }
  SGExpression<T>* getOperand()
  { return _expression; }
  void setOperand(SGExpression<T>* expression)
  {
    if (!expression)
      expression = new SGConstExpression<T>(T());
    _expression = expression;
  }
  virtual bool isConst() const
  { return getOperand()->isConst(); }
  virtual SGExpression<T>* simplify()
  {
    _expression = _expression->simplify();
    return SGExpression<T>::simplify();
  }
  
  virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const
    { _expression->collectDependentProperties(props); }  
protected:
  SGUnaryExpression(SGExpression<T>* expression = 0)
  { setOperand(expression); }

private:
  SGSharedPtr<SGExpression<T> > _expression;
};

template<typename T>
class SGBinaryExpression : public SGExpression<T> {
public:
  const SGExpression<T>* getOperand(size_t i) const
  { return _expressions[i]; }
  SGExpression<T>* getOperand(size_t i)
  { return _expressions[i]; }
  void setOperand(size_t i, SGExpression<T>* expression)
  {
    if (!expression)
      expression = new SGConstExpression<T>(T());
    if (2 <= i)
      i = 0;
    _expressions[i] = expression;
  }

  virtual bool isConst() const
  { return getOperand(0)->isConst() && getOperand(1)->isConst(); }
  virtual SGExpression<T>* simplify()
  {
    _expressions[0] = _expressions[0]->simplify();
    _expressions[1] = _expressions[1]->simplify();
    return SGExpression<T>::simplify();
  }

  virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const
  {
    _expressions[0]->collectDependentProperties(props);
    _expressions[1]->collectDependentProperties(props); 
  } 
  
protected:
  SGBinaryExpression(SGExpression<T>* expr0, SGExpression<T>* expr1)
  { setOperand(0, expr0); setOperand(1, expr1); }
  
private:
  SGSharedPtr<SGExpression<T> > _expressions[2];
};

template<typename T>
class SGNaryExpression : public SGExpression<T> {
public:
  size_t getNumOperands() const
  { return _expressions.size(); }
  const SGExpression<T>* getOperand(size_t i) const
  { return _expressions[i]; }
  SGExpression<T>* getOperand(size_t i)
  { return _expressions[i]; }
  size_t addOperand(SGExpression<T>* expression)
  {
    if (!expression)
      return ~size_t(0);
    _expressions.push_back(expression);
    return _expressions.size() - 1;
  }

  template<typename Iter>
  void addOperands(Iter begin, Iter end)
  {
    for (Iter iter = begin; iter != end; ++iter)
      {
        addOperand(static_cast< ::SGExpression<T>*>(*iter));
      }
  }

  virtual bool isConst() const
  {
    for (size_t i = 0; i < _expressions.size(); ++i)
      if (!_expressions[i]->isConst())
        return false;
    return true;
  }
  virtual SGExpression<T>* simplify()
  {
    for (size_t i = 0; i < _expressions.size(); ++i)
      _expressions[i] = _expressions[i]->simplify();
    return SGExpression<T>::simplify();
  }

  virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const
  {
    for (size_t i = 0; i < _expressions.size(); ++i)
      _expressions[i]->collectDependentProperties(props);
  } 
protected:
  SGNaryExpression()
  { }
  SGNaryExpression(SGExpression<T>* expr0, SGExpression<T>* expr1)
  { addOperand(expr0); addOperand(expr1); }
  
private:
  std::vector<SGSharedPtr<SGExpression<T> > > _expressions;
};




template<typename T>
class SGPropertyExpression : public SGExpression<T> {
public:
  SGPropertyExpression(const SGPropertyNode* prop) : _prop(prop)
  { }
  void setPropertyNode(const SGPropertyNode* prop)
  { _prop = prop; }
  virtual void eval(T& value, const simgear::expression::Binding*) const
  { doEval(value); }
  
  virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const
    { props.insert(_prop.get()); }
private:
  void doEval(float& value) const
  { if (_prop) value = _prop->getFloatValue(); }
  void doEval(double& value) const
  { if (_prop) value = _prop->getDoubleValue(); }
  void doEval(int& value) const
  { if (_prop) value = _prop->getIntValue(); }
  void doEval(long& value) const
  { if (_prop) value = _prop->getLongValue(); }
  void doEval(bool& value) const
  { if (_prop) value = _prop->getBoolValue(); }
  SGSharedPtr<const SGPropertyNode> _prop;
};

template<typename T>
class SGAbsExpression : public SGUnaryExpression<T> {
public:
  SGAbsExpression(SGExpression<T>* expr = 0)
    : SGUnaryExpression<T>(expr)
  { }

  virtual void eval(T& value, const simgear::expression::Binding* b) const
  { value = getOperand()->getValue(b); if (value <= 0) value = -value; }

  using SGUnaryExpression<T>::getOperand;
};

template<typename T>
class SGACosExpression : public SGUnaryExpression<T> {
public:
  SGACosExpression(SGExpression<T>* expr = 0)
    : SGUnaryExpression<T>(expr)
  { }

  virtual void eval(T& value, const simgear::expression::Binding* b) const
  { value = acos((double)SGMisc<T>::clip(getOperand()->getValue(b), -1, 1)); }

  using SGUnaryExpression<T>::getOperand;
};

template<typename T>
class SGASinExpression : public SGUnaryExpression<T> {
public:
  SGASinExpression(SGExpression<T>* expr = 0)
    : SGUnaryExpression<T>(expr)
  { }

  virtual void eval(T& value, const simgear::expression::Binding* b) const
  { value = asin((double)SGMisc<T>::clip(getOperand()->getValue(b), -1, 1)); }

  using SGUnaryExpression<T>::getOperand;
};

template<typename T>
class SGATanExpression : public SGUnaryExpression<T> {
public:
  SGATanExpression(SGExpression<T>* expr = 0)
    : SGUnaryExpression<T>(expr)
  { }

  virtual void eval(T& value, const simgear::expression::Binding* b) const
  { value = atan(getOperand()->getDoubleValue(b)); }

  using SGUnaryExpression<T>::getOperand;
};

template<typename T>
class SGCeilExpression : public SGUnaryExpression<T> {
public:
  SGCeilExpression(SGExpression<T>* expr = 0)
    : SGUnaryExpression<T>(expr)
  { }

  virtual void eval(T& value, const simgear::expression::Binding* b) const
  { value = ceil(getOperand()->getDoubleValue(b)); }

  using SGUnaryExpression<T>::getOperand;
};

template<typename T>
class SGCosExpression : public SGUnaryExpression<T> {
public:
  SGCosExpression(SGExpression<T>* expr = 0)
    : SGUnaryExpression<T>(expr)
  { }

  virtual void eval(T& value, const simgear::expression::Binding* b) const
  { value = cos(getOperand()->getDoubleValue(b)); }

  using SGUnaryExpression<T>::getOperand;
};

template<typename T>
class SGCoshExpression : public SGUnaryExpression<T> {
public:
  SGCoshExpression(SGExpression<T>* expr = 0)
    : SGUnaryExpression<T>(expr)
  { }

  virtual void eval(T& value, const simgear::expression::Binding* b) const
  { value = cosh(getOperand()->getDoubleValue(b)); }

  using SGUnaryExpression<T>::getOperand;
};

template<typename T>
class SGExpExpression : public SGUnaryExpression<T> {
public:
  SGExpExpression(SGExpression<T>* expr = 0)
    : SGUnaryExpression<T>(expr)
  { }

  virtual void eval(T& value, const simgear::expression::Binding* b) const
  { value = exp(getOperand()->getDoubleValue(b)); }

  using SGUnaryExpression<T>::getOperand;
};

template<typename T>
class SGFloorExpression : public SGUnaryExpression<T> {
public:
  SGFloorExpression(SGExpression<T>* expr = 0)
    : SGUnaryExpression<T>(expr)
  { }

  virtual void eval(T& value, const simgear::expression::Binding* b) const
  { value = floor(getOperand()->getDoubleValue(b)); }

  using SGUnaryExpression<T>::getOperand;
};

template<typename T>
class SGLogExpression : public SGUnaryExpression<T> {
public:
  SGLogExpression(SGExpression<T>* expr = 0)
    : SGUnaryExpression<T>(expr)
  { }

  virtual void eval(T& value, const simgear::expression::Binding* b) const
  { value = log(getOperand()->getDoubleValue(b)); }

  using SGUnaryExpression<T>::getOperand;
};

template<typename T>
class SGLog10Expression : public SGUnaryExpression<T> {
public:
  SGLog10Expression(SGExpression<T>* expr = 0)
    : SGUnaryExpression<T>(expr)
  { }

  virtual void eval(T& value, const simgear::expression::Binding* b) const
  { value = log10(getOperand()->getDoubleValue(b)); }

  using SGUnaryExpression<T>::getOperand;
};

template<typename T>
class SGSinExpression : public SGUnaryExpression<T> {
public:
  SGSinExpression(SGExpression<T>* expr = 0)
    : SGUnaryExpression<T>(expr)
  { }

  virtual void eval(T& value, const simgear::expression::Binding* b) const
  { value = sin(getOperand()->getDoubleValue(b)); }

  using SGUnaryExpression<T>::getOperand;
};

template<typename T>
class SGSinhExpression : public SGUnaryExpression<T> {
public:
  SGSinhExpression(SGExpression<T>* expr = 0)
    : SGUnaryExpression<T>(expr)
  { }

  virtual void eval(T& value, const simgear::expression::Binding* b) const
  { value = sinh(getOperand()->getDoubleValue(b)); }

  using SGUnaryExpression<T>::getOperand;
};

template<typename T>
class SGSqrExpression : public SGUnaryExpression<T> {
public:
  SGSqrExpression(SGExpression<T>* expr = 0)
    : SGUnaryExpression<T>(expr)
  { }

  virtual void eval(T& value, const simgear::expression::Binding* b) const
  { value = getOperand()->getValue(b); value = value*value; }

  using SGUnaryExpression<T>::getOperand;
};

template<typename T>
class SGSqrtExpression : public SGUnaryExpression<T> {
public:
  SGSqrtExpression(SGExpression<T>* expr = 0)
    : SGUnaryExpression<T>(expr)
  { }

  virtual void eval(T& value, const simgear::expression::Binding* b) const
  { value = sqrt(getOperand()->getDoubleValue(b)); }

  using SGUnaryExpression<T>::getOperand;
};

template<typename T>
class SGTanExpression : public SGUnaryExpression<T> {
public:
  SGTanExpression(SGExpression<T>* expr = 0)
    : SGUnaryExpression<T>(expr)
  { }

  virtual void eval(T& value, const simgear::expression::Binding* b) const
  { value = tan(getOperand()->getDoubleValue(b)); }

  using SGUnaryExpression<T>::getOperand;
};

template<typename T>
class SGTanhExpression : public SGUnaryExpression<T> {
public:
  SGTanhExpression(SGExpression<T>* expr = 0)
    : SGUnaryExpression<T>(expr)
  { }

  virtual void eval(T& value, const simgear::expression::Binding* b) const
  { value = tanh(getOperand()->getDoubleValue(b)); }

  using SGUnaryExpression<T>::getOperand;
};

template<typename T>
class SGScaleExpression : public SGUnaryExpression<T> {
public:
  SGScaleExpression(SGExpression<T>* expr = 0, const T& scale = T(1))
    : SGUnaryExpression<T>(expr), _scale(scale)
  { }
  void setScale(const T& scale)
  { _scale = scale; }
  const T& getScale() const
  { return _scale; }

  virtual void eval(T& value, const simgear::expression::Binding* b) const
  { value = _scale * getOperand()->getValue(b); }

  virtual SGExpression<T>* simplify()
  {
    if (_scale == 1)
      return getOperand()->simplify();
    return SGUnaryExpression<T>::simplify();
  }

  using SGUnaryExpression<T>::getOperand;
private:
  T _scale;
};

template<typename T>
class SGBiasExpression : public SGUnaryExpression<T> {
public:
  SGBiasExpression(SGExpression<T>* expr = 0, const T& bias = T(0))
    : SGUnaryExpression<T>(expr), _bias(bias)
  { }

  void setBias(const T& bias)
  { _bias = bias; }
  const T& getBias() const
  { return _bias; }

  virtual void eval(T& value, const simgear::expression::Binding* b) const
  { value = _bias + getOperand()->getValue(b); }

  virtual SGExpression<T>* simplify()
  {
    if (_bias == 0)
      return getOperand()->simplify();
    return SGUnaryExpression<T>::simplify();
  }

  using SGUnaryExpression<T>::getOperand;
private:
  T _bias;
};

template<typename T>
class SGInterpTableExpression : public SGUnaryExpression<T> {
public:
  SGInterpTableExpression(SGExpression<T>* expr,
                          const SGInterpTable* interpTable) :
    SGUnaryExpression<T>(expr),
    _interpTable(interpTable)
  { }

  virtual void eval(T& value, const simgear::expression::Binding* b) const
  {
    if (_interpTable)
      value = _interpTable->interpolate(getOperand()->getValue(b));
  }

  using SGUnaryExpression<T>::getOperand;
private:
  SGSharedPtr<SGInterpTable const> _interpTable;
};

template<typename T>
class SGClipExpression : public SGUnaryExpression<T> {
public:
  SGClipExpression(SGExpression<T>* expr)
    : SGUnaryExpression<T>(expr),
      _clipMin(SGMisc<T>::min(-SGLimits<T>::max(), SGLimits<T>::min())),
      _clipMax(SGLimits<T>::max())
  { }
  SGClipExpression(SGExpression<T>* expr,
                   const T& clipMin, const T& clipMax)
    : SGUnaryExpression<T>(expr),
      _clipMin(clipMin),
      _clipMax(clipMax)
  { }

  void setClipMin(const T& clipMin)
  { _clipMin = clipMin; }
  const T& getClipMin() const
  { return _clipMin; }

  void setClipMax(const T& clipMax)
  { _clipMax = clipMax; }
  const T& getClipMax() const
  { return _clipMax; }

  virtual void eval(T& value, const simgear::expression::Binding* b) const
  {
    value = SGMisc<T>::clip(getOperand()->getValue(b), _clipMin, _clipMax);
  }

  virtual SGExpression<T>* simplify()
  {
    if (_clipMin <= SGMisc<T>::min(-SGLimits<T>::max(), SGLimits<T>::min()) &&
        _clipMax >= SGLimits<T>::max())
      return getOperand()->simplify();
    return SGUnaryExpression<T>::simplify();
  }

  using SGUnaryExpression<T>::getOperand;
private:
  T _clipMin;
  T _clipMax;
};

template<typename T>
class SGStepExpression : public SGUnaryExpression<T> {
public:
  SGStepExpression(SGExpression<T>* expr = 0,
                   const T& step = T(1), const T& scroll = T(0))
    : SGUnaryExpression<T>(expr), _step(step), _scroll(scroll)
  { }

  void setStep(const T& step)
  { _step = step; }
  const T& getStep() const
  { return _step; }

  void setScroll(const T& scroll)
  { _scroll = scroll; }
  const T& getScroll() const
  { return _scroll; }

  virtual void eval(T& value, const simgear::expression::Binding* b) const
  { value = apply_mods(getOperand()->getValue(b)); }

  using SGUnaryExpression<T>::getOperand;

private:
  T apply_mods(T property) const
  {
    if( _step <= SGLimits<T>::min() ) return property;

    // apply stepping of input value
    T modprop = floor(property/_step)*_step;

    // calculate scroll amount (for odometer like movement)
    T remainder = property <= SGLimits<T>::min() ? -fmod(property,_step) : (_step - fmod(property,_step));
    if( remainder > SGLimits<T>::min() && remainder < _scroll )
      modprop += (_scroll - remainder) / _scroll * _step;

    return modprop;
  }

  T _step;
  T _scroll;
};

template<typename T>
class SGEnableExpression : public SGUnaryExpression<T> {
public:
  SGEnableExpression(SGExpression<T>* expr = 0,
                     SGCondition* enable = 0,
                     const T& disabledValue = T(0))
    : SGUnaryExpression<T>(expr),
      _enable(enable),
      _disabledValue(disabledValue)
  { }

  const T& getDisabledValue() const
  { return _disabledValue; }
  void setDisabledValue(const T& disabledValue)
  { _disabledValue = disabledValue; }

  virtual void eval(T& value, const simgear::expression::Binding* b) const
  {
    if (_enable->test())
      value = getOperand()->getValue(b);
    else
      value = _disabledValue;
  }

  virtual SGExpression<T>* simplify()
  {
    if (!_enable)
      return getOperand()->simplify();
    return SGUnaryExpression<T>::simplify();
  }
  
  virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const
  {
    SGUnaryExpression<T>::collectDependentProperties(props);
    _enable->collectDependentProperties(props);
  }

  using SGUnaryExpression<T>::getOperand;
private:
  SGSharedPtr<SGCondition> _enable;
  T _disabledValue;
};

template<typename T>
class SGAtan2Expression : public SGBinaryExpression<T> {
public:
  SGAtan2Expression(SGExpression<T>* expr0, SGExpression<T>* expr1)
    : SGBinaryExpression<T>(expr0, expr1)
  { }
  virtual void eval(T& value, const simgear::expression::Binding* b) const
  { value = atan2(getOperand(0)->getDoubleValue(b), getOperand(1)->getDoubleValue(b)); }
  using SGBinaryExpression<T>::getOperand;
};

template<typename T>
class SGDivExpression : public SGBinaryExpression<T> {
public:
  SGDivExpression(SGExpression<T>* expr0, SGExpression<T>* expr1)
    : SGBinaryExpression<T>(expr0, expr1)
  { }
  virtual void eval(T& value, const simgear::expression::Binding* b) const
  { value = getOperand(0)->getValue(b) / getOperand(1)->getValue(b); }
  using SGBinaryExpression<T>::getOperand;
};

template<typename T>
class SGModExpression : public SGBinaryExpression<T> {
public:
  SGModExpression(SGExpression<T>* expr0, SGExpression<T>* expr1)
    : SGBinaryExpression<T>(expr0, expr1)
  { }
  virtual void eval(T& value, const simgear::expression::Binding* b) const
  { value = mod(getOperand(0)->getValue(b), getOperand(1)->getValue(b)); }
  using SGBinaryExpression<T>::getOperand;
private:
  int mod(const int& v0, const int& v1) const
  { return v0 % v1; }
  float mod(const float& v0, const float& v1) const
  { return fmod(v0, v1); }
  double mod(const double& v0, const double& v1) const
  { return fmod(v0, v1); }
};

template<typename T>
class SGPowExpression : public SGBinaryExpression<T> {
public:
  SGPowExpression(SGExpression<T>* expr0, SGExpression<T>* expr1)
    : SGBinaryExpression<T>(expr0, expr1)
  { }
  virtual void eval(T& value, const simgear::expression::Binding* b) const
  { value = pow(getOperand(0)->getDoubleValue(b), getOperand(1)->getDoubleValue(b)); }
  using SGBinaryExpression<T>::getOperand;
};

template<typename T>
class SGSumExpression : public SGNaryExpression<T> {
public:
  SGSumExpression()
  { }
  SGSumExpression(SGExpression<T>* expr0, SGExpression<T>* expr1)
    : SGNaryExpression<T>(expr0, expr1)
  { }
  virtual void eval(T& value, const simgear::expression::Binding* b) const
  {
    value = T(0);
    size_t sz = SGNaryExpression<T>::getNumOperands();
    for (size_t i = 0; i < sz; ++i)
      value += getOperand(i)->getValue(b);
  }
  using SGNaryExpression<T>::getValue;
  using SGNaryExpression<T>::getOperand;
};

template<typename T>
class SGDifferenceExpression : public SGNaryExpression<T> {
public:
  SGDifferenceExpression()
  { }
  SGDifferenceExpression(SGExpression<T>* expr0, SGExpression<T>* expr1)
    : SGNaryExpression<T>(expr0, expr1)
  { }
  virtual void eval(T& value, const simgear::expression::Binding* b) const
  {
    value = getOperand(0)->getValue(b);
    size_t sz = SGNaryExpression<T>::getNumOperands();
    for (size_t i = 1; i < sz; ++i)
      value -= getOperand(i)->getValue(b);
  }
  using SGNaryExpression<T>::getValue;
  using SGNaryExpression<T>::getOperand;
};

template<typename T>
class SGProductExpression : public SGNaryExpression<T> {
public:
  SGProductExpression()
  { }
  SGProductExpression(SGExpression<T>* expr0, SGExpression<T>* expr1)
    : SGNaryExpression<T>(expr0, expr1)
  { }
  virtual void eval(T& value, const simgear::expression::Binding* b) const
  {
    value = T(1);
    size_t sz = SGNaryExpression<T>::getNumOperands();
    for (size_t i = 0; i < sz; ++i)
      value *= getOperand(i)->getValue(b);
  }
  using SGNaryExpression<T>::getValue;
  using SGNaryExpression<T>::getOperand;
};

template<typename T>
class SGMinExpression : public SGNaryExpression<T> {
public:
  SGMinExpression()
  { }
  SGMinExpression(SGExpression<T>* expr0, SGExpression<T>* expr1)
    : SGNaryExpression<T>(expr0, expr1)
  { }
  virtual void eval(T& value, const simgear::expression::Binding* b) const
  {
    size_t sz = SGNaryExpression<T>::getNumOperands();
    if (sz < 1)
      return;
    
    value = getOperand(0)->getValue(b);
    for (size_t i = 1; i < sz; ++i)
      value = SGMisc<T>::min(value, getOperand(i)->getValue(b));
  }
  using SGNaryExpression<T>::getOperand;
};

template<typename T>
class SGMaxExpression : public SGNaryExpression<T> {
public:
  SGMaxExpression()
  { }
  SGMaxExpression(SGExpression<T>* expr0, SGExpression<T>* expr1)
    : SGNaryExpression<T>(expr0, expr1)
  { }
  virtual void eval(T& value, const simgear::expression::Binding* b) const
  {
    size_t sz = SGNaryExpression<T>::getNumOperands();
    if (sz < 1)
      return;
    
    value = getOperand(0)->getValue(b);
    for (size_t i = 1; i < sz; ++i)
      value = SGMisc<T>::max(value, getOperand(i)->getValue(b));
  }
  using SGNaryExpression<T>::getOperand;
};

typedef SGExpression<int> SGExpressioni;
typedef SGExpression<float> SGExpressionf;
typedef SGExpression<double> SGExpressiond;
typedef SGExpression<bool> SGExpressionb;

typedef SGSharedPtr<SGExpressioni> SGExpressioni_ref;
typedef SGSharedPtr<SGExpressionf> SGExpressionf_ref;
typedef SGSharedPtr<SGExpressiond> SGExpressiond_ref;
typedef SGSharedPtr<SGExpressionb> SGExpressionb_ref;

/**
 * Global function to make an expression out of properties.

  <clip>
    <clipMin>0</clipMin>
    <clipMax>79</clipMax>
    <abs>
      <sum>
        <rad2deg>
          <property>sim/model/whatever-rad</property>
        </rad2deg>
        <property>sim/model/someother-deg</property>
        <value>-90</value>
      </sum>
    </abs>
  <clip>

will evaluate to an expression:

SGMisc<T>::clip(abs(deg2rad*sim/model/whatever-rad + sim/model/someother-deg - 90), clipMin, clipMax);

 */
SGExpression<int>*
SGReadIntExpression(SGPropertyNode *inputRoot,
                    const SGPropertyNode *configNode);

SGExpression<float>*
SGReadFloatExpression(SGPropertyNode *inputRoot,
                      const SGPropertyNode *configNode);

SGExpression<double>*
SGReadDoubleExpression(SGPropertyNode *inputRoot,
                       const SGPropertyNode *configNode);

SGExpression<bool>*
SGReadBoolExpression(SGPropertyNode *inputRoot,
                     const SGPropertyNode *configNode);

namespace simgear
{
  namespace expression
  {
  struct ParseError : public sg_exception
  {
      ParseError(const std::string& message = std::string())
          : sg_exception(message) {}
  };
    
  // Support for binding variables around an expression.
  class Binding
  {
  public:
      virtual ~Binding() {}
      const virtual Value* getBindings() const = 0;
      virtual Value* getBindings() = 0;
  };

  class VariableLengthBinding : public Binding
  {
  public:
      const Value* getBindings() const
      {
          if (_bindings.empty())
              return 0;
          else
              return &_bindings[0];
      }
      Value* getBindings()
      {
          if (_bindings.empty())
              return 0;
          else
              return &_bindings[0];
      }
      std::vector<Value> _bindings;
  };

  template<int Size> class FixedLengthBinding : public Binding
  {
  public:
      Value* getBindings()
      {
          return &_bindings[0];
      }
      const Value* getBindings() const
      {
          return &_bindings[0];
      }
      Value _bindings[Size];
  };

  struct VariableBinding
  {
      VariableBinding() : type(expression::DOUBLE), location(-1) {}

      VariableBinding(const std::string& name_, expression::Type type_,
                      int location_)
          : name(name_), type(type_), location(location_)
      {
      }
      std::string name;
      expression::Type type;
      int location;
  };

  class BindingLayout
  {
  public:
      size_t addBinding(const std::string& name, expression::Type type);
      bool findBinding(const std::string& name, VariableBinding& result) const;
      std::vector<VariableBinding> bindings;
  };

  class Parser {
  public:
      typedef Expression* (*exp_parser)(const SGPropertyNode* exp,
                                        Parser* parser);
      void addParser(const std::string& name, exp_parser parser)
      {
          getParserMap().insert(std::make_pair(name, parser));
      }
      Expression* read(const SGPropertyNode* exp)
      {
          ParserMap& map = getParserMap();
          ParserMap::iterator itr = map.find(exp->getName());
          if (itr == map.end())
              throw ParseError(std::string("unknown expression ") + exp->getName());
          exp_parser parser = itr->second;
          return (*parser)(exp, this);
      }
      // XXX vector of SGSharedPtr?
      bool readChildren(const SGPropertyNode* exp,
                        std::vector<Expression*>& result);
      /**
       * Function that parses a property tree, producing an expression.
       */
      typedef std::map<const std::string, exp_parser> ParserMap;
      virtual ParserMap& getParserMap() = 0;
      /**
       * After an expression is parsed, the binding layout may contain
       * references that need to be bound during evaluation.
       */
      BindingLayout& getBindingLayout() { return _bindingLayout; }
  protected:
      BindingLayout _bindingLayout;
  };

  class ExpressionParser : public Parser
  {
  public:
      ParserMap& getParserMap()
      {
          return ParserMapSingleton::instance()->_parserTable;
      }
      static void addExpParser(const std::string&, exp_parser);
  protected:
      struct ParserMapSingleton : public simgear::Singleton<ParserMapSingleton>
      {
          ParserMap _parserTable;
      };
  };

  /**
   * Constructor for registering parser functions.
   */
  struct ExpParserRegistrar
  {
      ExpParserRegistrar(const std::string& token, Parser::exp_parser parser)
      {
          ExpressionParser::addExpParser(token, parser);
      }
  };

  }

  /**
   * Access a variable definition. Use a location from a BindingLayout.
   */
  template<typename T>
  class VariableExpression : public ::SGExpression<T> {
  public:
    VariableExpression(int location) : _location(location) {}
    virtual ~VariableExpression() {}
    virtual void eval(T& value, const simgear::expression::Binding* b) const
    {
      const expression::Value* values = b->getBindings();
      value = *reinterpret_cast<const T *>(&values[_location].val);
    }
  protected:
    int _location;

  };

  /**
   * An n-ary expression where the types of the argument aren't the
   * same as the return type.
   */
  template<typename T, typename OpType>
  class GeneralNaryExpression : public ::SGExpression<T> {
  public:
    typedef OpType operand_type;
    size_t getNumOperands() const
    { return _expressions.size(); }
    const ::SGExpression<OpType>* getOperand(size_t i) const
    { return _expressions[i]; }
    ::SGExpression<OpType>* getOperand(size_t i)
    { return _expressions[i]; }
    size_t addOperand(::SGExpression<OpType>* expression)
    {
      if (!expression)
        return ~size_t(0);
      _expressions.push_back(expression);
      return _expressions.size() - 1;
    }
    
    template<typename Iter>
    void addOperands(Iter begin, Iter end)
    {
      for (Iter iter = begin; iter != end; ++iter)
        {
          addOperand(static_cast< ::SGExpression<OpType>*>(*iter));
        }
    }
    
    virtual bool isConst() const
    {
      for (size_t i = 0; i < _expressions.size(); ++i)
        if (!_expressions[i]->isConst())
          return false;
      return true;
    }
    virtual ::SGExpression<T>* simplify()
    {
      for (size_t i = 0; i < _expressions.size(); ++i)
        _expressions[i] = _expressions[i]->simplify();
      return SGExpression<T>::simplify();
    }

    simgear::expression::Type getOperandType() const
    {
      return simgear::expression::TypeTraits<OpType>::typeTag;
    }
    
  protected:
    GeneralNaryExpression()
    { }
    GeneralNaryExpression(::SGExpression<OpType>* expr0,
                          ::SGExpression<OpType>* expr1)
    { addOperand(expr0); addOperand(expr1); }

    std::vector<SGSharedPtr<SGExpression<OpType> > > _expressions;
  };

  /**
   * A predicate that wraps, for example the STL template predicate
   * expressions like std::equal_to.
   */
  template<typename OpType, template<typename PredOp> class Pred>
  class PredicateExpression : public GeneralNaryExpression<bool, OpType> {
  public:
    PredicateExpression()
    {
    }
    PredicateExpression(::SGExpression<OpType>* expr0,
                        ::SGExpression<OpType>* expr1)
      : GeneralNaryExpression<bool, OpType>(expr0, expr1)
    {
    }
    virtual void eval(bool& value, const simgear::expression::Binding* b) const
    {
      size_t sz = this->getNumOperands();
      if (sz != 2)
        return;
      value = _pred(this->getOperand(0)->getValue(b),
                    this->getOperand(1)->getValue(b));
    }
  protected:
    Pred<OpType> _pred;
  };

  template<template<typename OT> class Pred, typename OpType>
  PredicateExpression<OpType, Pred>*
  makePredicate(SGExpression<OpType>* op1, SGExpression<OpType>* op2)
  {
    return new PredicateExpression<OpType, Pred>(op1, op2);
  }
  
  template<typename OpType>
  class EqualToExpression : public PredicateExpression<OpType, std::equal_to>
  {
  public:
    EqualToExpression() {}
    EqualToExpression(::SGExpression<OpType>* expr0,
                      ::SGExpression<OpType>* expr1)
      : PredicateExpression<OpType, std::equal_to>(expr0, expr1)
    {
    }
  };

  template<typename OpType>
  class LessExpression : public PredicateExpression<OpType, std::less>
  {
  public:
    LessExpression() {}
    LessExpression(::SGExpression<OpType>* expr0, ::SGExpression<OpType>* expr1)
      : PredicateExpression<OpType, std::less>(expr0, expr1)
    {
    }
  };

  template<typename OpType>
  class LessEqualExpression
    : public PredicateExpression<OpType, std::less_equal>
  {
  public:
    LessEqualExpression() {}
    LessEqualExpression(::SGExpression<OpType>* expr0,
                        ::SGExpression<OpType>* expr1)
      : PredicateExpression<OpType, std::less_equal>(expr0, expr1)
    {
    }
  };

  class NotExpression : public ::SGUnaryExpression<bool>
  {
  public:
    NotExpression(::SGExpression<bool>* expr = 0)
      : ::SGUnaryExpression<bool>(expr)
    {
    }
    void eval(bool& value, const expression::Binding* b) const
    {
      value = !getOperand()->getValue(b);
    }
  };

  class OrExpression : public ::SGNaryExpression<bool>
  {
  public:
    void eval(bool& value, const expression::Binding* b) const
    {
      value = false;
      for (int i = 0; i < (int)getNumOperands(); ++i) {
        value = value || getOperand(i)->getValue(b);
        if (value)
          return;
      }
    }
  };

  class AndExpression : public ::SGNaryExpression<bool>
  {
  public:
    void eval(bool& value, const expression::Binding* b) const
    {
      value = true;
      for (int i = 0; i < (int)getNumOperands(); ++i) {
        value = value && getOperand(i)->getValue(b);
        if (!value)
          return;
      }
    }
  };

  /**
   * Convert an operand from OpType to T.
   */
  template<typename T, typename OpType>
  class ConvertExpression : public GeneralNaryExpression<T, OpType>
  {
  public:
    ConvertExpression() {}
    ConvertExpression(::SGExpression<OpType>* expr0)
    {
      this->addOperand(expr0);
    }
    virtual void eval(T& value, const simgear::expression::Binding* b) const
    {
      typename ConvertExpression::operand_type result;
      this->_expressions.at(0)->eval(result, b);
      value = result;
    }
  };
}
#endif // _SG_EXPRESSION_HXX
