/*------------------------------------------------------------------*/
/* calcul.h :   Fichier contenant les définitions des classes qui   */
/*              serviront à calculer l'expression mathématique.     */
/* On part avec une classe de base type_valeur.  De cette classe    */
/* sont dérivées d'autres classes.  Tout d'abord, la classe         */
/* type_opération, de laquelle seront dérivées toutes les classes   */
/* des opérations mathématiques.  Aussi, de type_valeur sont        */
/* dérivées les classes type_variable et type_nombre.               */
/*                                                                  */
/* Le principe est que l'objet de type type_formule contient un     */
/* pointeur vers une valeur qui contient la différence entre le     */
/* côté droit et le côté gauche de l'équation.  Chaque classe       */
/* contient la fonction Compute(), qui retourne la valeur de        */
/* l'objet.  Pour les opérations, elle retourne la valeur de        */
/* l'opération (par exemple l'addition) sur ses opérandes           */
/* (représentés par deux pointeurs).  Pour les nombres ou les       */
/* variables, la valeur retournée est tout simplement la valeur du  */
/* nombre ou celle de x, y ou z.                                    */
/*------------------------------------------------------------------*/

#ifndef CALCUL2_H
#define CALCUL2_H

double EvalDer(int Indice, double x);

// Classe de base de toutes les clasees

class type_valeur
{
public:
	virtual double Compute(double x) const = 0;
	virtual ~type_valeur() {};
};

class type_operation : public type_valeur
{
public:
	type_valeur* Gauche;
	type_valeur* Droite;

	type_operation(type_valeur* Left, type_valeur* Right)
	{ Gauche = Left; Droite = Right; }
	virtual double Compute(double x) const = 0;
	virtual ~type_operation() {};
};

// Classes de toutes les opérations

	// +
	class type_add : public type_operation
	{
	public:
		virtual double Compute(double x) const
		{return (Gauche->Compute(x) + Droite->Compute(x));}

		type_add(type_valeur* LaGauche, type_valeur* LaDroite)
			: type_operation(LaGauche, LaDroite) {}
		virtual ~type_add() { delete Gauche; delete Droite; }
	};

	// -
	class type_sub : public type_operation
	{
	public:
		virtual double Compute(double x) const
		{return (Gauche->Compute(x) - Droite->Compute(x));}

		type_sub(type_valeur* LaGauche, type_valeur* LaDroite)
			: type_operation(LaGauche, LaDroite) {}
		virtual ~type_sub() { delete Gauche; delete Droite; }
	};

	// *
	class type_prod : public type_operation
	{
	public:
		virtual double Compute(double x) const
		{ return (Gauche->Compute(x) * Droite->Compute(x)); }

		type_prod(type_valeur* LaGauche, type_valeur* LaDroite)
			: type_operation(LaGauche, LaDroite) {}
		virtual ~type_prod() { delete Gauche; delete Droite; }
	};

	// /
	class type_div : public type_operation
	{
	public:
		virtual double Compute(double x) const
		{	
			double Temp = Droite->Compute(x);
			if (Temp == 0)
				throw;
			return (Gauche->Compute(x) / Temp);
		}
		
		type_div(type_valeur* LaGauche, type_valeur* LaDroite)
			: type_operation(LaGauche, LaDroite) {}
		virtual ~type_div() { delete Gauche; delete Droite; }
	};

	// sqrt
	class type_sqrt : public type_operation
	{
	public:
		virtual double Compute(double x) const
		{
			double Temp = Gauche->Compute(x);
			if (Temp < 0)
				throw;
			return (sqrt(Temp));
		}

		type_sqrt(type_valeur* LaGauche, type_valeur* LaDroite = 0)
			: type_operation(LaGauche, LaDroite) {}
		virtual ~type_sqrt() { delete Gauche; }
	};

	// sin
	class type_sin : public type_operation
	{
	public:
		virtual double Compute(double x) const
		{ return (sin(Gauche->Compute(x))); }
		type_sin(type_valeur* LaGauche, type_valeur* LaDroite = 0)
			: type_operation(LaGauche, LaDroite) {}
		virtual ~type_sin() { delete Gauche; }
	};

	// cos
	class type_cos : public type_operation
	{
	public:
		virtual double Compute(double x) const { return (cos(Gauche->Compute(x))); }
		type_cos(type_valeur* LaGauche, type_valeur* LaDroite = 0)
			: type_operation(LaGauche, LaDroite) {}
		virtual ~type_cos() { delete Gauche; }
	};

	// tan
	class type_tan : public type_operation
	{
	public:
		virtual double Compute(double x) const { return (tan(Gauche->Compute(x))); }
		type_tan(type_valeur* LaGauche, type_valeur* LaDroite = 0)
			: type_operation(LaGauche, LaDroite) {}
		virtual ~type_tan() { delete Gauche; }
	};

	// exp
	class type_exp : public type_operation
	{
	public:
		virtual double Compute(double x) const { return (exp(Gauche->Compute(x))); }
		type_exp(type_valeur* LaGauche, type_valeur* LaDroite = 0)
			: type_operation(LaGauche, LaDroite) {}
		virtual ~type_exp() { delete Gauche; }
	};

	// pow
	class type_pow : public type_operation
	{
	public:
		virtual double Compute(double x) const
		{return (pow(Gauche->Compute(x), Droite->Compute(x)));}

		type_pow(type_valeur* LaGauche, type_valeur* LaDroite)
			: type_operation(LaGauche, LaDroite) {}
		virtual ~type_pow() { delete Gauche; delete Droite; }
	};

// variable
class type_variable : public type_valeur
{
public:
	unsigned char Type;

	virtual double Compute(double x) const
	{
		if (Type)
			return EvalDer(Type - 1, x);
		else
			return x;
	}
	
	type_variable(unsigned LeType) { Type = LeType; }
	virtual ~type_variable() {}
};

// nombre
class type_nombre : public type_valeur
{
public:
	double Nombre;

	virtual double Compute(double x) const { return Nombre; }
	type_nombre(double LeNombre) { Nombre = LeNombre; }
	virtual ~type_nombre() {}
};



// Classe contenant la formule

class type_formule
{
	type_valeur* Formule;

public:
	type_formule(const std::string& Equation);
	double Valeur(double x) const { return (Formule->Compute(x)); }
	~type_formule() { delete Formule; }
};
	
#endif