#ifndef NODO_HPP
#define NODO_HPP

#include <cstdlib>
#include <string>
#include <sstream>
#include <iostream>

using namespace std;

class Nodo {
	protected:
		enum { NUM, VARX, ADD, SUB, CHS, MUL, DIV, MOD, POW };
	public:
		Nodo(void) {	};
		virtual int    type(void)  const = 0;
		virtual Nodo*  copy(void)  const = 0;
		virtual string print(void) const = 0;
		virtual double eval(double)  const = 0;
		virtual Nodo*  deriv(void)  const = 0;
};

class Const : public Nodo {
	private:
		double val;
	public:
		Const(double v);
		virtual int    type(void) const { return NUM; };
		virtual Nodo*  copy(void)  const;
		virtual string print(void) const;
		virtual double eval(double) const;
		virtual Nodo*  deriv(void) const;
};

class VarX : public Nodo {
	public:
		VarX(void);
		virtual int    type(void) const { return VARX; };
		virtual Nodo*  copy(void)  const;
		virtual string print(void) const;
		virtual double eval(double) const;
		virtual Nodo*  deriv(void) const;
};

class OpBin : public Nodo {
	protected:
		Nodo *izq, *der;
	public:
		OpBin(Nodo *i, Nodo *d);
		virtual int    type(void) const = 0;
		virtual Nodo*  copy(void)  const = 0;
		virtual string print(void) const = 0;
		virtual double eval(double) const = 0;	
		virtual Nodo*  deriv(void) const = 0;
		Nodo *Lft(void) const { return izq; };
		Nodo *Rgt(void) const { return der; };
};

class Add : public OpBin {
	public:
		Add(Nodo *i, Nodo *d);
		virtual int    type(void) const { return ADD; };
		virtual Nodo*  copy(void) const;
		virtual string print(void) const;
		virtual double eval(double) const;	
		virtual Nodo*  deriv(void) const;
};

class Sub : public OpBin {
	public:
		Sub(Nodo *i, Nodo *d);
		virtual int    type(void) const { return SUB; };
		virtual Nodo*  copy(void) const;
		virtual string print(void) const;
		virtual double eval(double) const;	
		virtual Nodo*  deriv(void) const;
};

class Mul : public OpBin {
	public:
		Mul(Nodo *i, Nodo *d);
		virtual int    type(void) const { return MUL; };
		virtual Nodo*  copy(void) const;
		virtual string print(void) const;
		virtual double eval(double) const;	
		virtual Nodo*  deriv(void) const;
};

class Div : public OpBin {
	public:
		Div(Nodo *i, Nodo *d);
		virtual int    type(void) const { return DIV; };
		virtual Nodo*  copy(void) const;
		virtual string print(void) const;
		virtual double eval(double) const;	
		virtual Nodo*  deriv(void) const;
};

class Mod : public OpBin {
	public:
		Mod(Nodo *i, Nodo *d);
		virtual int    type(void) const { return MOD; };
		virtual Nodo*  copy(void) const;
		virtual string print(void) const;
		virtual double eval(double) const;	
		virtual Nodo*  deriv(void) const;
};

class Pow : public OpBin {
	public:
		Pow(Nodo *i, Nodo *d);
		virtual int    type(void) const { return POW; };
		virtual Nodo*  copy(void) const;
		virtual string print(void) const;
		virtual double eval(double) const;	
		virtual Nodo*  deriv(void) const;
};

class Chs : public Nodo {
	private:
		Nodo *der;
	public:
		Chs( Nodo *d);
		virtual int    type(void) const { return CHS; };
		virtual Nodo*  copy(void) const;
		Nodo *Rgt(void) const { return der; };
		virtual string print(void) const;
		virtual double eval(double) const;
		virtual Nodo*  deriv(void) const;
};

#endif
