/***************************************************************************
**
**  This file is part of QGpCoreTools.
**
**  This library is free software; you can redistribute it and/or
**  modify it under the terms of the GNU Lesser General Public
**  License as published by the Free Software Foundation; either
**  version 2.1 of the License, or (at your option) any later version.
**
**  This file 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 Lesser General Public
**  License for more details.
**
**  You should have received a copy of the GNU Lesser General Public
**  License along with this library; if not, write to the Free Software
**  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
**
**  See http://www.geopsy.org for more information.
**
**  Created: 2007-04-10
**  Copyright: 2007-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#ifndef EXPRESSIONACTION_H
#define EXPRESSIONACTION_H


#include "XMLClass.h"
#include "ExpressionStorage.h"
#include "ExpressionContext.h"
#include "Global.h"
#include "QGpCoreToolsDLLExport.h"

namespace QGpCoreTools {

class ExpressionContext;

class QGPCORETOOLS_EXPORT ExpressionAction : public XMLClass
{
  TRANSLATIONS("ExpressionAction")
public:
  enum Type {NoOperator, Assign, Sum, SumAssign, Subtract, SubtractAssign, Mult, MultAssign, FloatDiv,
             FloatDivAssign, IntMod, IntDiv, Coma, OpenBracket, CloseBracket, EndAction, Function, Equal,
             NotEqual, GreaterThan, GreaterOrEqual, LessThan, LessOrEqual, OpenSquareBracket, CloseSquareBracket,
             VariableArray};
  ExpressionAction() {_parent=0;}
  virtual ~ExpressionAction() {}

  virtual const QString& xml_tagName() const {return xmlExpressionActionTag;}
  static const QString xmlExpressionActionTag;

  virtual bool isReadOnly() const {return true;}
  virtual QVariant value() const=0;
  virtual void setValue(const QVariant& ) {}

  virtual int priority() const {return 4;}
  virtual ExpressionAction * parent() const {return _parent;}
  void setParent(ExpressionAction * p) {_parent=p;}
  ExpressionAction * superParent();
  virtual ExpressionAction * close(ExpressionAction::Type t);

  bool addAction(ExpressionAction * a);
  virtual bool addArgument(ExpressionAction * a)=0;
  virtual void replaceArgument(ExpressionAction * oldA, ExpressionAction * newA)=0;
protected:
  static QVariant sum(const QVariant& op1, const QVariant& op2);
  static QVariant subtract(const QVariant& op1, const QVariant& op2);
  static QVariant mult(const QVariant& op1, const QVariant& op2);
  static QVariant floatDiv(const QVariant& op1, const QVariant& op2);
  static int compare(const QVariant& op1, const QVariant& op2, bool& ok);

  ExpressionAction * _parent;
protected:
  //virtual XMLMember xml_member(XML_MEMBER_ARGS);
};

class QGPCORETOOLS_EXPORT ExpressionVariable : public ExpressionAction
{
public:
  ExpressionVariable(QString name, ExpressionContext * c);
  ~ExpressionVariable() {delete _index;}

  virtual const QString& xml_tagName() const {return xmlExpressionVariableTag;}
  static const QString xmlExpressionVariableTag;

  virtual ExpressionAction * parent() const {if(_open) return 0; else return _parent;}
  virtual bool isReadOnly() const;
  virtual QVariant value() const;
  virtual void setValue(const QVariant& val);
  virtual bool addArgument(ExpressionAction * a);
  virtual void replaceArgument(ExpressionAction *, ExpressionAction *);
  virtual ExpressionAction * close(Type t);
protected:
  virtual void xml_writeProperties(XML_WRITEPROPERTIES_ARGS) const;
  virtual void xml_writeChildren(XML_WRITECHILDREN_ARGS) const;
  //virtual bool xml_setProperty(XML_SETPROPERTY_ARGS);
private:
  ExpressionAction * _index;
  ExpressionContext * _context;
  bool _open;
  int _varIndex;
};

class QGPCORETOOLS_EXPORT ExpressionValue : public ExpressionAction
{
public:
  ExpressionValue(QVariant val) {_val=val;}

  virtual const QString& xml_tagName() const {return xmlExpressionValueTag;}
  static const QString xmlExpressionValueTag;

  virtual QVariant value() const {return _val;}
  virtual bool addArgument(ExpressionAction *) {return false;}
  virtual void replaceArgument(ExpressionAction *, ExpressionAction *) {ASSERT(false);}
private:
  QVariant _val;
protected:
  virtual void xml_writeProperties(XML_WRITEPROPERTIES_ARGS) const;
  //virtual bool xml_setProperty(XML_SETPROPERTY_ARGS);
};

class QGPCORETOOLS_EXPORT ExpressionBracket : public ExpressionAction
{
public:
  ExpressionBracket() {_open=true; _arg=0;}
  ~ExpressionBracket() {delete _arg;}

  virtual const QString& xml_tagName() const {return xmlExpressionBracketTag;}
  static const QString xmlExpressionBracketTag;

  virtual ExpressionAction * parent() const {if(_open) return 0; else return _parent;}
  virtual bool isReadOnly() const {return _arg->isReadOnly();}
  virtual QVariant value() const {return _arg ? _arg->value() : QVariant();}
  virtual ExpressionAction * close(Type t);
  virtual bool addArgument(ExpressionAction *);
  virtual void replaceArgument(ExpressionAction * oldA, ExpressionAction * newA);
private:
  ExpressionAction * _arg;
  bool _open;
protected:
  virtual void xml_writeChildren(XML_WRITECHILDREN_ARGS) const;
  virtual void xml_writeProperties(XML_WRITEPROPERTIES_ARGS) const;
  //virtual bool xml_setProperty(XML_SETPROPERTY_ARGS);
};

class QGPCORETOOLS_EXPORT ExpressionOperator : public ExpressionAction
{
public:
  ExpressionOperator(Type type) {_type=type;_operand1=0;_operand2=0;}
  virtual ~ExpressionOperator() {delete _operand1; delete _operand2;}

  virtual const QString& xml_tagName() const {return xmlExpressionOperatorTag;}
  static const QString xmlExpressionOperatorTag;

  virtual QVariant value() const;
  virtual int priority() const {
    switch (_type) {
    case Mult:
    case FloatDiv:
    case IntMod:
    case IntDiv:
      return 3;
    case Sum:
    case Subtract:
      return 2;
    default:
      return 1;
    }
  }
  virtual bool addArgument(ExpressionAction * a);
  virtual void replaceArgument(ExpressionAction * oldA, ExpressionAction * newA);
private:
  Type _type;
  ExpressionAction * _operand1;
  ExpressionAction * _operand2;
protected:
  virtual void xml_writeChildren(XML_WRITECHILDREN_ARGS) const;
  virtual void xml_writeProperties(XML_WRITEPROPERTIES_ARGS) const;
  //virtual bool xml_setProperty(XML_SETPROPERTY_ARGS);
};

class QGPCORETOOLS_EXPORT ExpressionFunction : public ExpressionAction
{
public:
  ExpressionFunction(QString name, ExpressionContext * context) {_name=name; _open=true; _currentArg=0; _context=context;}
  virtual ~ExpressionFunction() {qDeleteAll(_args);}

  virtual const QString& xml_tagName() const {return xmlExpressionFunctionTag;}
  static const QString xmlExpressionFunctionTag;

  virtual ExpressionAction * parent() const {if(_open) return 0; else return _parent;}
  virtual QVariant value() const {return _context->functionValue(_name, _args);}
  virtual bool addArgument(ExpressionAction * a);
  virtual void replaceArgument(ExpressionAction * oldA, ExpressionAction * newA);
  virtual ExpressionAction * close(Type t);
private:
  bool _open;
  QString _name;
  ExpressionAction * _currentArg;
  QVector<ExpressionAction *> _args;
  ExpressionContext * _context;
protected:
  virtual void xml_writeChildren(XML_WRITECHILDREN_ARGS) const;
  virtual void xml_writeProperties(XML_WRITEPROPERTIES_ARGS) const;
  //virtual bool xml_setProperty(XML_SETPROPERTY_ARGS);
};

} // namespace QGpCoreTools

#endif // EXPRESSIONACTION_H
