PageRenderTime 244ms CodeModel.GetById 120ms app.highlight 42ms RepoModel.GetById 79ms app.codeStats 0ms

/src/mpv5/utils/tables/DynamicArithmetic.java

http://mp-rechnungs-und-kundenverwaltung.googlecode.com/
Java | 251 lines | 213 code | 11 blank | 27 comment | 81 complexity | 7b6b08eebeee86e617ffa258b8a104b1 MD5 | raw file
  1
  2/*
  3 *  This file is part of YaBS.
  4 *
  5 *      YaBS is free software: you can redistribute it and/or modify
  6 *      it under the terms of the GNU General Public License as published by
  7 *      the Free Software Foundation, either version 3 of the License, or
  8 *      (at your option) any later version.
  9 *
 10 *      YaBS is distributed in the hope that it will be useful,
 11 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13 *      GNU General Public License for more details.
 14 *
 15 *      You should have received a copy of the GNU General Public License
 16 *      along with YaBS.  If not, see <http://www.gnu.org/licenses/>.
 17 */
 18package mpv5.utils.tables;
 19
 20import java.math.BigDecimal;
 21import java.util.ArrayList;
 22import java.util.HashMap;
 23import mpv5.globals.Constants;
 24import mpv5.logging.Log;
 25
 26class DynamicArithmetic {
 27
 28    private String toParse;
 29    private char[] operators = "+-:/*%".toCharArray();
 30    private ArrayList<BigDecimal> vals = new ArrayList<BigDecimal>();
 31    private char operator = 0;
 32    public BigDecimal result = BigDecimal.ZERO;
 33    private final BigDecimal hundert = Constants.BD100;
 34    private int openTerms = 0;
 35    private final HashMap<Integer, BigDecimal> values;
 36    private DynamicArithmetic da;
 37
 38    public DynamicArithmetic(String toParse, HashMap<Integer, BigDecimal> values) throws ParseFormatException {
 39      //  Log.Debug(this, toParse);
 40        this.toParse = toParse;
 41        this.values = values;
 42        result = parse();
 43    }
 44
 45    private BigDecimal parse() throws ParseFormatException {
 46        String columnString = "";
 47        boolean pushValueString = false;
 48
 49        if (toParse.charAt(0) != '(') {
 50            //Log.Debug(this, "First Char is not a Term opener --> enclosing it");
 51            toParse = "(" + toParse + ")";
 52        }
 53
 54        for (int i = 0; i < toParse.length(); i++) {
 55            char ch = toParse.charAt(i);
 56            switch (ch) {
 57                case '[':
 58                    //Log.Debug(this, "Value Opener found --> append Value String on ");
 59                    pushValueString = true;
 60                    break;
 61                case ']':
 62                    //Log.Debug(this, "Value Closer found --> append Value String off");
 63                    pushValueString = false;
 64                    if (!columnString.equals("")) {
 65                        if (values.containsKey(Integer.parseInt(columnString))) {
 66                            vals.add(values.get(Integer.parseInt(columnString)));
 67                        } else {
 68                            vals.add(null);
 69                        }
 70                    } else {
 71                        throw new ParseFormatException("Parsing Error at Position [" + i + "]: No Value given:\n"
 72                                + "Arithmetic Expression: " + toParse);
 73                    }
 74                    columnString = "";
 75                    break;
 76                case '(':
 77                    //Log.Debug(this, "Term Opener found --> increment Stack 3");
 78                    if (openTerms == 0) {
 79                        vals.clear();
 80                        openTerms = openTerms + 1;
 81                    } else {
 82                        parseForStaples();
 83                        return result;
 84                    }
 85                    break;
 86                case ')':
 87                    //Log.Debug(this, "Term Closer found --> decrement Stack 3");
 88                    openTerms = openTerms - 1;
 89                    calc();
 90                    break;
 91                default:
 92                    if (Character.isDigit(ch)) {
 93                        //Log.Debug(this, "Column found --> put it to Stack ??");
 94                        if (pushValueString) {
 95                            columnString = columnString + ch;
 96                        } else {
 97                            throw new ParseFormatException("Parsing Error at Position [" + i + "]: No Open Value Definition!\n"
 98                                    + "Arithmetic Expression: " + toParse);
 99                        }
100                    } else {
101                        for (int j = 0; j < operators.length; j++) {
102                            if (ch == operators[j]) {
103                                //Log.Debug(this, "Operator found --> put it to Stack ??");
104                                if (operator != ch && operator != 0) {
105                                    //Log.Debug(this, "Operator changed-->checking for Arithmetic Rules ...");
106                                    if (ch == '*' || ch == ':' || ch == '/' || ch == '%') {
107                                        //Log.Debug(this, "Handle privileged ...");
108                                        values.put(999999, vals.get(vals.size() - 1));
109                                        da = new DynamicArithmetic("([999999]" + toParse.substring(i), values);
110                                        values.remove(999999);
111                                        vals.set(vals.size() - 1, da.result);
112                                        openTerms = 0;
113                                        calc();
114                                        return result;
115                                    } else {
116                                        //Log.Debug(this, "normal Switch of 'same level operators' or comming from privileged");
117                                        openTerms = openTerms - 1;
118                                        calc();
119                                        openTerms = openTerms + 1;
120                                        vals.clear();
121                                        vals.add(result);
122                                        operator = ch;
123                                    }
124                                } else {
125                                    operator = ch;
126                                }
127                                break;
128                            }
129                        }
130                    }
131            }
132        }
133        return result;
134    }
135
136    private void calc() throws ParseFormatException {
137        BigDecimal tmp = BigDecimal.ZERO;
138        if (!vals.isEmpty()) {
139            switch (operator) {
140                case '+':
141                    for (int k = 0; k < vals.size(); k++) {
142                        BigDecimal val = vals.get(k) == null ? BigDecimal.ZERO : vals.get(k);
143                        if (k == 0) {
144                            tmp = val;
145                        } else {
146                            tmp = tmp.add(val);
147                        }
148                    }
149                    if (openTerms == 0) {
150                        result = tmp;
151                    }
152                    break;
153                case '-':
154                    for (int k = 0; k < vals.size(); k++) {
155                        BigDecimal val = vals.get(k) == null ? BigDecimal.ZERO : vals.get(k);
156                        if (k == 0) {
157                            tmp = val;
158                        } else {
159                            tmp = tmp.subtract(val);
160                        }
161                    }
162                    if (openTerms == 0) {
163                        result = tmp;
164                    }
165                    break;
166                case ':':
167                    for (int k = 0; k < vals.size(); k++) {
168                        BigDecimal val = vals.get(k) == null ? BigDecimal.ONE : vals.get(k);
169                        if (k == 0) {
170                            tmp = val;
171                        } else {
172                            tmp = tmp.divide(val, 9, BigDecimal.ROUND_HALF_UP);
173                        }
174                    }
175                    if (openTerms == 0) {
176                        result = tmp;
177                    }
178                    break;
179                case '/':
180                    for (int k = 0; k < vals.size(); k++) {
181                        BigDecimal val = vals.get(k) == null ? BigDecimal.ONE : vals.get(k);
182                        if (k == 0) {
183                            tmp = val;
184                        } else {
185                            tmp = tmp.divide(val, 9, BigDecimal.ROUND_HALF_UP);
186                        }
187                    }
188                    if (openTerms == 0) {
189                        result = tmp;
190                    }
191                    break;
192                case '*':
193                    for (int k = 0; k < vals.size(); k++) {
194                        BigDecimal val = vals.get(k) == null ? BigDecimal.ONE : vals.get(k);
195                        if (k == 0) {
196                            tmp = val;
197                        } else {
198                            tmp = tmp.multiply(val);
199                        }
200                    }
201                    if (openTerms == 0) {
202                        result = tmp;
203                    }
204                    break;
205                case '%':
206                    for (int k = 0; k < vals.size(); k++) {
207                        BigDecimal val = vals.get(k) == null ? BigDecimal.ZERO : vals.get(k);
208                        if (k == 0) {
209                            tmp = val;
210                        } else {
211                            tmp = tmp.multiply(val).divide(hundert, 9, BigDecimal.ROUND_HALF_UP);
212                        }
213                    }
214                    if (openTerms == 0) {
215                        result = tmp;
216                    }
217                    break;
218                default:
219                    if (vals.size() == 1) {
220                        result = vals.get(0) == null ? BigDecimal.ZERO : vals.get(0);
221                    } else {
222                        throw new ParseFormatException("Parsing Error: Missing Operator!\n"
223                                + "Arithmetic Expression: " + toParse);
224                    }
225            }
226        }
227    }
228
229    private void parseForStaples() {
230        int i = 900000;
231        while (toParse.contains(")")) {
232            int high = toParse.indexOf(")") + 1;
233            int low = toParse.lastIndexOf("(", high);
234            try {
235                da = new DynamicArithmetic(toParse.substring(low, high), values);
236                values.put(i, da.result);
237            } catch (ParseFormatException ex) {
238                Log.Debug(ex);
239            }
240            toParse = toParse.replace(toParse.substring(low, high), "[" + i + "]");
241            i++;
242        }
243
244        try {
245            da = new DynamicArithmetic(toParse, values);
246            result = da.result;
247        } catch (ParseFormatException ex) {
248            Log.Debug(ex);
249        }
250    }
251}