// author:		klaffenboeck patrick <patrick.k@rocketmail.com>
// matr.-nr:		0125335
// bsp.-nr:		1132
// beschreibung:	lieszt einen String ein, der einen mathematischen
//    - " -    :	ausdruck mit vektoren enthaelt und gibt das ergebnis
//    - " -    :	aus.  moechte noch kurz sagen, dass ich mit dem
//    - " -    :	programm eigenltich NICHT zufrieden bin.  der grund
//    - " -    :	steht in Vektoren.txt.

 // danke an gck, fuer den hinweis auf die klasse Vector!
 // for better readability try "sed '/^ \/\//d' ...." ;-)

import eprog.EprogIO;
import java.util.Vector;
import VectorObject;
import Calculator;

public class Vektoren
{

 // in Vektoren.txt wird erklaert warum ich einen
 // Vector zum organisieren meiner daten nehme.
public static Vector termv = null;

public static void main( String args[] )
{
	String terms;
	VectorObject result;
	float x, y, z;
	int i;

	terms = EprogIO.readWord();

 // die hier aufgerufenen methoden werden in Vektoren.txt
 // erklaert.
	try {

		quickSyntaxCheck(terms);
		termsToTermv(terms);
		convertVectors();
		processPrefixes();
		convertScalars();
		solveBrackets();
		calculate(0, termv.size() - 1);

	} catch (Exception e) {
		EprogIO.println("FALSCHE EINGABE");
		System.exit(0);
	}

 // nachdem alle operationen durchgefuehrt wurden,
 // ist nur noch das ergebenis im Vector
	result = getVO(0);

 // und laut spezifikation muss das ein vektor sein
	if (result.getType() != VectorObject.VECTOR) {
		EprogIO.println("FALSCHE EINGABE");
		System.exit(0);
	}

 // dessen werte nun ausgelesen und ausgegeben werden koennen	
	x = (float) result.getX();
	y = (float) result.getY();
	z = (float) result.getZ();
	
	EprogIO.print("[ ");
	EprogIO.printFixed(x);
	EprogIO.print(" , ");
	EprogIO.printFixed(y);
	EprogIO.print(" , ");
	EprogIO.printFixed(z);
	EprogIO.println(" ]");

} // end void main( String[] )

/*
 * ueberprueft wird:
 *		- ob jede oeffnende klammer auch eine schlieszende hat
 *		- ob fuer jede geschlossene klammer vorher ueberhaupt
 *		  eine geoeffnet wurde
 *		- ob mehr als eine eckige klammer offen ist
 *		- ob mehr als zwei runde klammern offen sind
 *		  (einschraenkung von EProg)
 *		- ob ueberhaupt ein vektor vorkommt
 *
 * bei einem fehler wird eine Exception geworfen.
 */
public static void quickSyntaxCheck( String terms ) throws Exception
{
	int i;
	int brackets = 0;
	int sqBrackets = 0;
	int currentChar = 255;
	boolean containsVector = false;

	for (i = 0; i < terms.length(); i++) {
		currentChar = terms.charAt(i);
		switch (currentChar) {
			case '(':	brackets++;
					if (brackets > 2)
						throw new Exception();
					break;

			case ')':	brackets--;
					if (brackets < 0)
						throw new Exception();
					break;

			case '[':	sqBrackets++;
					if (sqBrackets > 1)
						throw new Exception();
					break;

			case ']':	sqBrackets--;
					if (sqBrackets < 0)
						throw new Exception();
 // wir haben mindestens ein oeffnene und eine schlieszende eckige klammer, also ...
					containsVector = true;
					break;
		}
	}

	if ((brackets != 0) | (sqBrackets != 0)) throw new Exception();
	if (containsVector == false) throw new Exception();
} // end void quickSyntaxCheck( String )

/*
 * lieszt jedes zeichen des Strings ein, wandelt ihn ihn ein object
 * und haengt es an den Vector.
 */
public static void termsToTermv( String terms ) throws Exception
{
	int i;

	termv = new Vector(terms.length());

	for (i = 0; i < terms.length(); i++)
			termv.add(new VectorObject(terms.charAt(i)));
} // end Vector termsToTermv( String )

/*
 * wird eine oeffnende eckige klammer gefunden, wird an dieser
 * stelle (pos) angefangen einen vektor einzulesen.
 */
public static void convertVectors() throws Exception
{
	int pos;
	int curr = 0;

	for (pos = 0; pos < termv.size(); pos++) {
		curr = (getVO(pos)).getType();
		
		if (curr == VectorObject.L_SQ_BRACKET) scanVector(pos);
	}
} // end void convertVectors()

/*
 * zwei operatoren hintereinander koennen bedeuten,
 * dass einer nur ein vorzeichen ist.  hier wird das
 * vorzeichen auf den nachetehenden operanden angewand.
 */
public static void processPrefixes() throws Exception
{
	int pos;
	boolean lastWasOperator = false;
	VectorObject curr, next, tmp;

	for (pos = 0; pos < termv.size() - 1; pos++) {
		curr = getVO(pos);
		next = getVO(pos + 1);

		if (curr.isPrefix()) {
			if (lastWasOperator) {
				tmp = (new Calculator(curr, next)).prefix();
				termv.set(pos, tmp);
				termv.remove(pos + 1);
				lastWasOperator = false;
			} else lastWasOperator = true;
		} else lastWasOperator = curr.isOperator();
	}
}

/*
 * wenn eine oeffnende klammer gefunden wird, darf dahinter nur
 * folgendes stehen: noch eine oeffnende klammer, ein vektor
 * ein vorzeichen, oder eine ziffer.  bei den letzten beiden, wird
 * ab dieser stelle ein skalar eingelesen.  kommt ganz was anderes
 * war die eingabe falsch.
 */
public static void convertScalars() throws Exception
{
	int pos;
	VectorObject curr, next, tmp;

	next = getVO(0);

 // ganz am anfang des ausdrucks darf nur ein vektor oder eine oeffnende
 // klammer sein.
	if ((next.getType() != VectorObject.VECTOR) &
	    (next.getType() != VectorObject.L_BRACKET)) throw new Exception();

	for (pos = 0; pos < termv.size() - 1; pos++) {
		curr = next;
		next = getVO(pos + 1);

		if (curr.isLBr()) {
			if (next.isPrefix() | next.isDigit()) {
				tmp = new VectorObject(scanScalar(pos + 1));
				termv.set(pos, tmp);
 // da skalare in klammern stehen, muss danach eine schlieszende kommen
				tmp = getVO(pos + 1);
				if (!tmp.isRBr()) throw new Exception();
				termv.remove(pos + 1);
			} else if (!next.isVector() & !next.isLBr())
				throw new Exception();
		}
	}
} // end void convertScalars()

/*
 * loest alle klammernausdruecke und ersetzt sie durch
 * einen einzigen wert im Vector.
 */
public static void solveBrackets() throws Exception
{
	int openBr, closeBr;

 // die positionen der klammern suchen
	openBr = search(VectorObject.L_BRACKET);
	closeBr = search(VectorObject.R_BRACKET);

 // solange welche gefunden werden, auswerten
	while (openBr != -1) {
 // das innere der klammer aufloesen
		calculate(openBr + 1, closeBr - 1);
 // danach steht nur noch ein operand zwischen den klammern
 // dadurch hat sich die schlieszende klammer nach vor verschoben
 // die klammer neu suchen und beide loeschen
		closeBr = search(VectorObject.R_BRACKET);

		termv.remove(closeBr);
		termv.remove(openBr);

 // das naechste klammernpaar suchen und die schleife von vorne beginnen
		openBr = search(VectorObject.L_BRACKET);
		closeBr = search(VectorObject.R_BRACKET);
	}
}

/*
 * start und end sind da, damit man die methode auf das innere
 * einer klammer beschraenken kann.
 */
public static void calculate(int start, int end ) throws Exception
{
	int pos;

 // solange multiplikationen gefunden werden sagen wir giveToCalculator
 // wo die operation gefunden wurde.  dann werden von ende zwei
 // abgezogen, weil der operator und der zweite operand aus dem Vector
 // geloescht wurden.
	while ((pos = search(VectorObject.MULT, start, end)) != -1) {
		giveToCalculator(pos);
		end -= 2;
	}

	while ((pos = search(VectorObject.PLUS, start, end)) != -1) {
		giveToCalculator(pos);
		end -= 2;
	}

	while ((pos = search(VectorObject.MINUS, start, end)) != -1) {
		giveToCalculator(pos);
		end -= 2;
	}

	if (start != end) throw new Exception();
} // end void calculate( int, int )

public static void giveToCalculator( int pos ) throws Exception
{
	VectorObject operand1, operator, operand2, result;

 // der erste operand
	operand1 = getVO(pos - 1);
 // der operator
	operator = getVO(pos);
 // der zeite operand
	operand2 = getVO(pos + 1);

 // das ergebnis ueberschreibt den ersten operanden
 // der operator und der zweite operand werden geloescht
	result = (new Calculator(operand1, operator, operand2)).run();
	termv.set(pos - 1, result);

	termv.remove(pos + 1);
	termv.remove(pos);
} // end void giveToCalculator( int )

/*
 * lieszt die als einzelne chars gespeicherten daten eines
 * vektors aus dem Vector und speichert ihn in ein einziges
 * objekt.
 */
public static void scanVector( final int pos ) throws Exception
{
	VectorObject tmp;
	String x, y, z;

 // ganz am anfang ist eine eckige klammer, die koennen
 // wir loeschen.
	termv.remove(pos);

 // danach kommt ein skalar
	x = scanScalar(pos);

 // dann _muss_ ein beistrich kommen, dass wir dann
 // auch loeschen.
	tmp = getVO(pos);
	if (tmp.getC() != ',') throw new Exception();
	termv.remove(pos);

 // wieder ein skalar, ..., ..., ...
	y = scanScalar(pos);

	tmp = getVO(pos);
	if (tmp.getC() != ',') throw new Exception();
	termv.remove(pos);

	z = scanScalar(pos);

 // am schluss muss eine schlieszende eckige klammer kommen
	tmp = getVO(pos);
	if (tmp.getC() != ']') throw new Exception();

 // die wird mit dem gesamten vektor ueberschrieben
	termv.set(pos, new VectorObject(x, y, z));
} // end void scanVector( int )

/*
 * damit man diese methode auch in den anderen verwenden kann
 * schreibt sie kein objekt inden Vector, sondern liefert einen
 * String zurueck.  preDot und postDot werden in Vektoren.txt erklaert.
 */
public static String scanScalar( final int pos ) throws Exception
{
	VectorObject tmp;
	StringBuffer value = new StringBuffer(10);
	double x;
	boolean preDot = false;
	boolean postDot = true;

	tmp = getVO(pos);

 // als erstes _kann_ ein vorzeichen kommen.
 // wenn ja, an den String anhaengen und aus dem Vector loeschen.
	if (tmp.isPrefix()) {
		value.append(tmp.getC());
		termv.remove(pos);
		tmp = getVO(pos);
	}

 // dann koennen beliebig viele ziffern kommen ...
	while (tmp.isDigit()) {
		value.append(tmp.getC());
		termv.remove(pos);
		tmp = getVO(pos);
		preDot = true;
	}

 // dann _kann_ ein dezimalpunkt da sein ...
	if (tmp.isDot()) {
		value.append(tmp.getC());
		termv.remove(pos);
		tmp = getVO(pos);
		postDot = false;
	}
 // dann muessen natuerlich auch wieder ziffern da sein
	while (tmp.isDigit()) {
		value.append(tmp.getC());
		termv.remove(pos);
		tmp = getVO(pos);
		postDot = true;
	}

 // wenn vor, oder nach einem punkt keine ziffern sind, wird abgebrochen.
	if (!(preDot & postDot)) throw new Exception();

 // der einfachheit halber, wandle ich das ergebnis kurz in einen
 // double um um zu ueberpruefen, ob es im richtigen bereich liegt
 // (EProg einschraenkung)
	x = Double.parseDouble(value.toString());
	if ((x < -100) | (x > 100)) throw new Exception();

	return value.toString();
} // end String scanVector( final int )

/*
 * durchsucht den gesamten Vector und liefert die erste
 * position an der ein eintrag vom typ <type> ist, zurueck.
 */
public static int search( int type )
{
	int i;

	for (i = 0; i < termv.size(); i++)
		if ((getVO(i)).getType() == type) return i;

	return -1;
} // end int search( int )

/*
 * wie search( int ), aber sucht nur in einem gewissen bereich.
 */
public static int search( int type, int start, int end )
{
	int i;

	for (i = start + 1; i <= end; i++)
		if ((getVO(i)).getType() == type) return i;

	return -1;
} // end int search( int, int )

/*
 * liefert das objekt, das an der position <pos> im
 * Vector ist.
 */
public static VectorObject getVO( int pos )
{
	return (VectorObject) termv.get(pos);
} // end VectorObject getVO ( int )

} // end class Vektoren