/*
* 26/11/2006 - 17:02
*
* GraphMonkey - mono based graphing calculator
* Copyright (C) 2006 Lounis Bellabes
* nolius@users.sourceforge.net
*
* 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 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

using System;
	

public class operation : object{
	public string phrase;
	public string operateur;
	public operation droite;
	public operation gauche;

	public operation(string phrase) {
		this.phrase=phrase;			
	}
		
	public void decouper(){
		//search a + (the more at rigth) not in Bracket
		int position_plus=this.phrase.LastIndexOf("+");
		bool trouver_bon_plus = false;
		while (position_plus != -1 && trouver_bon_plus==false ){
			if (this.compte_jusqua("(", position_plus) != this.compte_jusqua(")", position_plus) ){
				position_plus = this.phrase.LastIndexOf("+", position_plus-1, position_plus);
			}
			else{
				trouver_bon_plus = true;
			}
		}
		if (trouver_bon_plus == false){
			position_plus = -1;
		}
		
		//search a - (the more at rigth) not in Bracket
		int position_moin=this.phrase.LastIndexOf("-");
		bool trouver_bon_moin = false;
		while (position_moin != -1 && trouver_bon_moin==false ){
			if (this.compte_jusqua("(", position_moin) != this.compte_jusqua(")", position_moin) ){
				position_moin = this.phrase.LastIndexOf("-", position_moin-1, position_moin);
			}
			else{
				trouver_bon_moin = true;
			}
		}
		if (trouver_bon_moin == false){
			position_moin = -1;
		}
			
		// priority for + and -
			
		// initially  a +
		if ( (position_plus!=-1 && position_moin==-1) || (position_plus!=-1 && position_moin!=-1 && position_plus>position_moin) ){
			this.operateur = "+";
			
			string phrase_gauche=this.phrase;
			phrase_gauche = phrase_gauche.Remove(position_plus,phrase_gauche.Length-position_plus);	
			this.gauche = new operation(phrase_gauche);
			
			string phrase_droite=this.phrase;
			phrase_droite = phrase_droite.Remove(0,position_plus+1);
			this.droite = new operation(phrase_droite);				
		}
		// initially  a -
		else if ( (position_plus==-1 && position_moin!=-1) || (position_plus!=-1 && position_moin!=-1 && position_moin>position_plus) ){
			this.operateur = "-";
			
			string phrase_gauche=this.phrase;
			phrase_gauche = phrase_gauche.Remove(position_moin,phrase_gauche.Length-position_moin);	
			this.gauche = new operation(phrase_gauche);
			
			string phrase_droite=this.phrase;
			phrase_droite = phrase_droite.Remove(0,position_moin+1);
			this.droite = new operation(phrase_droite);	
	
		}
			
			// now * et /
		else {
			//search a * (the more at rigth) not in Bracket
			int position_multiplier=this.phrase.LastIndexOf("*");
			bool trouver_bon_multiplier = false;
			while (position_multiplier != -1 && trouver_bon_multiplier==false ){
				if (this.compte_jusqua("(", position_multiplier) != this.compte_jusqua(")", position_multiplier) ){
					position_multiplier = this.phrase.LastIndexOf("*", position_multiplier-1, position_multiplier);
				}
				else{
					trouver_bon_multiplier = true;
				}
			}
			if (trouver_bon_multiplier == false){
				position_multiplier= -1;
			}
				
			//search a / (the more at rigth) not in Bracket
			int position_diviser=this.phrase.LastIndexOf("/");
			bool trouver_bon_diviser = false;
			while (position_diviser != -1 && trouver_bon_diviser==false ){
				if (this.compte_jusqua("(", position_diviser) != this.compte_jusqua(")", position_diviser) ){
					position_diviser = this.phrase.LastIndexOf("/", position_diviser-1, position_diviser);
				}
				else{
					trouver_bon_diviser = true;
				}
			}				
			if (trouver_bon_diviser == false){
				position_diviser= -1;
			}				
			
			
			// initially  a *
			if ( (position_multiplier!=-1 && position_diviser==-1) || (position_multiplier!=-1 && position_diviser!=-1 && position_multiplier>position_diviser) ){ // initially  a *
				this.operateur = "*";
					
				string phrase_gauche=this.phrase;
				phrase_gauche = phrase_gauche.Remove(position_multiplier,phrase_gauche.Length-position_multiplier);	
				this.gauche = new operation(phrase_gauche);
				
				string phrase_droite=this.phrase;
				phrase_droite = phrase_droite.Remove(0,position_multiplier+1);
				this.droite = new operation(phrase_droite);				
			}
			// initially  a /
			else if ( (position_multiplier==-1 && position_diviser!=-1) || (position_multiplier!=-1 && position_diviser!=-1 && position_diviser>position_multiplier) ){	// initially  a /
				this.operateur = "/";
				
				string phrase_gauche=this.phrase;
				phrase_gauche = phrase_gauche.Remove(position_diviser,phrase_gauche.Length-position_diviser);	
				this.gauche = new operation(phrase_gauche);
				
				string phrase_droite=this.phrase;
				phrase_droite = phrase_droite.Remove(0,position_diviser+1);
				this.droite = new operation(phrase_droite);	
		
			}
			
			// now ^
			else{
				//search a ^ (the more at rigth) not in Bracket
				int position_puissance=this.phrase.IndexOf("^");
				bool trouver_bon_puissance = false;
				while (position_puissance != -1 && trouver_bon_puissance==false ){
					if (this.compte_jusqua("(", position_puissance) != this.compte_jusqua(")", position_puissance) ){
						position_puissance = this.phrase.IndexOf("^", position_puissance+1);
					}
					else{
						trouver_bon_puissance = true;
					}
				}
				if (trouver_bon_puissance == false){					
					position_puissance= -1;
				}				
							
				if ( (position_puissance!=-1) ){	// there is a ^
					this.operateur = "^";
				
					string phrase_gauche=this.phrase;
					phrase_gauche = phrase_gauche.Remove(position_puissance,phrase_gauche.Length-position_puissance);	
					this.gauche = new operation(phrase_gauche);
				
					string phrase_droite=this.phrase;
					phrase_droite = phrase_droite.Remove(0,position_puissance+1);
					this.droite = new operation(phrase_droite);				
				}				
				else{ // there is no + - / * or ^ so phrase is like "(2+x-3)" or "2" or "x" or r(2*x)...
							
					//if phrase is in bracket (2+x-3), delete bracket
					if (this.phrase.StartsWith("(")){
						this.operateur="()";
					
						string phrase_gauche=this.phrase;
						phrase_gauche = phrase_gauche.Remove(0,1);	//delete "(" in beginning 
						phrase_gauche = phrase_gauche.Remove(phrase_gauche.Length-1,1);		//delete ")" in end		
						this.gauche = new operation(phrase_gauche);
					}
					else if (this.phrase.StartsWith("sqrt(")){	// root square
						this.operateur = "sqrt()";
						
						string phrase_gauche = this.phrase;
						phrase_gauche = phrase_gauche.Remove(0,5);	//delete "sqrt(" in beginning
						phrase_gauche = phrase_gauche.Remove(phrase_gauche.Length-1,1);		//delete ")" in end				
						this.gauche = new operation(phrase_gauche);
					}
					else if (this.phrase.StartsWith("cos(")){	// cos
						this.operateur = "cos()";
						
						string phrase_gauche = this.phrase;
						phrase_gauche = phrase_gauche.Remove(0,4);	//delete "cos(" in beginning
						phrase_gauche = phrase_gauche.Remove(phrase_gauche.Length-1,1);		//delete ")" in end				
						this.gauche = new operation(phrase_gauche);
					}
					else if (this.phrase.StartsWith("sin(")){	// sin
						this.operateur = "sin()";
						
						string phrase_gauche = this.phrase;
						phrase_gauche = phrase_gauche.Remove(0,4);	//delete "sin(" in beginning
						phrase_gauche = phrase_gauche.Remove(phrase_gauche.Length-1,1);		//delete ")" in end				
						this.gauche = new operation(phrase_gauche);
					}
					else if (this.phrase.StartsWith("tan(")){	// tan
						this.operateur = "tan()";
						
						string phrase_gauche = this.phrase;
						phrase_gauche = phrase_gauche.Remove(0,4);	//delete "tan(" in beginning
						phrase_gauche = phrase_gauche.Remove(phrase_gauche.Length-1,1);		//delete ")" in end				
						this.gauche = new operation(phrase_gauche);
					}
					else if (this.phrase.StartsWith("ln(")){	// ln
						this.operateur = "ln()";
						
						string phrase_gauche = this.phrase;
						phrase_gauche = phrase_gauche.Remove(0,3);	//delete "ln(" in beginning
						phrase_gauche = phrase_gauche.Remove(phrase_gauche.Length-1,1);		//delete ")" in end				
						this.gauche = new operation(phrase_gauche);
					}
					else if (this.phrase.StartsWith("log(")){	// log
						this.operateur = "log()";
						
						string phrase_gauche = this.phrase;
						phrase_gauche = phrase_gauche.Remove(0,4);	//delete "log(" in beginning
						phrase_gauche = phrase_gauche.Remove(phrase_gauche.Length-1,1);		//delete ")" in end				
						this.gauche = new operation(phrase_gauche);
					}
					else if (this.phrase.StartsWith("acos(")){	// acos
						this.operateur = "acos()";
						
						string phrase_gauche = this.phrase;
						phrase_gauche = phrase_gauche.Remove(0,5);	//delete "acos(" in beginningt
						phrase_gauche = phrase_gauche.Remove(phrase_gauche.Length-1,1);		//delete ")" in end				
						this.gauche = new operation(phrase_gauche);
					}
					else if (this.phrase.StartsWith("asin(")){	// asin
						this.operateur = "asin()";
						
						string phrase_gauche = this.phrase;
						phrase_gauche = phrase_gauche.Remove(0,5);	//delete "asin(" in beginning
						phrase_gauche = phrase_gauche.Remove(phrase_gauche.Length-1,1);		//delete ")" in end				
						this.gauche = new operation(phrase_gauche);
					}
					else if (this.phrase.StartsWith("atan(")){	// atan
						this.operateur = "atan()";
						
						string phrase_gauche = this.phrase;
						phrase_gauche = phrase_gauche.Remove(0,5);	//delete "atan(" in beginning
						phrase_gauche = phrase_gauche.Remove(phrase_gauche.Length-1,1);		//on supprime le ")" de la fin				
						this.gauche = new operation(phrase_gauche);
					}
					else if (this.phrase.StartsWith("cosh(")){	// cosh
						this.operateur = "cosh()";
						
						string phrase_gauche = this.phrase;
						phrase_gauche = phrase_gauche.Remove(0,5);	//delete "cosh(" in beginning
						phrase_gauche = phrase_gauche.Remove(phrase_gauche.Length-1,1);		//delete ")" in end				
						this.gauche = new operation(phrase_gauche);
					}
					else if (this.phrase.StartsWith("sinh(")){	// sinh
						this.operateur = "sinh()";
						
						string phrase_gauche = this.phrase;
						phrase_gauche = phrase_gauche.Remove(0,5);	//delete "sinh(" in beginning
						phrase_gauche = phrase_gauche.Remove(phrase_gauche.Length-1,1);		//delete ")" in end				
						this.gauche = new operation(phrase_gauche);
					}
					else if (this.phrase.StartsWith("tanh(")){	// tanh
						this.operateur = "tanh()";
						
						string phrase_gauche = this.phrase;
						phrase_gauche = phrase_gauche.Remove(0,5);	//delete "tanh(" in beginning
						phrase_gauche = phrase_gauche.Remove(phrase_gauche.Length-1,1);		//delete ")" in end				
						this.gauche = new operation(phrase_gauche);
					}
					else if (this.phrase.StartsWith("exp(")){	// exp
						this.operateur = "exp()";
						
						string phrase_gauche = this.phrase;
						phrase_gauche = phrase_gauche.Remove(0,4);	//delete "exp(" in beginning
						phrase_gauche = phrase_gauche.Remove(phrase_gauche.Length-1,1);		//delete ")" in end				
						this.gauche = new operation(phrase_gauche);
					}
					else if (this.phrase.StartsWith("abs(")){	// abs
						this.operateur = "abs()";
						
						string phrase_gauche = this.phrase;
						phrase_gauche = phrase_gauche.Remove(0,4);	//delete "abs(" in beginning
						phrase_gauche = phrase_gauche.Remove(phrase_gauche.Length-1,1);		//delete ")" in end				
						this.gauche = new operation(phrase_gauche);
					}
					else if (this.phrase.StartsWith("int(")){	// int
						this.operateur = "int()";
						
						string phrase_gauche = this.phrase;
						phrase_gauche = phrase_gauche.Remove(0,4);	//delete "int(" in beginning
						phrase_gauche = phrase_gauche.Remove(phrase_gauche.Length-1,1);		//delete ")" in end				
						this.gauche = new operation(phrase_gauche);
					}
				}
			}
		}
	}
		
		
	public void corrige(){
		if (this.phrase.StartsWith("-")){
			this.phrase = this.phrase.Insert(0, "0");
		}
		
		this.phrase = this.phrase.Replace("X", "x");
		
		this.phrase = this.phrase.Replace("(-", "(0-");
		
		this.phrase = this.phrase.Replace("x(", "x*(");
		this.phrase = this.phrase.Replace("0(", "0*(");
		this.phrase = this.phrase.Replace("1(", "1*(");
		this.phrase = this.phrase.Replace("2(", "2*(");
		this.phrase = this.phrase.Replace("3(", "3*(");
		this.phrase = this.phrase.Replace("4(", "4*(");
		this.phrase = this.phrase.Replace("5(", "5*(");
		this.phrase = this.phrase.Replace("6(", "6*(");
		this.phrase = this.phrase.Replace("7(", "7*(");
		this.phrase = this.phrase.Replace("8(", "8*(");
		this.phrase = this.phrase.Replace("9(", "9*(");
		
		this.phrase = this.phrase.Replace(")x", ")*x");
		
		this.phrase = this.phrase.Replace("0x", "0*x");
		this.phrase = this.phrase.Replace("1x", "1*x");
		this.phrase = this.phrase.Replace("2x", "2*x");
		this.phrase = this.phrase.Replace("3x", "3*x");
		this.phrase = this.phrase.Replace("4x", "4*x");
		this.phrase = this.phrase.Replace("5x", "5*x");
		this.phrase = this.phrase.Replace("6x", "6*x");
		this.phrase = this.phrase.Replace("7x", "7*x");
		this.phrase = this.phrase.Replace("8x", "8*x");
		this.phrase = this.phrase.Replace("9x", "9*x");
			
		this.phrase = this.phrase.Replace(")(", ")*(");
	}
		
		
	public double calculer(double x){
		double resultat=0;
		
		//this.corrige();
		this.decouper();
		
		// cas: + - * / ^
		if(this.gauche!=null && this.droite!=null){
			if(this.operateur=="+"){
				resultat=this.gauche.calculer(x)+this.droite.calculer(x);
				return resultat;
			}
			else if(this.operateur=="*"){
				resultat=this.gauche.calculer(x)*this.droite.calculer(x);
				return resultat;
			}
			else if(this.operateur=="-"){
				resultat=this.gauche.calculer(x)-this.droite.calculer(x);
				return resultat;					
			}
			else if(this.operateur=="/"){
				resultat=this.gauche.calculer(x)/this.droite.calculer(x);
				return resultat;
			}
			else if(this.operateur=="^"){
				double gauche_double = this.gauche.calculer(x);
				double droite_double = this.droite.calculer(x);
				resultat = Math.Pow(gauche_double,droite_double);
				return resultat;
			}
		}
		// case: () r() cos() sin() tan() and n()
		else if(this.gauche!=null){
			if (this.operateur=="()"){
				resultat=this.gauche.calculer(x);
				return resultat;
			}
			else if (this.operateur=="sqrt()"){
				double gauche_double = this.gauche.calculer(x);
				resultat = Math.Sqrt(gauche_double);
				return resultat;
				
			}
			else if (this.operateur=="cos()"){
				double gauche_double = this.gauche.calculer(x);
				resultat = Math.Cos(gauche_double);
				return resultat;
				
			}
			else if (this.operateur=="sin()"){
				double gauche_double = this.gauche.calculer(x);
				resultat = Math.Sin(gauche_double);
				return resultat;
				
			}
			else if (this.operateur=="tan()"){	
				double gauche_double = this.gauche.calculer(x);
				resultat = Math.Tan(gauche_double);
				return resultat;
				
			}
			else if (this.operateur=="ln()"){
				double gauche_double = this.gauche.calculer(x);
				resultat = Math.Log(gauche_double);
				return resultat;
				
			}
			else if (this.operateur=="log()"){
				double gauche_double = this.gauche.calculer(x);
				resultat = Math.Log10(gauche_double);
				return resultat;
				
			}
			else if (this.operateur=="acos()"){
				double gauche_double = this.gauche.calculer(x);
				resultat = Math.Acos(gauche_double);
				return resultat;
				
			}
			else if (this.operateur=="asin()"){
				double gauche_double = this.gauche.calculer(x);
				resultat = Math.Asin(gauche_double);
				return resultat;
				
			}
			else if (this.operateur=="atan()"){
				double gauche_double = this.gauche.calculer(x);
				resultat = Math.Atan(gauche_double);
				return resultat;
				
			}
			else if (this.operateur=="cosh()"){
				double gauche_double = this.gauche.calculer(x);
				resultat = Math.Cosh(gauche_double);
				return resultat;
				
			}
			else if (this.operateur=="sinh()"){
				double gauche_double = this.gauche.calculer(x);
				resultat = Math.Sinh(gauche_double);
				return resultat;
				
			}
			else if (this.operateur=="tanh()"){
				double gauche_double = this.gauche.calculer(x);
				resultat = Math.Tanh(gauche_double);
				return resultat;
				
			}
			else if (this.operateur=="exp()"){
				double gauche_double = this.gauche.calculer(x);
				resultat = Math.Exp(gauche_double);
				return resultat;
				
			}
			else if (this.operateur=="abs()"){
				double gauche_double = this.gauche.calculer(x);
				resultat = Math.Abs(gauche_double);
				return resultat;
				
			}
			else if (this.operateur=="int()"){
				double gauche_double = this.gauche.calculer(x);
				resultat = Math.Floor(gauche_double);
				return resultat;
				
			}
			
			
			
		}
		
		else{ // phrase is like "x" or "2,1213" or "2" 
			if (this.phrase=="x" || this.phrase=="X"){
				return x;
			}
			else{
				decimal res_d = Convert.ToDecimal(this.phrase);
				double res_f = (double) res_d;	
				resultat=res_f;
				return resultat;
			}
		}
		return resultat;	
	}
		

	// exemple: compte_jusqua("a", 3) for "aaaaaa" =>3
	private int compte_jusqua(string ch, int fin){
		int pos;
		int nb=0;
		bool arreter=false;
		int i=0;
		while( (i <= fin) && (arreter == false) && (i <= this.phrase.Length) ){
			pos=phrase.IndexOf(ch, i, fin-i);
			if(pos != -1){
				nb++;
				i=pos+1;
			}
			else{
				arreter=true;
			}
			
		}
		return nb;
	}
	
	
	
}
