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