import java.util.*;

public class Berechne_zahl {


static Anzeige  anzeige;

static Stack 	zahlen_stack;
static Stack 	operator_stack= new Stack();;

/*
*	Flags fuer
*/

static boolean  plus;						// Addition
static boolean  minus;						// Subtraktion
static boolean  mal;						// Multiplikation
static boolean  durch;						// Division
static boolean	potenz; 					// Potenz

/*
*	Variablen zur Aufnahme von Zwischenstrings
*/

static String 	hilf;
static String 	hilf2;
static String 	klammerausdruck;	
static String 	wurzelausdruck;

static int  	i;							// Laufvariable 
static double  	bla;						// zur Aufnahme von
											// Zwischenergebnissen

static int  	klammer_auf,klammer_zu; 	// Zaehler fuer geoeffnete und
											// geschlossene Klammern

static Berechne_zahl berechnez = new Berechne_zahl();


	public String Berechnez(String s, Anzeige anzeige, String potenzieren){
	
	/*
	* 	Initialisierung
	*/
		zahlen_stack 	= new Stack();
	 	
		plus 			= false;
		minus			= false;
		mal 			= false;
		durch 			= false;
		potenz			= false;
	
		hilf			= "";
		hilf2			= "";
		klammerausdruck = "";
		wurzelausdruck	= "";
	
		klammer_auf 	= 0;
		klammer_zu	 	= 0;
	
		this.anzeige 	= anzeige;
	
	
	/*
	*	Leerzeichen entfernen
	*/
	
		for (i=0; i<s.length(); i++){
		
			if (s.charAt(i)!=' ' ){
			
				hilf += s.charAt(i);
			
			}
	
		}
	
		s=hilf;
		hilf="";
	
	/*
	* 	Eleminierung der Klammerausdruecke
	*/
	
		for (i=0; i<s.length(); i++){
	
			switch (s.charAt(i)) {
			
			case '(' :	klammer_auf=1;
				
						i++;
							
						while ( i < s.length()
								&& 
								klammer_auf!=klammer_zu) {
																
							klammerausdruck+= s.charAt(i);
								
							if (s.charAt(i)=='(') {
								
								klammer_auf++;
								
							} else  if (s.charAt(i)==')'){
								
										klammer_zu++;
								
							} // ende if
							
							i++;
								
						} // ende while
							
						klammerausdruck = klammerausdruck.substring(0,klammerausdruck.length()-1);
					
						i--;
		
				/*
				* 	Backup in Stack schreiben
				*/			
						operator_stack.push(String.valueOf(i));
						operator_stack.push(hilf2);
					
		/*
		* 	Klammerausdruck berechnen
		*/
					hilf = berechnez.Berechnez(klammerausdruck,anzeige,potenzieren);
						
				/*
				* 	Backup zuruecklesen
				*/	
					hilf2= (String)operator_stack.pop();
					i = Integer.parseInt((String)operator_stack.pop(),10);
				
		/*
		* 	berechneten Klammerwert an String anfuegen
		*/	
		
			/*
			*	wenn eine Potenz folgt, muessen Klammern gesetzt
			*	werden, damit die Auswertung der Minuszeichen
			*	nicht durcheinander geraet
			*
			*	dabei darf davor keine Wurzel stehen (sqr), da
			*	es sonst zu Interpretationsproblemen kommt
			*
			*	Bsp.: 	10--2^2 wird falsch interpretiert
			*			10-(-2)^2 ist korrekt
			*/
			
			if (i+1<s.length()
				&&
				s.charAt(i+1)=='^'
				&&
				s.charAt(i-hilf.length())!='r'){
		
				hilf = "("+hilf+")";
		
			} // ende if
			
					hilf2 += hilf;
					
					break;
					
			default: 
					hilf2 += s.charAt(i);
					break;
					
			} // ende switch
			
		} // ende for
	
	/*
	* 	s enthaelt nun den zu berechnenden String ohne Klammerausdruecke
	*/
	
		s=hilf2;
		
		hilf="";
		hilf2="";
	
	/*
	* 	Eleminierung der Wurzel
	*/
	
		for (i=0; i<s.length(); i++){
	
			switch (s.charAt(i)) {
			
			/*
			*	Test, ob sqr oder SQR im Text vorkommt
			*
			*		- ja 	-> Wert einlesen und Wurzel berechnen
			*		- nein	-> Zeichen einfach an die Zeichenkette 
			*				   anhaengen
			*/
			
			case 's': case 'S':
			
			/*
			*	Test, ob es sich um Wurzelberechnung handelt - sqr(...)
			*/
				if (s.regionMatches(true, i, "sqr", 0, 3)) {
				
				i+=3;	// sqr ueberlesen
				
				
				wurzelausdruck="";
				
				/*
				*	Test, ob Zahlenwert negativ ist
				*		- ja 	-> FC ERROR
				*		- nein  -> ok
				*/
				
					if (s.charAt(i)=='-'){
						anzeige.schreiben("?FC ERROR");
						Aus.Aus();
						return "";
					}
				
				/*
				*	alles ok
				*/
					while ( i < s.length()
							&&
							s.charAt(i) <= '9' 
							&&
							s.charAt(i) >= '0'
							||
							i < s.length()
							&&
							s.charAt(i) == '.'
							){
								
						wurzelausdruck += s.charAt(i);
						i++;	
					} // ende while
			
				//i--;
			
				/*
				*	Wurzel ausrechnen
				*/
			
					bla = Double.valueOf(wurzelausdruck).doubleValue();
					hilf = String.valueOf(Math.sqrt(bla));
		
				/*
				* 	berechneten Wurzelwert an String anfuegen
				*/	
				
					hilf2 += hilf;
					
					i--;
				
			/*
			*	es ging nicht um Wurzelberechnung
			*/	
				}	else {
		
					hilf2 += s.charAt(i);
		
				} // ende else	
		
					break;
					
			default: 
					hilf2 += s.charAt(i);
					break;
					
			} // ende switch
		
		} // ende for
	
	/*
	* 	s enthaelt nun den zu berechnenden String ohne Wurzelausdruecke
	*	und ohne Klammern
	*/
	
		s=hilf2;
		
		hilf="";
		hilf2="";
		
	/*
	* 	Eleminierung der Potenz und von Variablen
	*/
	
		for (i=0; i<s.length(); i++){
		
			switch (s.charAt(i)) {
			
				case '(':
				
							while ( i<s.length()
								&&
								s.charAt(i)!=')'){
									
									hilf2+=s.charAt(i);
									i++;
							}
							
							hilf2+=")";
							
							zahlen_stack.push(hilf2);
							i++;
			
				case '^':	potenz=true;
							break;
							
				case '-':	if (potenz==true){	
							
								hilf="-";
								i++;
							
							/*
							*	moegliche Mehrfach-Leerzeichen
							*	z.B. --3, einlesen
							*/
							
								while ( i<s.length()
										&&
										s.charAt(i)=='-'){
								
									hilf += s.charAt(i);
									i++;
								}
							
								while ( i<s.length()
										&&
										s.charAt(i)!='-'
										&&
										s.charAt(i)!='+'
										&&
										s.charAt(i)!='*'
										&&
										s.charAt(i)!='/'
										&&
										s.charAt(i)!='^'){
							
									hilf += s.charAt(i);
									i++;
								}
							
								i--;
							
								ausrechnen_potenz();
							
							} else {
							
								zahlen_stack.push("-");
								
							} // ende else
							
							break;
			
			/*
			*	Variablen
			*/
				
				case 'a': case 'b':	case 'c': case 'd': case 'e': case 'f':
				case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
				case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
				case 's': case 't': case 'u': case 'v': case 'w': case 'x':
				case 'y': case 'z': 
				case 'A': case 'B':	case 'C': case 'D': case 'E': case 'F':
				case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
				case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
				case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
				case 'Y': case 'Z':	
					
						hilf2= "";
					
						//Varibalenname einelesen
						
							while(	i < s.length()
									&&
									s.charAt(i)!=' '
									&&
									s.charAt(i)!='+'
									&&
									s.charAt(i)!='*'
									&&
									s.charAt(i)!='/'
									&&
									s.charAt(i)!='^'
									&&
									s.charAt(i)!='-'){
							
								hilf2 += s.charAt(i);
								i++; 
							}
						
						i--; 			
						
						// Schreibweise auf Kleinbuchstaben aendern
						
						hilf2=hilf2.toLowerCase();
						
						/*
						*	Test auf Typkorrektheit
						*/
						
						if (hilf2.endsWith("$")){
				
							anzeige.schreiben("? TM ERROR");
							Aus.Aus();
							Print.endausgabe="";
		
							return "";
							
						} // ende if
						
						/*
						*	Test, ob Variablenname die nachfolgenden 
						*	reservierte Woerter
						*	enthaelt
						*
						*		- AT
						*		- FN
						*		- IF
						*		- LN
						*		- ON
						*		- OR
						*		- PI
						*		- TO
						*
						*	wenn ja, dann Syntax Error
						*/
		
						if (hilf2.indexOf("at")!=-1
							||
							hilf2.indexOf("fn")!=-1
							||
							hilf2.indexOf("if")!=-1
							||
							hilf2.indexOf("ln")!=-1
							||
							hilf2.indexOf("on")!=-1
							||
							hilf2.indexOf("or")!=-1
							||
							hilf2.indexOf("to")!=-1) {
			
							anzeige.schreiben("?SN ERROR");
							Aus.Aus();
							return "";
							
						} // ende if
						
						// normales PI muss durchgelassen werden
						
						if (hilf2.indexOf("pi")!=-1
							&&
							hilf2.length()>2) {
							
							anzeige.schreiben("?SN ERROR");
							Aus.Aus();
							return "";
						}
						
						// 	Wert der Variablen holen
						
							hilf = (String)Ausfuehren.vartab.get(hilf2);
						
						/*  Test, ob Variable ueberhaupt definiert wurde
						*	ja	->  alles ok
						*	nein->	Variable auf 0 setzen
						*/
						
							if (hilf==null){
							
								hilf="0";
									
							} // ende if
							
						
						/*
						*	ein mögliches Minus muss beachtet werden
						*/
							if (minus==true){
								hilf = "-" + hilf;
								minus = false;
							} 
							
						/*
						*	und ausrechnen
						*/
						
							ausrechnen_potenz();
						
							break;
						
			/*
			*	Zahlen
			*/
				case '0': case '1': case '2': case '3': case '4': case '5': 
				case '6': case '7': case '8': case '9': case '.': 
				
						/*
						*	Zahl einlesen
						*/
							hilf="";
							while ( i < s.length()
								&&
								s.charAt(i) <= '9' 
								&&
								s.charAt(i) >= '0'
								||
								i < s.length()
								&&
								s.charAt(i) == '.'
								){
								
								hilf += s.charAt(i);
								i++;	
							}
							
							i--;
					
						/*
						*	und ausrechnen
						*/
						
							ausrechnen_potenz();
							
							break;
				
						
				default:	hilf = s.charAt(i)+"";
							zahlen_stack.push(hilf);
							
			} // ende switch
			
		} // ende for
	
	/*
	*	Stack leeren und damit die neue Formel aufbauen
	*
	*	diese enthaelt nun keine Klammern, keine Potenzen 
	*	und keine Wurzel
	*/
	
		s="";
		
		while (!zahlen_stack.empty()){
		
			s = zahlen_stack.pop()+s;
		
		} 
		
		hilf = "";
		hilf2 ="";
	
	/*
	* 	s ausrechnen
	*/
		for (i=0; i<s.length(); i++){
		
			switch (s.charAt(i)) {
			
				case ' ': 	break;	// Leerzeichen ueberlesen
				
				case '+':	plus=true;
							break;
				
				case '-':	if (minus==true){ 
							
							// wenn schon ein minus,
							// dann muss es negiert werden
							
								minus = false;
								plus  = true;
							
							} else {
							
								minus = true;
								plus  = false;
							
							} // ende else
							
							break;
				
				case '*':	mal=true;
							break;
				
				case '/':	durch=true;
							break;
						
			/*
			*	Zahlen
			*/
				case '0': case '1': case '2': case '3': case '4': case '5': 
				case '6': case '7': case '8': case '9': case '.': 
				
						/*
						*	Zahl einlesen
						*/
							hilf="";
							while ( i < s.length()
								&&
								s.charAt(i) <= '9' 
								&&
								s.charAt(i) >= '0'
								||
								i < s.length()
								&&
								s.charAt(i) == '.'
								){
								
								hilf += s.charAt(i);
								i++;	
							}
							
							i--;
							
						/*
						*	und ausrechnen
						*/
							ausrechnen();
								
							break;
							
				case '\"':	anzeige.schreiben("? TM ERROR");
							Aus.Aus();
							Print.endausgabe="";
		
							return "";
						
				default:	anzeige.schreiben("? SN ERROR");
							Aus.Aus();
							Print.endausgabe="";
		
							return "";
							
			} // ende switch
			
		} // ende for
	
	return String.valueOf(ausgabe());
	
	} // ende berechnez
	
/*
*	
*	Ausgaberoutine
*
*	- baut den Stack ab
*	- dabei werden die abgeholten Elemente aufaddiert
*	  und dann mittels return ausgegeben
*
*	+ laenge 	- int-Variable zur Aufnahme der Stackgroesse
*	+ x 		- int-Laufvariable fuer den Stackabbau
*	+ test		- String zur temporaeren Aufnahme eines Stackelements
*	+ aus		- double-Variable zur Aufnahme des Ergebnisses
*
*/

	public double ausgabe(){
	
	double aus = 0;
	int laenge,x;
	
	String test="";
	
	laenge = zahlen_stack.size();
	
	 
		for (x=0; x<laenge; x++) {
		
			test = (String)zahlen_stack.pop();

			aus = Double.valueOf(test).doubleValue() + aus;
				
		} // ende for
	
	return aus;	
	
	} // ende ausgabe


/*
*
*	Rechen-Routine
*
*/
	public void ausrechnen(){
	
	/* Test, ob ueberhaupt gerechnet werden soll
	* ja 	->	alles ok	
	* neine->	alle Elemente vom Stack nehmen, 
	*			Element soll ja das erste sein
	*/	
	
	if (	durch	== false
			&&
			mal 	== false
			&&
			plus 	== false
			&&
			minus 	== false
			){

			zahlen_stack.removeAllElements();
			
	} 
	
	/*
	*	Test auf +, und einfach durchreichen
	*/
	
	if (plus==true){	
		
		plus = false;
					
	} 
	
	
	/*
	*	Test auf -, und berechnen
	*/
	
	if (minus==true){
				
		bla = 0-Double.valueOf(hilf).doubleValue();
					
		hilf = String.valueOf(bla);
							
		minus=false;
					
	} 
	
	
	/*
	*	Test auf *, und berechnen
	*/
	
	if (mal==true){
			
		bla = Double.valueOf((String)zahlen_stack.pop()).doubleValue();
		
		bla = bla * Double.valueOf(hilf).doubleValue();
					
		hilf = String.valueOf(bla);
							
		mal=false;
							
	}  
	
	
	/*
	*	Test auf /, und berechnen
	*/
	
	if (durch==true){
		
		bla = Double.valueOf((String)zahlen_stack.pop()).doubleValue();				
		
		bla = bla / Double.valueOf(hilf).doubleValue();
							
		hilf = String.valueOf(bla);
							
		durch=false;
							
	}	

	/*
	*	berechnetes Element auf den Stack
	*/

		zahlen_stack.push(hilf);
						
	} // ende ausrechnen

/*
*
*	Rechen-Routine Potenzberechnung
*
*/
	public void ausrechnen_potenz(){
	
	/*
	*	Test auf ^ (Potenz), und berechnen
	*/
	
	String hilf3="";
	int z=0;
	
	if (potenz==true){
		
		hilf3 = (String)zahlen_stack.pop();
		
		/*
		*	Basis ist geklammert, da negativ -> Klammerung entfernen
		*/
		
		if (hilf3.endsWith(")")) {
			
			hilf2 = "";
			z=1;
			
			while ( z<hilf3.length()
					&&
					hilf3.charAt(z)!=')'){

				hilf2 += hilf3.charAt(z);
				z++;
				
			} // ende while
		
		/*
		*	war nicht negativ, also auch keine Klammer
		*/
		
		} else {
		
			hilf2 = hilf3;
		
		} // ende else
		
		bla = Double.valueOf(hilf2).doubleValue();				
		
		bla = Math.pow(bla,Double.valueOf(hilf).doubleValue());
							
		hilf = String.valueOf(bla);
							
		potenz=false;
							
	}	

	/*
	*	berechnetes Element auf den Stack
	*/

		zahlen_stack.push(hilf);
						
	} // ende ausrechnen potenz
	
} // end class print

