package com.towel.math.exp; import com.towel.cfg.StringUtil; import com.towel.math.Expression; import com.towel.math.exp.Operator.Operands; /** * Represents one or more operation nodes (a group of one or two operands and an * operator). * * @author Marcos A. Vasconcelos Junior */ public class Node { private Operator operator = null; private Node leftNode = null; private Node rightNode = null; private Double value = null; /** * Create a Node using the given expression. * * @param s * the expression */ public Node(Expression s) { this(s.getExpression(), s); } private Node(String s, Expression exp) { s = StringUtil.removeCharacters(s, ' '); s = removeBrackets(s); s = addZero(s); if (!checkBrackets(s)) throw new IllegalArgumentException("Wrong number of brackets in '" + s + "'"); value = exp.getDouble(s); int sLength = s.length(); int inBrackets = 0; int startOperator = 0; for (int i = 0; i < sLength; i++) { if (s.charAt(i) == '(') inBrackets++; else if (s.charAt(i) == ')') inBrackets--; else { if (inBrackets == 0) { Operator o = getOperator(s, i); if (o != null) if (operator == null || operator.getPriority() >= o.getPriority()) { operator = o; startOperator = i; } } } } if (operator != null) { // one operand, should always be at the beginning if (startOperator == 0 && operator.getType() == Operands.SINGLE) { if (checkBrackets(s.substring(operator.getOperator().length()))) { leftNode = new Node(s.substring(operator.getOperator() .length()), exp); return; } throw new IllegalArgumentException( "Error parsing. Missing brackets in '" + s + "'"); } else if (startOperator > 0 && operator.getType() == Operands.DOUBLE) { leftNode = new Node(s.substring(0, startOperator), exp); rightNode = new Node(s.substring(startOperator + operator.getOperator().length()), exp); } } } /** * Returns the operator starting at given index. * * @param s * the expression part * @param start * the start index * @return the operator */ public Operator getOperator(String s, int start) { Operator[] operators = Operator.values(); String next = getNextWord(s.substring(start)); for (int i = 0; i < operators.length; i++) if (next.startsWith(operators[i].getOperator())) return operators[i]; return null; } /** * @param s * the part of expression * @return the first word of this expression */ public String getNextWord(String s) { int sLength = s.length(); for (int i = 1; i < sLength; i++) { char c = s.charAt(i); if ((c > 'z' || c < 'a') && (c > '9' || c < '0')) return s.substring(0, i); } return s; } /** * Checks if there is any missing brackets * * @param s * the operation to check * @return true if the operation is valid */ public boolean checkBrackets(String s) { int brackets = 0; for (int i = 0; i < s.length(); i++) if (s.charAt(i) == '(' && brackets >= 0) brackets++; else if (s.charAt(i) == ')') brackets--; return brackets == 0; } /** * Returns a string that doesn't start with '+' or '-' * * @param s * the original String * @return the node with zero at start */ public String addZero(String s) { if (s.startsWith("+") || s.startsWith("-")) return "0" + s; return s; } /** * Trace the expression graph. */ public void trace() { System.out.println(value != null ? value : operator.getOperator()); if (hasChild()) { if (hasLeft()) getLeft().trace(); if (hasRight()) getRight().trace(); } } /** * @return <code>true</code> if there is one or more children, * <code>false</code> otherwise */ public boolean hasChild() { return leftNode != null || rightNode != null; } /** * @return <code>true</code> if there the operator is set, * <code>false</code> otherwise */ public boolean hasOperator() { return operator != null; } /** * @return <code>true</code> if there is one a left node, <code>false</code> * otherwise */ public boolean hasLeft() { return leftNode != null; } /** * @return the left node */ public Node getLeft() { return leftNode; } /** * @return <code>true</code> if there is one a right node, * <code>false</code> otherwise */ public boolean hasRight() { return rightNode != null; } /** * @return the right node */ public Node getRight() { return rightNode; } /** * @return the operator */ public Operator getOperator() { return operator; } /** * @return the value of this node */ public Double getValue() { return value; } /** * @param f * the new node's value */ public void setValue(Double f) { value = f; } private String removeBrackets(String s) { String res = s; if (s.length() > 2 && res.startsWith("(") && res.endsWith(")") && checkBrackets(s.substring(1, s.length() - 1))) res = res.substring(1, res.length() - 1); // In case the String was something like '((1+1))' // only '1+1' is returned. if (res != s) return removeBrackets(res); return res; } }