#ifndef mpfitAST_H
#define mpfitAST_H

#include <cstdlib>
#include <string>
#include <map>
#include "dpstringlist.h"

class mpfitASTNode;

extern std::map<std::string, double> mpfit_vars;
extern double mpfit_quick_vars[256];
extern mpfitASTNode *mpfitAST;
extern std::map<std::string, int> mpfitAST_dummy;
extern dpStringList mpfit_sorted_variables;
int main_mpfit(std::string);
void mpfiterror(const char *);
void initialize_mpfit_functions(void);

class mpfitASTNode {
public:
   double      Value;
 
   mpfitASTNode() { Value = 0; }
   ~mpfitASTNode() { }
   virtual double evaluate() = 0;
};

extern mpfitASTNode *mpfitAST;

class mpfitnumberNode : public mpfitASTNode {
public:
  mpfitnumberNode(double value) { Value = value; }
	double evaluate() { return Value; }
};

class mpfitunaryMinusNode : public mpfitASTNode {
public:
  mpfitunaryMinusNode(mpfitASTNode *left) : exp(left) { }
  ~mpfitunaryMinusNode() { delete exp; }
	mpfitASTNode *exp;
	double evaluate();
};

class mpfitvariableNode : public mpfitASTNode {
public:
  std::string id;
  char first_character;
  bool onechar;
    mpfitvariableNode(std::string value);
	double evaluate();
};

class mpfitfunctionNode : public mpfitASTNode {
public:
  int id;
	mpfitASTNode *arg;
    mpfitfunctionNode(std::string func, mpfitASTNode *exp);
  ~mpfitfunctionNode() { delete arg; }
	double evaluate();
};

class mpfitfunctionNode2 : public mpfitASTNode {
public:
  int id;
    mpfitASTNode *arg1, *arg2;
    mpfitfunctionNode2(std::string func, mpfitASTNode *exp, mpfitASTNode *exp2);
  ~mpfitfunctionNode2() { delete arg1; delete arg2; }
    double evaluate();
};

class mpfitfunctionNode3 : public mpfitASTNode {
public:
  int id;
    mpfitASTNode *arg1, *arg2, *arg3;
    mpfitfunctionNode3(std::string func, mpfitASTNode *exp, mpfitASTNode *exp2, mpfitASTNode *exp3);
  ~mpfitfunctionNode3() { delete arg1; delete arg2; delete arg3; }
    double evaluate();
};

class mpfitoperator_node : public mpfitASTNode {
public:
    mpfitoperator_node(mpfitASTNode *L, mpfitASTNode *R) : left(L), right(R) { }
    ~mpfitoperator_node() { delete left; delete right; }
    mpfitASTNode *left;
    mpfitASTNode *right;
};

class mpfitplusNode : public mpfitoperator_node {
public:
  mpfitplusNode(mpfitASTNode *L, mpfitASTNode *R) : mpfitoperator_node(L, R) { }
	double evaluate();
};

class mpfitminusNode : public mpfitoperator_node {
public:
  mpfitminusNode(mpfitASTNode *L, mpfitASTNode *R) : mpfitoperator_node(L, R) { }
	double evaluate();
};

class mpfitmultiplyNode : public mpfitoperator_node {
public:
  mpfitmultiplyNode(mpfitASTNode *L, mpfitASTNode *R) : mpfitoperator_node(L, R) { }
	double evaluate();
};

class mpfitdivideNode : public mpfitoperator_node {
public:
  mpfitdivideNode(mpfitASTNode *L, mpfitASTNode *R) : mpfitoperator_node(L, R) { }
	double evaluate();
};

class mpfitpowerNode : public mpfitoperator_node {
public:
  mpfitpowerNode(mpfitASTNode *L, mpfitASTNode *R) : mpfitoperator_node(L, R) { }
	double evaluate();
};

class mpfitassignmentNode {
public:
  std::string id;
	mpfitASTNode *exp;
	mpfitassignmentNode(std::string name, mpfitASTNode *node) : id(name), exp(node) { }
  ~mpfitassignmentNode() { delete exp; }
    void evaluate() { double result = exp->evaluate(); mpfit_vars[id] = result; }
};

#endif /* mpfitAST_H */
