/**
 * Trieda reprezentujuca aritmeticky vyraz
 */
public class Vyraz {
        /**
         * Rozhranie, ktore implementuju vsetky uzly aritmetickeho stromu
         */
        private interface Clen {
                @Override
                public String toString();
        }
        /**
         * Trieda implementujuca uzol stromu aritmetickeho stromu, ktory
         * reprezentuje binarnu operaciu
         */
        private static class BinarnaOperacia implements Clen {
                private char operator;
                private Clen lavyPodvyraz;
                private Clen pravyPodvyraz;
                public BinarnaOperacia(char operator, Clen lavy, Clen pravy) {
                        this.operator = operator;
                        this.lavyPodvyraz = lavy;
                        this.pravyPodvyraz = pravy;
                }
                @Override
                public String toString() {
                        return "(" + lavyPodvyraz.toString() + operator
                                        + pravyPodvyraz.toString() + ")";
                }
        }
        /**
         * Trieda implementujuca uzol aritmetickeho stromu, ktory reprezentuje
         * konstantu
         */
        private static class Hodnota implements Clen {
                private double hodnota;
                public Hodnota(double hodnota) {
                        this.hodnota = hodnota;
                }
                @Override
                public String toString() {
                        return Double.toString(hodnota);
                }
        }
        /**
         * Symboly operacii od najnizsej priority po najvyssiu
         */
        private static final String SYMBOLY_OPERACII = "+-*/";
        /**
         * Prevedie zadany vyraz do aritmetickeho stromu
         * 
         * @param vyraz
         *            vyraz, ktory sa ma parsovat
         * @return referencia na koren aritmetickeho stromu
         */
        private static Clen prevedNaStrom(String vyraz) {
                // Odstranime zbytocne medzery
                vyraz = vyraz.trim();
                // Najdeme operator s najnizsou prioritou, ktory nie je v zatvorkach
                int operatorIdx = Integer.MAX_VALUE;
                int operatorPoz = -1;
                int pocitadloZatvoriek = 0;
                for (int i = 0; i < vyraz.length(); i++) {
                        char znak = vyraz.charAt(i);
                        if (znak == '(')
                                pocitadloZatvoriek++;
                        if (znak == ')')
                                pocitadloZatvoriek--;
                        int priorita = SYMBOLY_OPERACII.indexOf(znak);
                        if ((priorita != -1) && (pocitadloZatvoriek == 0) && (i > 0)) {
                                if (priorita < operatorIdx) {
                                        operatorIdx = priorita;
                                        operatorPoz = i;
                                }
                        }
                }
                // Rozdelime vyraz na podvyrazy
                if (operatorPoz != -1) {
                        return new BinarnaOperacia(SYMBOLY_OPERACII.charAt(operatorIdx),
                                        prevedNaStrom(vyraz.substring(0, operatorPoz)),
                                        prevedNaStrom(vyraz.substring(operatorPoz + 1)));
                }
                // Poznamka: Ak sme nenasli operator, tak je to alebo konstanta, alebo
                // cely vyraz je ozatvorkovany
                // Ak je cely vyraz ozatvorkovany, tak nechame rozparsovat jeho vnutornu
                // cast
                if ((vyraz.charAt(0) == '(')
                                && (vyraz.charAt(vyraz.length() - 1) == ')'))
                        return prevedNaStrom(vyraz.substring(1, vyraz.length() - 1));
                // Ak sme tu, tak to musi byt cislo
                try {
                        return new Hodnota(Double.parseDouble(vyraz));
                } catch (NumberFormatException e) {
                        throw new RuntimeException(
                                        "Zadany vyraz nie je korektny aritmeticky vyraz");
                }
        }
        /**
         * Koren aritmetickeho stromu vyrazu
         */
        private Clen koren;
        /**
         * Skontruuje novy aritmeticky vyraz
         * 
         * @param vyraz
         *            retazec s aritmetickym vyrazom
         */
        public Vyraz(String vyraz) {
                koren = prevedNaStrom(vyraz);
        }
        @Override
        public String toString() {
                return koren.toString();
        }
        public static void main(String[] args) {
                Vyraz v = new Vyraz("(-3)+6/2+3*2");
                System.out.println(v);
        }
}